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 注入攻击的典型流程

我画了一张流程图,帮你理解攻击者是怎么一步步得手的:

PASE Shell环境变量注入攻击流程 1. 攻击者获得PASE Shell访问 2. 探测可写目录和环境变量加载顺序 3. 在可写目录放置恶意库/脚本(如/tmp/libevil.so) 4. 通过环境变量注入修改搜索路径 5. 触发目标程序执行,加载恶意代码 关键点:攻击者不需要root权限,只要目标程序以受害用户身份运行,注入就有效

3.3 PATH劫持攻击:最经典的“狸猫换太子”

PATH劫持,说白了就是攻击者通过修改PATH环境变量,让系统执行攻击者指定的恶意程序,而不是原本的系统命令。这个攻击手法在Unix/Linux世界已经存在了几十年,但在PASE Shell上,它依然有效得可怕。

我曾经在某个项目中遇到过:客户的PASE环境里跑着一个定时任务,脚本里调用了tar命令做备份。攻击者发现/tmp目录可写,就在/tmp下放了一个同名的恶意tar脚本,然后通过注入PATH=/tmp:$PATH——嗯,下次定时任务运行时,直接执行了恶意脚本,把备份数据全传到了外部服务器。

3.3.1 攻击者如何构造PATH劫持

典型的攻击步骤是这样的:

  1. 侦察阶段:查看目标用户的.profile或.kshrc,找到PATH定义
  2. 寻找可写目录:检查/tmp、/var/tmp、用户家目录等
  3. 创建恶意命令:在可写目录下创建与系统命令同名的恶意脚本
  4. 修改PATH:通过export PATH=/tmp:$PATH将恶意目录前置
  5. 触发执行:等待目标用户或定时任务调用该命令

💡 避坑指南:我曾经见过一个案例,攻击者没有直接修改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 检测与应急响应

万一已经被攻击了怎么办?我分享几个快速检测的方法:

  1. 检查环境变量:执行echo $PATH,看有没有异常目录(比如/tmp、/var/tmp)出现在前面
  2. 对比命令哈希:用type tar或which tar,看返回的路径是不是系统标准路径
  3. 审计日志:检查IBM i的审计日志(QAUDJRN),搜索QIBM_QSH_相关事件
  4. 文件完整性:对比/usr/bin下关键命令的md5sum,看有没有被替换

嗯,到这里,PASE Shell的安全问题基本讲透了。记住一句话:Shell是攻击者的第一道门,也是你的最后一道防线。把环境变量管好,把PATH锁死,攻击者就没那么容易得手。