3. PASE Shell安全:Qshell与PASE Shell的攻防博弈
Shell,说白了就是攻击者的第一道门。在IBM i上,这道门有两把锁:一把是Qshell,一把是PASE Shell。很多人觉得它们差不多,都是敲命令的地方。但在我眼里,这两者的安全边界天差地别。
我做过不少IBM i的渗透测试,坦白讲,大部分客户对Qshell还算有点警觉,毕竟它跟IBM i的传统权限模型绑得紧。但PASE Shell?嗯,很多人把它当成了“Linux虚拟机”来用,安全配置几乎裸奔。今天我们就来聊聊这两个Shell的区别,以及最要命的两个攻击面:环境变量注入和PATH劫持。
3.1 Qshell vs PASE Shell:不只是名字不同
先看一张对比表,把核心差异说清楚:
| 对比维度 | Qshell | PASE Shell |
|---|---|---|
| 运行环境 | IBM i 原生POSIX子系统 | AIX兼容层(PASE内核扩展) |
| 默认Shell | /QOpenSys/usr/bin/bsh (Korn变体) | /usr/bin/ksh 或 /usr/bin/bash |
| 权限模型 | 继承IBM i *USER profile权限 | 映射到AIX风格的UID/GID |
| 文件系统 | QOpenSys + IFS根文件系统 | PASE独立文件系统(/usr, /etc等) |
| 环境变量来源 | 系统值QIBM_QSH_* + 用户profile | /etc/environment + .profile |
| 典型漏洞面 | 命令注入、权限提升 | 环境变量注入、PATH劫持、LD_PRELOAD |
我个人习惯把Qshell看作“穿了西装的Shell”——它跟IBM i的权限体系绑得死死的,想越权?没那么容易。但PASE Shell更像“穿便装的Shell”,它模拟的是AIX环境,很多Linux上的攻击手法在这里直接能用。
核心观点:PASE Shell的安全问题,本质上是“AIX兼容层”带来的信任边界模糊。攻击者只要进了PASE,就能用标准Unix攻击手法绕过IBM i的很多原生防护。
3.2 环境变量注入:看不见的“后门”
环境变量注入,说白了就是攻击者通过控制Shell启动时的环境变量,改变程序的行为。在PASE Shell里,这个攻击面尤其大。
为什么会这样?因为PASE Shell启动时会读取多个环境变量文件,而且读取顺序有优先级。我遇到过最典型的一个案例:某客户在PASE里跑了一个Java应用,启动脚本里写了export LD_LIBRARY_PATH=/app/lib。结果攻击者通过一个上传功能,在/tmp下放了一个同名的恶意.so文件,然后修改了LD_LIBRARY_PATH的顺序——嗯,程序下次启动时,直接加载了恶意库。
3.3.2.1 关键的可注入变量
在PASE Shell里,下面这几个变量是攻击者的“最爱”:
- PATH:控制命令搜索路径,劫持后可以替换系统命令
- LD_PRELOAD:强制预加载共享库,优先级最高
- LD_LIBRARY_PATH:修改库搜索路径
- IFS:内部字段分隔符,可以改变命令解析行为
- PS1/PS2:提示符变量,可以注入控制字符
⚠️ 特别注意:在PASE Shell中,LD_PRELOAD默认是生效的!这和Linux上的现代安全机制(比如glibc的__secure_getenv)不同。IBM i的PASE实现没有完全移植这些防护,所以LD_PRELOAD攻击在PASE上成功率极高。
3.3.2.2 注入攻击的典型流程
我画了一张流程图,帮你理解攻击者是怎么一步步得手的:
3.3 PATH劫持攻击:最经典的“狸猫换太子”
PATH劫持,说白了就是攻击者通过修改PATH环境变量,让系统执行攻击者指定的恶意程序,而不是原本的系统命令。这个攻击手法在Unix/Linux世界已经存在了几十年,但在PASE Shell上,它依然有效得可怕。
我曾经在某个项目中遇到过:客户的PASE环境里跑着一个定时任务,脚本里调用了tar命令做备份。攻击者发现/tmp目录可写,就在/tmp下放了一个同名的恶意tar脚本,然后通过注入PATH=/tmp:$PATH——嗯,下次定时任务运行时,直接执行了恶意脚本,把备份数据全传到了外部服务器。
3.3.1 攻击者如何构造PATH劫持
典型的攻击步骤是这样的:
- 侦察阶段:查看目标用户的
.profile或.kshrc,找到PATH定义 - 寻找可写目录:检查
/tmp、/var/tmp、用户家目录等 - 创建恶意命令:在可写目录下创建与系统命令同名的恶意脚本
- 修改PATH:通过
export PATH=/tmp:$PATH将恶意目录前置 - 触发执行:等待目标用户或定时任务调用该命令
💡 避坑指南:我曾经见过一个案例,攻击者没有直接修改PATH,而是利用了IFS变量。他把IFS设为/,然后执行/bin/ls——结果Shell把路径拆成了bin和ls,然后执行了当前目录下的bin命令。这种手法更隐蔽,因为管理员检查PATH时发现没被改过。
3.3.2 防御PATH劫持的实战策略
防御不能只靠一个点,要层层设防。我总结了下面几个关键措施:
| 防御层级 | 具体措施 | 实施难度 | 效果 |
|---|---|---|---|
| 用户层 | 在.profile中硬编码绝对路径,如PATH=/usr/bin:/bin |
低 | 中(依赖用户自觉) |
| 系统层 | 使用chmod 755锁定系统目录,禁止普通用户写/tmp |
中 | 高 |
| Shell层 | 启用restricted shell或rbash,限制PATH修改 |
中 | 高 |
| 监控层 | 审计PATH变更事件,记录export PATH操作 |
高 | 极高 |
| 应用层 | 在脚本中使用command或which验证命令来源 |
低 | 中 |
3.4 实战防御:从攻击者视角加固PASE Shell
说了这么多攻击手法,我们来点实在的。下面是我个人在项目中验证过的加固方案:
3.4.1 环境变量白名单
在PASE Shell的启动脚本(/etc/profile和~/.profile)中,显式重置关键环境变量:
# 在 /etc/profile 开头添加
# 重置PATH为安全值
PATH=/usr/bin:/bin:/usr/sbin:/sbin
export PATH
# 清除危险变量
unset LD_PRELOAD
unset LD_LIBRARY_PATH
unset IFS
# 只读保护(如果Shell支持)
readonly PATH
readonly LD_PRELOAD 2>/dev/null || true
⚠️ 注意:PASE Shell的readonly命令不是所有版本都支持。在较老的IBM i版本(7.2之前)上,readonly可能被绕过。我建议配合文件系统权限一起使用。
3.4.2 文件系统权限锁定
这是最基础也最有效的一招:
- 把
/tmp挂载为noexec(如果PASE支持) - 把用户家目录的写权限收窄,只允许必要用户
- 对
/usr/bin、/bin等系统目录设置chmod 755,属主为root - 定期扫描可写目录,查找可疑的同名脚本
3.4.3 使用绝对路径调用命令
这个习惯一定要养成。在脚本里,永远不要这样写:
# ❌ 危险写法
tar -czf backup.tar.gz /data
要改成这样:
# ✅ 安全写法
/usr/bin/tar -czf backup.tar.gz /data
核心原则:在PASE Shell中,永远不要相信环境变量。你写的每一行脚本,都要假设PATH已经被污染了。用绝对路径,是最简单、最有效的防御。
3.5 检测与应急响应
万一已经被攻击了怎么办?我分享几个快速检测的方法:
- 检查环境变量:执行
echo $PATH,看有没有异常目录(比如/tmp、/var/tmp)出现在前面 - 对比命令哈希:用
type tar或which tar,看返回的路径是不是系统标准路径 - 审计日志:检查IBM i的审计日志(QAUDJRN),搜索
QIBM_QSH_相关事件 - 文件完整性:对比
/usr/bin下关键命令的md5sum,看有没有被替换
嗯,到这里,PASE Shell的安全问题基本讲透了。记住一句话:Shell是攻击者的第一道门,也是你的最后一道防线。把环境变量管好,把PATH锁死,攻击者就没那么容易得手。