一道典型的house of force题~
分析
没啥需要关注的保护:
逆向分析,此处存在off by one的溢出:
1 | int __cdecl Read(char *name, int size, char endChar) |
在此处,当输入64字节时,结束符会被存放在nameBak
里,接下来就会被覆盖为堆地址,此时就可以泄露堆地址啦(注意此时并没有对堆溢出,因为由于对齐,分配的chunk size为0x48也就是可用size为0x44字节)~
1 | unsigned int readName() |
此处,由于没有结束符,可以使org=s+org+v3
溢出,org后面就是topchunk了,于是可以修改它的size。
1 | unsigned int readInfo() |
这里的malloc
参数可控于是可以分配任意大小,到目前为止已经满足house of force
的条件啦~
1 | int new() |
接着,控制哪些区域呢?首先需要泄露出libc的地址,show函数未实现,puts
、printf
的参数写死都不能直接拿来输出,于是需要劫持其他函数,可以把free
劫持了,把GOT项改为printf的plt+6
1 | int delet() |
上面free
的参数是noteList[id]
,这里可以更改它指向位置的值,也是需要修改noteList
里的地址的,所以还需要一次分配,使noteList
这片区域可控~
1 | int edit() |
利用
通过分析发现了漏洞所在与一些可能的利用点子,现在来综合一下,最初思路:
- 由于不知道system地址,第一次先泄露地址,第二次再劫持函数。
- 在初始化时,通过
readName
输出堆地址。 - 接着在
readInfo
中对org输入0x40个字符,对host输入随意(不会有溢出),这样host的前四字节就会覆盖到topchunk的size位。 - 此时有topchunk的size为0xfffffff8且topchunk的位置已知,就可以算出需要控制位置的相对偏移,先分配去掉前面的部分,再次分配即可控制
free@got
区域,将其改写为printf@plt+6
即可劫持它获得libc地址,再次分配atoi@got
区域 - 接下来分配
notLits
区域,以泄露libc地址,再编辑atoi
为system
地址,即可getshell。
然而,这种方法由于topchunk的size与对齐问题,将会破坏很多数据,部分数据可以通过一些方法修复,另一些却很难修复,于是另寻它法:
- 123步同上
- 首先分配
lenList
区域,将里面的各项数字都改大点,总有好处的。 - 接着分配
noteList
区域,除了之前有的区域,将第一个未使用的区域改为free@got
地址,第二个改为atoi@got
地址,第三个改为atoi@got
地址(将这三个块编号123) - 编辑块1,改为
printf@plt+6
再释放块3得到libc地址 - 编辑块2,改为
system
地址,再次输入/bin/sh\0
getshell
最终代码如下:
1 | #!/usr/bin/env python |
结果
参考
[0]https://0x48.pw/2018/01/16/0x41/#house-of-force
[1]http://uaf.io/exploitation/2016/03/20/BCTF-bcloud.html