📚 网络安全 Kali 学习系列
模块 0 基础阶段 ✅ 已完成
01-18 Linux系统 → 计算机网络 → 密码学 → Python/Bash/PHP/JS → Docker
模块 1 信息收集与侦察 ✅ 已完成
19 nmap 主动扫描 → 20 masscan 高速扫描 → 21 指纹识别与目录爆破 → 22 漏洞扫描与 Web 安全基础
模块 2 Web 应用渗透(攻击技术阶段)
✓ 23 sqlmap 注入与 Burp 抓包
✓ 24 XSS 跨站脚本攻击
✓ 25 CSRF 与文件上传漏洞
26 命令执行与代码执行漏洞(当前篇)
27 文件包含与 SSRF(预告)
模块 3-5 共 XX 篇,后续持续更新

命令执行与代码执行漏洞:直接拿到 Shell 的致命漏洞

模块 2 Web 应用渗透 · 高级篇 · 最危险的 Web 漏洞类型之一
读完本篇你将能:理解命令注入和代码执行漏洞的本质区别——前者让操作系统执行命令,后者让应用执行代码。掌握命令注入的常见场景(ping、traceroute、文件操作)和六大绕过技巧(管道符、换行、通配符、编码等);了解 PHP 危险函数(eval、assert、system、exec 等)的利用方式;以及两种漏洞的防御手段(白名单、参数绑定、禁用危险函数)。命令执行漏洞往往意味着直接获取服务器权限,是 Web 渗透中危害等级最高的漏洞类型。
📑 本文目录
01命令注入原理:拼出来的系统命令
02命令注入绕过技巧大全
03代码执行漏洞:eval 的诅咒
04PHP 危险函数全景与利用
05防御与修复:从源头切断
06道德边界与法律红线
07分级练习与知识回顾

一、命令注入原理:拼出来的系统命令

命令注入(Command Injection)是指攻击者通过在输入参数中注入恶意命令,使得 Web 应用执行了非预期的系统命令。它和 SQL 注入的原理非常相似——都是"把用户输入拼接到命令/语句中执行",只不过 SQL 注入拼的是 SQL 语句,命令注入拼的是操作系统命令。

SQL 注入攻击的是数据库,命令注入攻击的是操作系统。一旦成功,攻击者就能以 Web 服务进程的权限在服务器上执行任意命令——这通常意味着拿到了服务器的初步控制权。

类比:想象你去餐厅吃饭,服务员问你"要什么菜?",然后把你的回答直接告诉后厨。你说"宫保鸡丁",后厨就做宫保鸡丁。但如果你说"宫保鸡丁,然后把后厨的钥匙给我",服务员不加思考地把整句话传给后厨,后厨的人就可能真的把钥匙给你——这就是命令注入。正常情况下输入的是"菜名"(命令参数),但攻击者把额外的"指令"(新的命令)混在参数里,而系统没有区分参数和命令。

1.1 典型场景:网络诊断工具

命令注入最经典的场景就是"在线 Ping"或"在线 Traceroute"功能。很多网管系统提供"输入 IP 地址,测试网络连通性"的功能,底层其实就是调用系统的 ping 命令。

假设后端代码是这样写的(PHP 示例):

ping.php - 存在命令注入漏洞的代码
// 获取用户输入的 IP 地址
<?php
$ip = $_GET['ip'];
 
// 直接拼接到系统命令中执行
system("ping -c 4 " . $ip);
?>

正常用户输入 192.168.1.1,执行的命令是 ping -c 4 192.168.1.1,一切正常。

但如果攻击者输入 192.168.1.1; id,实际执行的命令就变成了:

注入后的实际命令
ping -c 4 192.168.1.1; id

分号 ; 是 Shell 中的命令分隔符,它把一行命令分成了两条——先执行 ping,再执行 id。攻击者就这样"额外"执行了一条系统命令。

1.2 命令注入 vs 代码执行:别搞混了

命令注入和代码执行经常被放在一起讲,但它们不是一回事:

对比维度 命令注入 代码执行
执行层 操作系统(Shell) 应用层(PHP/Python/JS)
注入对象 系统命令(bash/sh/cmd) 编程语言代码
常见入口 system()、exec()、shell_exec() eval()、assert()、动态函数
权限范围 Web 进程的系统权限 应用语言的运行权限

简单说:命令注入是让服务器操作系统执行命令,代码执行是让服务器的应用程序执行代码。命令注入的权限通常更大(直接操作系统级别的命令),但代码执行也可以通过调用系统函数间接拿到命令执行权限。

二、命令注入绕过技巧大全

真实场景中,很多应用会对输入做一些过滤,比如过滤空格、过滤某些关键字。这时候就需要掌握各种绕过技巧。下面介绍常用的绕过方法。

2.1 命令连接符

Shell 中有多种命令连接符,可以在一条命令后追加另一条命令:

符号 作用 示例
; 顺序执行,前命令失败不影响后命令 127.0.0.1; id
&& 逻辑与,前命令成功才执行后命令 127.0.0.1 && id
|| 逻辑或,前命令失败才执行后命令 fake_cmd || id
| 管道,前命令输出作为后命令输入 127.0.0.1 | id
& 后台执行,前命令后台运行 127.0.0.1 & id

2.2 空格绕过

如果空格被过滤了,可以用以下方式替代空格:

• Tab 制表符:用 %09(URL 编码的 Tab)替代空格
• 重定向符号:cat<flag.txt 用小于号替代空格
• 花括号展开:{cat,flag.txt} Bash 花括号展开会自动加空格
• IFS 变量:Shell 的 IFS(内部字段分隔符)默认包含空格,可以用 $IFS$9 替代空格

2.3 关键字绕过

如果某些命令关键字(如 cat、flag)被过滤了:

• 通配符:用 /???/c?t f???.txt 匹配 cat 和 flag.txt(? 匹配单个字符,* 匹配任意)
• 变量拼接:a=c; b=at; $a$b flag.txt 变量拼接成 cat
• Base64 编码:echo Y2F0IGZsYWcudHh0 | base64 -d | bash 把命令 base64 编码后解码执行
• 反斜杠转义:c\at fl\ag.txt 反斜杠在 Shell 中被当作转义符,不影响命令执行
💡 小贴士
命令注入的绕过技巧非常多,核心思路是"用各种方式构造出目标命令字符串"。Shell 的语法非常灵活——变量替换、命令替换、通配符、重定向、管道……这些本来用于方便 Shell 编程的特性,都可能被用来绕过过滤。测试时要从多个角度尝试,不能只试一两种就放弃。

三、代码执行漏洞:eval 的诅咒

代码执行漏洞(Code Execution)是指应用程序将用户输入当作代码执行的漏洞。与命令注入不同,代码执行发生在应用程序语言层面——PHP 执行 PHP 代码,Python 执行 Python 代码,JavaScript 执行 JS 代码。

代码执行漏洞通常源于对"动态执行"功能的滥用。很多编程语言提供了"把字符串当代码执行"的函数(如 PHP 的 eval()、Python 的 exec()),这些函数本身没有错,但如果把用户可控的字符串传给它们,就会造成代码执行漏洞。

3.1 最经典的代码执行:eval()

eval() 函数几乎存在于所有编程语言中,它的作用就是把字符串当作代码执行。如果用户能控制 eval() 的参数,就能执行任意代码。

calc.php - 存在代码执行漏洞的计算器页面
// 一个"在线计算器"功能,用户输入表达式,用 eval 计算结果
<?php
$expr = $_GET['expr'];
eval("echo " . $expr . ";");
?>

正常用户输入 1+1,eval 执行 echo 1+1;,输出 2。

但攻击者可以输入 1;phpinfo();,实际执行的代码变成:

注入后 eval 实际执行的代码
echo 1;phpinfo();

分号结束了 echo 语句,然后 phpinfo() 作为新的语句被执行。攻击者成功执行了任意 PHP 代码。

3.2 代码执行的常见场景

除了直接使用 eval(),代码执行还可能出现在这些场景中:

• 模板引擎:某些模板引擎允许在模板中执行代码,如果用户能控制模板内容,就可能造成代码执行
• 动态函数调用:$func = $_GET['f']; $func(); 函数名由用户控制
• 反序列化:PHP/Python/Java 的反序列化过程中,如果存在魔法方法(__wakeup、__destruct 等),可能触发代码执行
• preg_replace /e 修饰符:PHP 的 preg_replace 使用 /e 修饰符时,替换结果会被当作 PHP 代码执行(PHP 5.x 存在,PHP 7 已废弃)
• 断言函数:PHP 的 assert() 在某些版本中会把字符串参数当作代码执行

四、PHP 危险函数全景与利用

PHP 是 Web 安全中最常遇到的语言,它的"灵活"特性也带来了最多的安全问题。以下是 PHP 中常见的危险函数分类:

4.1 命令执行类函数

函数 作用 返回值
system() 执行命令并直接输出结果 输出最后一行
exec() 执行命令,结果存入数组 输出最后一行
shell_exec() 执行命令,返回全部输出 全部输出字符串
passthru() 执行命令并直接输出原始结果 无返回值(直接输出)
popen() 打开进程指针,可读写 进程指针
反引号 `` PHP 特有语法,等同 shell_exec 全部输出字符串

4.2 代码执行类函数

函数 作用 危险等级
eval() 将字符串作为 PHP 代码执行 极高
assert() 断言检查,字符串参数会被执行 极高
call_user_func() 调用第一个参数指定的函数 高
create_function() 创建匿名函数(PHP 7.2 废弃) 高
⚠️ 常见错误
"disable_functions 禁用了 system 就安全了" — 只禁一个函数没用,绕过方式太多
✓ 正确理解:PHP 中能执行命令的函数至少有十几种(system、exec、shell_exec、passthru、popen、proc_open、pcntl_exec...),只禁几个没用。而且就算命令执行函数全禁了,代码执行本身也能做很多事——读文件、写文件、操作数据库等。真正的安全是从架构上避免让用户输入进入这些危险函数。

五、防御与修复:从源头切断

5.1 命令注入防御

命令注入的核心是"用户输入被拼接到命令中执行",防御就要从这个根上解决:

1 尽量不调用系统命令:能用语言自带的函数/库实现的功能,就不要调用系统命令。比如 PHP 可以用 fsockopen 实现 ping 功能,而不是调用系统的 ping 命令
2 使用白名单过滤:如果必须调用系统命令,对输入参数进行严格的白名单校验。比如 IP 地址用正则匹配 IP 格式,文件名只允许字母数字下划线点
3 使用 escapeshellarg / escapeshellcmd:PHP 提供了 escapeshellarg()(把参数转义为安全的 shell 参数)和 escapeshellcmd()(转义 shell 元字符),可以有效防止命令注入
4 参数数组传递:使用 proc_open 等函数以数组形式传递参数,而不是拼接字符串。数组方式下每个参数都是独立的,不会被 Shell 解析

5.2 代码执行防御

• 禁用危险函数:在 php.ini 的 disable_functions 中禁用不需要的危险函数(eval、assert、system、exec 等)
• 避免 eval/assert:不到万不得已不要使用 eval 和 assert,它们是代码执行的最大源头
• 安全配置:开启 open_basedir 限制 PHP 可访问的目录范围,降低被利用后的危害
• 最小权限原则:Web 服务进程以低权限用户运行(如 www-data、nobody),即使被攻破也无法直接获取高权限
💡 小贴士
命令注入和代码执行的防御,最核心的一条原则是:永远不要把用户输入传给危险函数。如果你发现代码中需要把用户输入拼接到命令或 eval 中,应该立刻停下来想——有没有更安全的方式实现同样的功能?90% 以上的场景都有不调用系统命令的替代方案。防御的最佳方式,就是从架构上消除漏洞存在的可能性。

六、道德边界与法律红线

命令执行漏洞一旦成功,意味着你可以在目标服务器上执行任意命令——这已经是"拿到服务器权限"的级别了。这种级别的攻击,如果没有明确的授权,法律后果非常严重。

🚨 法律红线
根据《中华人民共和国刑法》第二百八十五条,非法侵入计算机信息系统或者采用其他技术手段获取该系统中数据的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。
命令执行漏洞的利用属于"采用其他技术手段"获取系统控制权,完全在刑法第二百八十五条的覆盖范围内。哪怕你只是执行了一个 id 命令,也是对系统的非法侵入。
🛡️ 正确的学习姿势
1. 本地靶场练习:用 Docker 搭建 DVWA、BWAPP、WebGoat 等靶场,在本地环境中练习命令注入和代码执行的利用
2. CTF 比赛:参加 CTF(夺旗赛)比赛,在主办方提供的合法环境中挑战 Web 题目
3. 漏洞赏金平台:在 HackerOne、补天、漏洞盒子等平台上,按照平台规则和厂商授权范围提交漏洞
4. 代码审计练习:读开源项目的代码,从代码中寻找命令注入和代码执行的漏洞点(只读不利用)

七、分级练习与知识回顾

🌟 入门级(理解原理)

• 在本地搭建 DVWA,完成 Command Injection 模块的 Low 级别
• 在本地测试 eval() 函数,输入不同 payload 观察执行结果
• 说出命令注入和代码执行的三个核心区别

⭐ 进阶级(掌握利用)

• 完成 DVWA Command Injection 的 Medium 和 High 级别,学会绕过简单过滤
• 用三种不同的空格绕过技巧(IFS、重定向、花括号)在命令注入场景中执行 cat /etc/passwd
• 用 base64 编码方式绕过关键字过滤,执行系统命令

💎 大师级(防御审计)

• 找一个开源 PHP 项目,从代码中审计出至少一处命令注入或代码执行漏洞点(不利用,只记录)
• 为一段存在命令注入漏洞的代码编写修复方案,使用 escapeshellarg 和白名单双重防护
• 思考:如果目标禁用了所有命令执行函数,仅保留代码执行权限,你还能做哪些攻击?列出至少 5 种攻击路径
🏷️ 知识回顾标签
命令注入 代码执行 eval system 管道符绕过 空格绕过 关键字绕过 PHP 危险函数 白名单过滤 escapeshellarg
📖 下一篇预告
下一篇我们将学习文件包含与 SSRF 漏洞。文件包含(LFI/RFI)是 PHP 应用中常见的漏洞类型,可以用来读取敏感文件甚至执行代码;SSRF(服务端请求伪造)则是利用服务器发起请求的能力,探测内网、攻击内网服务。这两种漏洞都属于"服务器端"漏洞,利用思路和命令执行有相通之处。