某项目管理系统审计
字数 4588 2025-11-05 23:45:18
某项目管理系统安全漏洞审计与分析教学文档
文档说明
本文档基于公开的漏洞分析文章,对某项目管理系统(具体系统名称未知)进行全面的安全审计教学。文档将深入剖析系统中存在的多个关键安全漏洞,包括权限绕过、敏感信息泄露、业务逻辑漏洞、越权访问和SQL注入。通过学习,您将掌握这些漏洞的发现思路、形成原理、验证方法及修复方案。
一、 漏洞概述
该项目管理系统的安全体系存在严重缺陷,攻击者可以通过组合利用多个漏洞,最终实现未授权获取所有用户敏感信息(包括密码)的目标。核心漏洞链如下:
- 权限绕过: 绕过前端登录过滤器,直接访问需要认证的接口。
- 敏感信息泄露与账户激活: 利用未授权接口泄露用户信息,并通过逻辑漏洞激活未审核账户。
- 越权访问: 在登录后,利用参数可控接口查询所有用户信息。
- SQL注入: 在上述查询接口中,存在可直接利用的SQL注入漏洞。
二、 漏洞详细分析
2.1 漏洞一:权限绕过 (LoginFilterFront 过滤器缺陷)
- 漏洞位置:
LoginFilterFront过滤器。 - 漏洞描述: 该过滤器负责对访问请求进行权限校验,但其校验逻辑存在缺陷,可被绕过。
- 技术原理:
- 过滤器通常会检查用户请求的URL,如果请求的是需要认证的资源(如
.jsp,.html,.do后缀的文件),则会验证用户会话(Session)是否已登录。 - 为实现某些公共页面的正常访问(如登录页面、注册页面),过滤器会配置一个白名单(
whiteList),白名单内的路径无需校验。 - 关键缺陷: 此系统的过滤器在获取请求路径时,使用了
HttpServletRequest.getRequestURI()方法。该方法返回完整的请求路径(例如:/project/user/login.do)。 - 绕过方法: 攻击者可以构造一个以白名单路径开头的URL,从而绕过校验。例如,如果
/user/login是白名单,那么攻击者访问/user/login/../admin/queryInfo.do,经过标准化后实际访问的是/admin/queryInfo.do,但getRequestURI()在过滤器进行白名单匹配时,可能仍返回/user/login/..开头的路径,导致匹配成功,校验被绕过。另一种常见情况是,过滤器白名单配置不完整,遗漏了某些关键接口。
- 过滤器通常会检查用户请求的URL,如果请求的是需要认证的资源(如
- 复现步骤:
- 使用Burp Suite或浏览器开发者工具,尝试直接访问一个需要权限的接口(如
xxx/secretPage.do),观察返回结果是否为“未登录”或跳转到登录页。 - 寻找一个已知的白名单路径(如登录页
xxx/user/login.do)。 - 构造URL:
xxx/user/login/../secretPage.do或尝试直接访问可能未被纳入过滤器的API接口路径。 - 发送请求,如果返回了敏感数据而非登录提示,则表明权限绕过成功。
- 使用Burp Suite或浏览器开发者工具,尝试直接访问一个需要权限的接口(如
2.2 漏洞二:敏感信息泄露与账户状态修改(业务逻辑漏洞)
-
漏洞点A:邮箱获取用户密码
- 漏洞位置:
queryUserInfoByUserName方法。 - 漏洞描述: 存在一个接口(可能与邮箱相关)在未授权的情况下,可以调用
queryUserInfoByUserName方法查询用户信息。 - 技术原理:
- 代码逻辑会检查单点登录(SSO)配置
sso.enable。在该系统中,此配置为false。 - 因此,程序会执行
UserInfoAccessSessionMySQL().queryUserInfoByUserName(userName)从本地数据库查询用户信息。 - 关键缺陷: 此方法返回的
User对象包含了用户的明文或加密存储的密码等极度敏感字段,并且该接口没有进行有效的权限控制。
- 代码逻辑会检查单点登录(SSO)配置
- 复现步骤:
- 通过权限绕过漏洞,直接访问触发
queryUserInfoByUserName的接口。 - 传入一个已知的用户名(如注册时使用的用户名)作为参数。
- 观察服务器响应,如果响应体中包含
password等相关字段,则漏洞存在。
- 通过权限绕过漏洞,直接访问触发
- 漏洞位置:
-
漏洞点B:修改用户状态
- 漏洞描述: 系统默认新注册的用户处于“未激活”或“禁用”状态(
userStat字段),无法登录。存在接口可以修改此状态。 - 技术原理:
- 这是一个典型的业务逻辑漏洞。系统应该只允许管理员(Admin)执行激活用户的操作。
- 然而,某个本应受控的接口(例如
updateUserStatus)可能因为权限绕过或本身缺乏权限检查,允许任意用户调用。
- 复现步骤:
- 首先注册一个新账户,此时该账户无法登录。
- 通过权限绕过漏洞,找到修改用户状态的接口(如
xxx/user/updateStatus.do)。 - 构造请求包,将
userStat参数修改为表示“激活”的值(如1或ACTIVE),并指定要修改的用户名(可以是自己刚注册的用户名)。 - 发送请求后,尝试用新注册的账户登录,若能登录成功,则漏洞存在。
- 漏洞描述: 系统默认新注册的用户处于“未激活”或“禁用”状态(
2.3 漏洞三:越权查询所有用户信息
- 漏洞位置: 查询用户信息的接口。
- 漏洞描述: 在成功登录后(例如利用漏洞二激活账户后),正常功能中存在一个查询用户信息的接口。该接口本应查询当前登录用户自身的信息,但由于参数处理不当,导致可以查询所有用户信息。
- 技术原理:
- 后端代码类似
queryAllUserInfo(String userName, String userStat)。 - 正常的业务逻辑是:如果不传入
userName和userStat参数,则默认查询当前登录用户的信息。 - 关键缺陷: 代码逻辑错误地处理了“参数为空”的情况。当这两个参数为空时,执行的SQL语句可能是
SELECT * FROM user_table而不是SELECT * FROM user_table WHERE id = ?,从而导致全表查询。
- 后端代码类似
- 复现步骤:
- 使用已登录的Cookie。
- 访问用户信息查询接口(如
xxx/user/queryUserInfo.do)。 - 不传递任何参数,或者传递空字符串/
null值的参数。 - 如果接口返回了系统中所有用户的详细信息列表,则存在越权漏洞。
2.4 漏洞四:SQL注入
- 漏洞位置: 与漏洞三相同的
queryUserInfoByUserName或类似接口。 - 漏洞描述: 在处理
userName参数时,直接进行了字符串拼接,而非使用预编译(Prepared Statement),导致SQL注入。 - 技术原理:
- 后端代码使用了危险的字符串拼接方式构造SQL:
String sql = "SELECT * FROM users WHERE username = '" + userName + "'"; - 攻击者可以控制
userName参数,注入恶意Payload。例如,传入' OR '1'='1,最终执行的SQL变为:SELECT * FROM users WHERE username = '' OR '1'='1',这将查询出所有用户记录。 - 此漏洞可与权限绕过漏洞结合,在未登录状态下直接利用,危害极大。
- 后端代码使用了危险的字符串拼接方式构造SQL:
- 复现步骤:
- 通过权限绕过漏洞,访问存在注入的接口。
- 使用工具(如Sqlmap)或手动检测。
- 手动检测示例:传入
tom',观察是否报数据库错误。然后传入tom' AND '1'='1和tom' AND '1'='2,观察返回结果是否不同。如果不同,则极有可能存在SQL注入。 - 使用Sqlmap:
sqlmap.py -u "http://target.com/xxx.do?userName=admin" --batch --dbs进行自动化探测。
三、 漏洞链利用场景演示
一个完整的攻击流程如下:
- 信息收集: 攻击者注册一个账户(如:
attacker),但该账户处于未激活状态。 - 权限绕过: 攻击者构造URL,绕过
LoginFilterFront,直接访问用户状态修改接口xxx/user/updateStatus.do。 - 激活账户: 攻击者通过该接口将
attacker账户的状态修改为“激活”。 - 登录系统: 使用
attacker账户正常登录,获取有效Cookie。 - 越权查询: 登录后,访问用户查询接口
xxx/user/queryUserInfo.do,不传入参数,下载全部用户列表。 - SQL注入(更深层次利用): 或者,在步骤2后,攻击者不登录,直接通过权限绕过访问查询接口,并附加SQL注入Payload(如
' UNION SELECT 1, database(), 3, 4...),直接窃取数据库信息(如数据库名、表结构、管理员密码哈希等)。
四、 修复建议
-
修复权限绕过:
- 路径校验: 在过滤器中,使用
getServletPath()而非getRequestURI()获取路径,并与白名单进行精确匹配或使用正则表达式严格限定。 - 规范化路径: 在比对前,先对
getRequestURI()的结果进行规范化(normalize),消除./和../的影响,再与白名单进行精确匹配。
- 路径校验: 在过滤器中,使用
-
修复敏感信息泄露与逻辑漏洞:
- 最小权限原则: 对所有API接口实施严格的权限控制(基于角色或权限码)。默认拒绝所有请求,仅显式允许授权访问。
- 敏感数据脱敏: 在返回用户信息的接口中,永远不要在响应体中返回
password、salt等敏感字段。 - 状态修改加固: 用户状态修改等重要操作,必须校验当前用户是否拥有管理员权限。
-
修复越权访问:
- 强制参数校验: 对于查询接口,不应在参数为空时默认查询全部数据。应强制要求传入查询条件。
- 服务端绑定用户ID: 查询用户信息时,应从当前登录用户的会话(Session)中直接获取其用户ID(如
session.getAttribute("userId")),而不是依赖客户端传递的参数。SQL应形如SELECT * FROM users WHERE id = ?,参数来自服务端。
-
修复SQL注入:
- 使用预编译语句(Prepared Statements): 这是根除SQL注入最有效的方法。将所有数据库查询改为参数化查询。
- 输入验证: 对所有用户输入进行严格的格式验证(如用户名只允许特定字符集)。
五、 总结
本案例是一个典型的多层安全缺陷导致的严重安全事件。它警示我们,安全是一个整体,需要从权限控制、业务逻辑、数据安全、代码安全等多个层面进行纵深防御。任何一个环节的疏忽都可能导致整个防御体系的崩塌。在代码开发和审计过程中,应始终坚持**“永不信任用户输入”和“最小权限”** 两大基本原则。
文档修订记录
- Version 1.0 | 生成日期: 基于提供内容 | 作者: 审计分析师