-
-
[原创]hctf 2018 部分pwn writeup
-
发表于: 2018-12-19 11:34 13165
-
这次比赛因为有事所以比赛期间做不了pwn题,现在只能事后看着大佬们的wp把题目再学习一波。
漏洞很明显,任意地址写五字节。
需要解决的问题是如何利用已有的五字节get shell。
首先checksec检查保护:
RELRO
是full,所以不能写got,然后在看到在最后返回的时候是直接掉用exit
函数的,因此应该是通过exit
函数里面掉用的函数指针来劫持控制流。
首先是信息泄露,得到libc
地址,这一点很明显。
大佬们的wp关于劫持函数流有两种思路,一种是利用stdout
的函数表,一种是_dl_fini
函数中的函数指针,下面对于这两种解法进行描述。
因为glibc是2.23的,没有vtable的检查,因此修改函数表不会引起程序的错误。
查看exit
函数的源码,exit中存在一条函数调用链,exit->__run_exit_handlers->_IO_cleanup->_IO_flush_all_lockp
。看到最后这个_IO_flush_all_lockp
就感觉应该可以利用这一点拿shell。这个函数里关键的源码是:
从源码中可以看到,如果可以控制stdin
、stdout
或者stderr
中实现fp->_mode <= 0
以及fp->_IO_write_ptr > fp->_IO_write_base
同时修改vtable里面的_IO_OVERFLOW
为one gadget,那么就可以顺利的劫持控制流。
经过测试,五字节的修改思路为:
exp如下:
还是查看exit
函数的源码,一条调用链是exit->_dl_fini
,查看_dl_fini
源码:
可以看到该函数调用了__rtld_lock_lock_recursive
函数,再看这个函数的定义:
查看宏GL
的定义:
_rtld_global
是一个结构体,所以__rtld_lock_lock_recursive
函数实际上是结构体中的一个函数指针,在gdb实际调试出现的指令为:
所以可以修改_rtld_global
结构体的__rtld_lock_lock_recursive
指针,将其修改为one gadget即可。
事实上,好像只要修改三个字节就可以实现了。
exp如下:
漏洞也很明显,格式化字符串漏洞,格式化字符串在bss段上,同时使用的是printf_chk函数。
格式化字符串的buff后面可以覆盖stdout
,因此这题最后的解仍然是使用stdout
来实现任意写任意读。由于是libc2.27,虚表存在检查,且在函数中也会将修改后的虚表改回去,因此无法使用函数表来做文章,但是仍然可以用stdout
结构体里的数据实现任意写与任意读。checksec
查看程序开启的保护机制:
程序看起了PIE
以及full
的RELRO
,因此无法修改got
表劫持控制流。
首先贴出_IO_FILE
结构体的定义,后面用的到:
里面前面的几个指针比较关键。
要实现完整的利用,首先是要实现地址泄露,可以通过stdout
的任意读来实现地址的泄露。在程序中,我们已知的是程序的基址,因为一开始就打印出来了,可以利用bss段来伪造stdout
结构体来实现任意读,相关涉及到的源代码如下:
以及
因此需要控制stdout
结构体满足以下条件实现任意泄露:
_IO_read_end
等于_IO_write_base
以绕过多余的代码。
满足这三个条件,可实现任意读。当然不包含结构体里的_flags
字段的伪造,该字段都从原来的结构体里面复制过来,所以就没去分析该如何构造了。
任意写功能的实现在于IO缓冲区没有满时,会先将要输出的数据复制到缓冲区中,可通过这一点来实现任意地址写的功能。相关源代码如下:
可以看到当_IO_write_end
大于_IO_write_ptr
时,memcpy
就会调用,因此任意写,只需要将_IO_write_ptr
指向需要写的地址,_IO_write_end
指向结束位置即可。
有了任意读与任意写之后,具体实现就是使用任意读泄露libc地址,然后用任意写将one gadget
写到malloc_hook
中,然后利用%n
报错或者是较大的字符打印来触发malloc函数。
最终的exp如下:
存在一个off-by-null
的漏洞,在函数sub_EE0
中,会超过一字节并置0。
感谢bscause大佬的off-by-null
的利用思路:
根据官方的wp,这题的主要考点在于malloc的时候只能申请大小小于等于0x38的块,只能申请fastbin,无法构造overlap chunk,所以出题人设置了scanf
函数,使得可以通过scanf
来触发malloc
申请比较大的堆块,从而触发malloc consolidate
,使得构造重叠块成为可能。
接着就按上面的思路构造了重叠块,后面利用fastbin里的数据,将top chunk覆盖成了malloc hook上面一点的地址,最后申请出来,覆盖为one gadget,得到shell。
exp如下:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)