在bWAPP中有一关是XML External Entity Attacks (XXE)传送门,比较简单的了解了一下XXE
师傅的博客
浅谈XML实体注入漏洞
XXE漏洞全称XML External Entity Injection即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等危害
xxe漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件
所以可以先来学习一下XML的相关知识XML 简介
简单了解如下
XML 被设计为传输和存储数据,其焦点是数据的内容HTML 被设计用来显示数据,其焦点是数据的外观
HTML 旨在显示信息,而 XML 旨在传输信息
XML 用于传输数据,而 HTML 用于格式化并显示数据
XML 把数据从 HTML 分离, XML 不是对 HTML 的替代,XML 是独立于软件和硬件的信息传输工具
基本语法
所有 XML 元素都须有关闭标签
XML 标签对大小写敏感
XML 文档必须有根元素
XML 的属性值须加引号
这里着重学习一下实体引用
在 XML 中,一些字符拥有特殊的意义,如果把这些字符放在XML元素中就会产生错误,所以必须用实体引用来代替
DTD 的作用是定义 XML 文档的结构。它使用一系列合法的元素来定义文档结构:
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。
DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
详见内部的 DOCTYPE 声明与外部文档声明
DTD元素
这里重点学习一下DTD实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量
实体引用是对实体的引用
实体可在内部或外部进行声明
内部实体声明语法
外部实体声明语法
附上实例:
内部实体声明
DTD 实例:XML 实例:
&writer;©right;
外部实体声明
DTD 实例:XML 实例:
&writer;©right;
注: 一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号(;)
XXE主要是利用了DTD引用外部实体导致的漏洞
输入任意账号密码进行抓包
观察请求包
发现头部:Accept: application/xml, text/xml, */*; q=0.01
构造XML声明和DTD部分,引用外部实体来进行实体调用
]>
<user><username>&test;username><password>Mikasapassword>user>
并且在元素中引用外部实体参数&test
查看回显
一般XXE利用分为两大场景:有回显和无回显。有回显的情况可以直接在页面中看到Payload的执行结果或现象,无回显的情况又称为blind xxe可以使用外带数据通道提取数据
xxe-lab是有回显的
看大佬的源码审计
/**
* autor: c0ny1
* date: 2018-2-7
*/
$USERNAME = 'admin'; //账号
$PASSWORD = 'admin'; //密码
$result = null;
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');//这里面因为没有xml文档所以用的是php的伪协议来获取我们发送的xml文档
try{
$dom = new DOMDocument();//创建XML的对象
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);//将我们发送的字符串生成xml文档。
$creds = simplexml_import_dom($dom);//这一步感觉相当于实例化xml文档
$username = $creds->username;//获取username标签的值
$password = $creds->password;//获取password标签的值
if($username == $USERNAME && $password == $PASSWORD){
//将获取的值与前面的进行比较。...
$result = sprintf("%d
%s ",1,$username);//注意必须要有username这个标签,不然的话找不到username,就没有了输出了,我们也不能通过回显来获取信息了
}else{
$result = sprintf("%d
%s ",0,$username);//与上方相同,都会输出username的值,都可以达到我们的目的
}
}catch(Exception $e){
$result = sprintf("%d
%s ",3,$e->getMessage());
}
header('Content-Type: text/html; charset=utf-8');
echo $result;
?>
还可以进行其他的恶意引入外部实体方式
详见XXE漏洞攻防
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("%d
%s ",1,username);
}else{
result = String.format("%d
%s ",0,username);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
result = String.format("%d
%s ",3,e.getMessage());
} catch (SAXException e) {
e.printStackTrace();
result = String.format("%d
%s ",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 "";
}
}
水平有限不会操作。。
Java XXE漏洞正确修复方法及原理
#coding=utf-8
'''
autor: c0ny1
date: 2018-2-7
'''
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 = "%d
%s " % (1,username)
else:
result = "%d
%s " % (0,username)
except Exception,e:
result = "%d
%s " % (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()
大佬说是要下载Python Flask 框架,然后运行即可
附上安装教程
按照提示先解决看看
再来尝试一下这种方法Windows下安装使用python的Flask框架
具体操作按上面的来就行,这里是终于成功了
但是运行过程中还是出错
我***
大佬说是放vs里,但我不会搞。。
使用菜单栏工具下的NuGet包管理器,在程序包管理控制台中输入 Install-Package Microsoft.CodeDom.Providers.DotNetCompilerPlatform
静静等待。
。。。
还是没有解决,放弃了