ciscn_2019_ne_3
总结
一道很无语的rop
的题目,由于在puts
调用中会卡在[ebp - 0x46c]
这样的语句,所以只能把栈往抬高,避免访问到不可写的内存区域。
- 如果题目给的
rop
很短,那么需要想办法调用read
写入更长的rop
链 - 必要的时候需要把栈抬高,避免在函数调用过程中,让不可写的内存写入了东西,直接
core dump
call
的时候会放置下一条指令到esp
,但如果直接覆写了esp
,那么还是可以继续劫持程序流
题目分析
checksec
很久没碰到32
位的题目了,环境为libc-2.27.so
函数分析
最开始的时候,IDA
无法识别函数。只需要在__printf_chk
这个函数上按下Y
,修改函数签名为int __printf_chk(int, const char*, ...);
即可
流程很简单,先往bss
段上写数据,然后有整数溢出和栈溢出:
刚开始以为是很简单的栈溢出,后来瞅了眼main
函数退出的时候的汇编,发现栈直接被改变了:
这里的esp
来自于ecx
,而ecx
可控。没有地址泄露,所以只能往bss
段搞栈迁移。
所以一开始直接准备:
puts
泄露地址- 重新执行
main
- 再次
rop
执行system(/bin/sh)
、
然而事情,并没有那么简单,在调用puts
的时候,由于栈太低了,会往更低处的不可写的区域赋值,程序直接GG
。然后想改成__printf_chk
,也遇到了类似的问题。
所以只能找一下read
函数,然后重新写一段长的rop
,并把栈抬到高处,再进行泄露和利用。
在输入passwd
长度的时候,只能写入0x10
个字节。去掉要转化为负数的-1\x00\x00
,只剩12
个字节可以操作。如果直接rop
,由于read
有3
个参数,所以至少需要0x14
的大小,很显然这里不够。所以只能利用程序中的call read
这样的汇编执令来缩小rop
的长度。
我们必须要控制的参数有read
的第二个和第三个参数,指明往bss
段写和写的大小。那么第一个参数fd
就没法控制,好在程序中就有,如下图:
有一个push 0
,省了不少事情。
因此,最终的解题思路为:
-
将栈迁移到
bss
段 -
rop
往buf
区域写更长的rop
-
将栈抬高
-
执行
puts
泄露地址 -
再次执行
read
读入rop
-
执行
system(/bin/sh)
这里还是不能回到main
函数,还是会出现往非法内存区域写入的操作。索性直接再次读入rop
,然后刚好esp
也在bss
段上,所以可控制执行system(/bin/sh)
Exp
|
|
栈迁移:
泄露地址:
第二次read
:
拿shell
:
远程打:
引用与参考
1、My Blog
2、Ctf Wiki
3、pwncli