某项目管理系统审计
字数 4588 2025-11-05 23:45:18

某项目管理系统安全漏洞审计与分析教学文档

文档说明

本文档基于公开的漏洞分析文章,对某项目管理系统(具体系统名称未知)进行全面的安全审计教学。文档将深入剖析系统中存在的多个关键安全漏洞,包括权限绕过敏感信息泄露业务逻辑漏洞越权访问SQL注入。通过学习,您将掌握这些漏洞的发现思路、形成原理、验证方法及修复方案。

一、 漏洞概述

该项目管理系统的安全体系存在严重缺陷,攻击者可以通过组合利用多个漏洞,最终实现未授权获取所有用户敏感信息(包括密码)的目标。核心漏洞链如下:

  1. 权限绕过: 绕过前端登录过滤器,直接访问需要认证的接口。
  2. 敏感信息泄露与账户激活: 利用未授权接口泄露用户信息,并通过逻辑漏洞激活未审核账户。
  3. 越权访问: 在登录后,利用参数可控接口查询所有用户信息。
  4. SQL注入: 在上述查询接口中,存在可直接利用的SQL注入漏洞。

二、 漏洞详细分析

2.1 漏洞一:权限绕过 (LoginFilterFront 过滤器缺陷)

  • 漏洞位置LoginFilterFront 过滤器。
  • 漏洞描述: 该过滤器负责对访问请求进行权限校验,但其校验逻辑存在缺陷,可被绕过。
  • 技术原理
    1. 过滤器通常会检查用户请求的URL,如果请求的是需要认证的资源(如 .jsp, .html, .do 后缀的文件),则会验证用户会话(Session)是否已登录。
    2. 为实现某些公共页面的正常访问(如登录页面、注册页面),过滤器会配置一个白名单whiteList),白名单内的路径无需校验。
    3. 关键缺陷: 此系统的过滤器在获取请求路径时,使用了 HttpServletRequest.getRequestURI() 方法。该方法返回完整的请求路径(例如:/project/user/login.do)。
    4. 绕过方法: 攻击者可以构造一个以白名单路径开头的URL,从而绕过校验。例如,如果 /user/login 是白名单,那么攻击者访问 /user/login/../admin/queryInfo.do,经过标准化后实际访问的是 /admin/queryInfo.do,但 getRequestURI() 在过滤器进行白名单匹配时,可能仍返回 /user/login/.. 开头的路径,导致匹配成功,校验被绕过。另一种常见情况是,过滤器白名单配置不完整,遗漏了某些关键接口。
  • 复现步骤
    1. 使用Burp Suite或浏览器开发者工具,尝试直接访问一个需要权限的接口(如 xxx/secretPage.do),观察返回结果是否为“未登录”或跳转到登录页。
    2. 寻找一个已知的白名单路径(如登录页 xxx/user/login.do)。
    3. 构造URL:xxx/user/login/../secretPage.do 或尝试直接访问可能未被纳入过滤器的API接口路径。
    4. 发送请求,如果返回了敏感数据而非登录提示,则表明权限绕过成功。

2.2 漏洞二:敏感信息泄露与账户状态修改(业务逻辑漏洞)

  • 漏洞点A:邮箱获取用户密码

    • 漏洞位置queryUserInfoByUserName 方法。
    • 漏洞描述: 存在一个接口(可能与邮箱相关)在未授权的情况下,可以调用 queryUserInfoByUserName 方法查询用户信息。
    • 技术原理
      1. 代码逻辑会检查单点登录(SSO)配置 sso.enable。在该系统中,此配置为 false
      2. 因此,程序会执行 UserInfoAccessSessionMySQL().queryUserInfoByUserName(userName) 从本地数据库查询用户信息。
      3. 关键缺陷: 此方法返回的User对象包含了用户的明文或加密存储的密码等极度敏感字段,并且该接口没有进行有效的权限控制。
    • 复现步骤
      1. 通过权限绕过漏洞,直接访问触发 queryUserInfoByUserName 的接口。
      2. 传入一个已知的用户名(如注册时使用的用户名)作为参数。
      3. 观察服务器响应,如果响应体中包含 password 等相关字段,则漏洞存在。
  • 漏洞点B:修改用户状态

    • 漏洞描述: 系统默认新注册的用户处于“未激活”或“禁用”状态(userStat 字段),无法登录。存在接口可以修改此状态。
    • 技术原理
      1. 这是一个典型的业务逻辑漏洞。系统应该只允许管理员(Admin)执行激活用户的操作。
      2. 然而,某个本应受控的接口(例如 updateUserStatus)可能因为权限绕过或本身缺乏权限检查,允许任意用户调用。
    • 复现步骤
      1. 首先注册一个新账户,此时该账户无法登录。
      2. 通过权限绕过漏洞,找到修改用户状态的接口(如 xxx/user/updateStatus.do)。
      3. 构造请求包,将 userStat 参数修改为表示“激活”的值(如 1ACTIVE),并指定要修改的用户名(可以是自己刚注册的用户名)。
      4. 发送请求后,尝试用新注册的账户登录,若能登录成功,则漏洞存在。

2.3 漏洞三:越权查询所有用户信息

  • 漏洞位置: 查询用户信息的接口。
  • 漏洞描述: 在成功登录后(例如利用漏洞二激活账户后),正常功能中存在一个查询用户信息的接口。该接口本应查询当前登录用户自身的信息,但由于参数处理不当,导致可以查询所有用户信息。
  • 技术原理
    1. 后端代码类似 queryAllUserInfo(String userName, String userStat)
    2. 正常的业务逻辑是:如果不传入 userNameuserStat 参数,则默认查询当前登录用户的信息。
    3. 关键缺陷: 代码逻辑错误地处理了“参数为空”的情况。当这两个参数为空时,执行的SQL语句可能是 SELECT * FROM user_table 而不是 SELECT * FROM user_table WHERE id = ?,从而导致全表查询。
  • 复现步骤
    1. 使用已登录的Cookie。
    2. 访问用户信息查询接口(如 xxx/user/queryUserInfo.do)。
    3. 不传递任何参数,或者传递空字符串/null值的参数。
    4. 如果接口返回了系统中所有用户的详细信息列表,则存在越权漏洞。

2.4 漏洞四:SQL注入

  • 漏洞位置: 与漏洞三相同的 queryUserInfoByUserName 或类似接口。
  • 漏洞描述: 在处理 userName 参数时,直接进行了字符串拼接,而非使用预编译(Prepared Statement),导致SQL注入。
  • 技术原理
    1. 后端代码使用了危险的字符串拼接方式构造SQL: String sql = "SELECT * FROM users WHERE username = '" + userName + "'";
    2. 攻击者可以控制 userName 参数,注入恶意Payload。例如,传入 ' OR '1'='1,最终执行的SQL变为: SELECT * FROM users WHERE username = '' OR '1'='1',这将查询出所有用户记录。
    3. 此漏洞可与权限绕过漏洞结合,在未登录状态下直接利用,危害极大。
  • 复现步骤
    1. 通过权限绕过漏洞,访问存在注入的接口。
    2. 使用工具(如Sqlmap)或手动检测。
    3. 手动检测示例:传入 tom',观察是否报数据库错误。然后传入 tom' AND '1'='1tom' AND '1'='2,观察返回结果是否不同。如果不同,则极有可能存在SQL注入。
    4. 使用Sqlmap:sqlmap.py -u "http://target.com/xxx.do?userName=admin" --batch --dbs 进行自动化探测。

三、 漏洞链利用场景演示

一个完整的攻击流程如下:

  1. 信息收集: 攻击者注册一个账户(如:attacker),但该账户处于未激活状态。
  2. 权限绕过: 攻击者构造URL,绕过 LoginFilterFront,直接访问用户状态修改接口 xxx/user/updateStatus.do
  3. 激活账户: 攻击者通过该接口将 attacker 账户的状态修改为“激活”。
  4. 登录系统: 使用 attacker 账户正常登录,获取有效Cookie。
  5. 越权查询: 登录后,访问用户查询接口 xxx/user/queryUserInfo.do,不传入参数,下载全部用户列表。
  6. SQL注入(更深层次利用): 或者,在步骤2后,攻击者不登录,直接通过权限绕过访问查询接口,并附加SQL注入Payload(如 ' UNION SELECT 1, database(), 3, 4...),直接窃取数据库信息(如数据库名、表结构、管理员密码哈希等)。

四、 修复建议

  1. 修复权限绕过

    • 路径校验: 在过滤器中,使用 getServletPath() 而非 getRequestURI() 获取路径,并与白名单进行精确匹配或使用正则表达式严格限定。
    • 规范化路径: 在比对前,先对 getRequestURI() 的结果进行规范化(normalize),消除 ./../ 的影响,再与白名单进行精确匹配。
  2. 修复敏感信息泄露与逻辑漏洞

    • 最小权限原则: 对所有API接口实施严格的权限控制(基于角色或权限码)。默认拒绝所有请求,仅显式允许授权访问。
    • 敏感数据脱敏: 在返回用户信息的接口中,永远不要在响应体中返回 passwordsalt 等敏感字段。
    • 状态修改加固: 用户状态修改等重要操作,必须校验当前用户是否拥有管理员权限。
  3. 修复越权访问

    • 强制参数校验: 对于查询接口,不应在参数为空时默认查询全部数据。应强制要求传入查询条件。
    • 服务端绑定用户ID: 查询用户信息时,应从当前登录用户的会话(Session)中直接获取其用户ID(如 session.getAttribute("userId")),而不是依赖客户端传递的参数。SQL应形如 SELECT * FROM users WHERE id = ?,参数来自服务端。
  4. 修复SQL注入

    • 使用预编译语句(Prepared Statements): 这是根除SQL注入最有效的方法。将所有数据库查询改为参数化查询。
    • 输入验证: 对所有用户输入进行严格的格式验证(如用户名只允许特定字符集)。

五、 总结

本案例是一个典型的多层安全缺陷导致的严重安全事件。它警示我们,安全是一个整体,需要从权限控制、业务逻辑、数据安全、代码安全等多个层面进行纵深防御。任何一个环节的疏忽都可能导致整个防御体系的崩塌。在代码开发和审计过程中,应始终坚持**“永不信任用户输入”“最小权限”** 两大基本原则。


文档修订记录

  • Version 1.0 | 生成日期: 基于提供内容 | 作者: 审计分析师
某项目管理系统安全漏洞审计与分析教学文档 文档说明 本文档基于公开的漏洞分析文章,对某项目管理系统(具体系统名称未知)进行全面的安全审计教学。文档将深入剖析系统中存在的多个关键安全漏洞,包括 权限绕过 、 敏感信息泄露 、 业务逻辑漏洞 、 越权访问 和 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/.. 开头的路径,导致匹配成功,校验被绕过。另一种常见情况是,过滤器白名单配置不完整,遗漏了某些关键接口。 复现步骤 : 使用Burp Suite或浏览器开发者工具,尝试直接访问一个需要权限的接口(如 xxx/secretPage.do ),观察返回结果是否为“未登录”或跳转到登录页。 寻找一个已知的白名单路径(如登录页 xxx/user/login.do )。 构造URL: xxx/user/login/../secretPage.do 或尝试直接访问可能未被纳入过滤器的API接口路径。 发送请求,如果返回了敏感数据而非登录提示,则表明权限绕过成功。 2.2 漏洞二:敏感信息泄露与账户状态修改(业务逻辑漏洞) 漏洞点A:邮箱获取用户密码 漏洞位置 : queryUserInfoByUserName 方法。 漏洞描述 : 存在一个接口(可能与邮箱相关)在未授权的情况下,可以调用 queryUserInfoByUserName 方法查询用户信息。 技术原理 : 代码逻辑会检查单点登录(SSO)配置 sso.enable 。在该系统中,此配置为 false 。 因此,程序会执行 UserInfoAccessSessionMySQL().queryUserInfoByUserName(userName) 从本地数据库查询用户信息。 关键缺陷 : 此方法返回的 User 对象包含了用户的明文或加密存储的密码等极度敏感字段,并且该接口没有进行有效的权限控制。 复现步骤 : 通过权限绕过漏洞,直接访问触发 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' ,这将查询出所有用户记录。 此漏洞可与权限绕过漏洞结合,在未登录状态下直接利用,危害极大。 复现步骤 : 通过权限绕过漏洞,访问存在注入的接口。 使用工具(如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 | 生成日期: 基于提供内容 | 作者: 审计分析师