看了这篇帖子 https://bbs.pediy.com/thread-223659.htm
前人之述备矣,然在下仍觉细节尚缺,故有此文。
看了题目名字就知道这是32c3那道readme翻版。
32c3那道题是一个栈溢出,通过stack_chk_fail去调用fortify_fail。
当时的利用方法是控制栈上的参数,也就是argv和环境变量。特别注意要控制LIBC_FATAL_STDERR_=1
让fortify_fail能够把输出作为stderr给我们。否则fortify_fail
下层接的是libc_message
,而libc_message
调用的是getenv
。
getenv就是从environ指针那里去找环境变量指针数组。
getenv如果发现这环境变量没设置,libc_message会syscall调用open('/dev/tty')
,输出你是看不到的。
而34c3这道题的想法应该是源自于0ctf 2017里面的easiest printf(个人猜测)。
当时在0ctf结束后的irc里面,rpisec的人说到了一种非预期解法,就是改printf相关的两个函数指针,用自定义扩展%k调用shell。连dragon sector的人都很吃惊。
这种精巧的利用来源于printf的一个功能:https://www.gnu.org/software/libc/manual/html_node/Customizing-Printf.html#Customizing-Printf
我不知道原帖作者是否仔细看了GNU的文档或者printf的源代码。
这里实际有两次RIP控制的机会,对应与printf的逻辑:首先是printf_arginfo_table
,调用函数指针完成自定义spec的参数数目和类型的指定,后来才是对应的printf_function_table
做真正的输出。
这里还有一点是,看完printf的代码你会知道,检查自定义spec是优先于printf自带的spec的。
于是ESPR他们应该是造了readme-revenge来结合上述两道题。
由于这道题是静态连接,又有bss
段上的溢出,于是可以控制printf相关的函数指针和libc_argv
。那么你就可以去构造%s对应的函数指针去控制RIP。
但是需要注意到environ
指针是你覆盖不到的,他的位置在输入的上面。
所以说这种原帖作者所说的利用是存在问题的,你控制不了envivon啊?我不知道原帖作者是忘了、不知道还是故意没提(我希望是前两者)。在下第一时间就是因为这一点所以觉得这种思路不可用,去漫天找其他gadget。
实际上,217的同学也表示队友找了5个小时RCE的gadget找不到。
04:46 < david942j> _2can: yap.. it took my teammate 5hrs to try to do RCE (but fails as well)
<del> 是的,想要做这道题,需要撞大运,撞一个主办方帮你设置了环境变量LIBC_FATAL_STDERR_=1
。 </del>
更新:2018年1月16日 20:41:28
发现并不是如此。似乎xinetd有一些奇怪的行为,LIBC_FATAL_STDERR并不需要设置,readme那题我自己用docker+xinetd起了之后发现不设置这个环境变量也有flag回来。
于是strace上去看了一波,发现如下操作
还是回到__libc_message
这个函数:
即是说在docker xinetd的环境下,open('/dev/tty')
会失败?
对比一下ncat的结果,
open成功,write也就自然喷给了/dev/tty。
于是自己也实际跑了一次xinetd,发现仍然open失败。
在网络上搜了一会儿,找不到xinetd和/dev/tty相关的资料。希望有了解的朋友可以分享告诉我,不胜感激。
目前的猜测是:xinetd有一些奇怪的操作,导致open失败,然后还是会走stderr喷flag出来。所以之前32c3那道题,设置环境变量是多余的。但是ncat是需要同时设置环境变量和2>&1的。
更新:2018年1月19日 23:02:11
今天抽空看了下xinetd的源代码,通过/dev/tty很快定位到了util.c
然后再在init.c中找到了这个函数的调用。
搜索了一番后,网络上的说法是这是一种做daemon的常规套路。
此贴至此终结 (应该没后续了吧?)
后续:实际上还不对,早上起来想起我们平时都是dontfork的,不应该走daemon,再研究了一下,发现是docker本身的问题。
https://github.com/moby/moby/issues/14
看起来不-it就不会分配tty。
发现删除线不好使了,用引用代替吧。
一个队友去撞了,于是成功get flag……真的是……哎。
如果你想要复现这个题目,要注意服务端把stderr导给stdout,并且把环境变量设好。
最后感谢原帖作者的分享。在下写这篇文章不是想批判原帖作者,只是认为有必要做一点细节的补充。因为个人认为,这些质量上乘的题目,好就好在引导我们去深入更加底层的程序运作和代码实现的细节。
希望能在pwn板块上看到更多的,经过自己辛勤探索、苦读代码、精心分析所得的干货。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!