ctfhub-RCE
关于管道操作符
windows:
1. “|”:直接执行后面的语句。
2. “||”:如果前面的语句执行失败,则执行后面的语句,前面的语句只能为假才行。
3. “&”:两条命令都执行,如果前面的语句为假则直接执行后面的语句,前面的语句可真可假。
4. “&&”:如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则两条命令都执行,前面的语句只能为真。linux:
1. “;”:执行完前面的语句再执行后面的语句。
2. “|”:显示后面语句的执行结果。
3. “||”:当前面的语句执行出错时,执行后面的语句。
4. “&”:两条命令都执行,如果前面的语句为假则执行执行后面的语句,前面的语句可真可假。
5. “&&”:如果前面的语句为假则直接出错,也不执行后面的语句,前面的语句为真则两条命令都执行,前面的语句只能为真。关于转义字符
由反斜杠 \ 后面跟一个或多个字符组成,其目的是为了表示那些不能直接输入或具有特殊含义的字符。使用转义字符可以明确其表示的是普通字符而不是特殊含义
1.eval执行
开启环境,得到源码主要是eval函数
eval函数:将内容转为php语言进行执行
所以我们就直接传入参数cmd没有看到flag,就再往上进行穿越(或者直接进行查看根目录也可以)
查看到了flag,就去cat这个文件
2文件包含
得到源码
strpos函数:
strpos()
函数用于查找字符串中某个子字符串的位置。
那么这个代码就是:检查是否有get传参的参数file,查找参数file里是否有字符flag
由于代码是!strpos所以需要不含flag,如果含就会输出hacker
include():语句的主要作用是将指定文件的内容插入到当前 PHP 文件中该语句所在的位置,并当作当前文件的一部分来执行。
这里include()函数就提供了文件包含漏洞,文件包含漏洞同时要求那个被包含的文件是用户通过传参方式引入的,这个条件我们也满足了
那么我们就直接进行get传参,传入参数file,访问shell.txt,然后进入这个文件,看到有一个request传参“ctfhub”,所以进行传参查看就好了
php://input
源码
<?php
if (isset($_GET['file'])) {if ( substr($_GET["file"], 0, 6) === "php://" ) {include($_GET["file"]);} else {echo "Hacker!!!";}
} else {highlight_file(__FILE__);
}
?>
get传参传入参数file
且对参数file的前六个字符有限定,必须是“php://”
而且这里已经给了我们phpinfo界面了,我们直接看看
没有flag直接给出,但是我们传入php://input就可以执行传入的php代码
所以我们抓包去构造文件执行,写入命令执行的php代码
然后再进行cat那个flag文件
读取源代码
<?php
error_reporting(E_ALL);
if (isset($_GET['file'])) {if ( substr($_GET["file"], 0, 6) === "php://" ) {include($_GET["file"]);} else {echo "Hacker!!!";}
} else {highlight_file(__FILE__);
}
?>
get传参file,前六字节限定为php://
而且直接告诉了我们flag文件在哪
所以我们就直接去访问就好
用php伪协议
这样就得到了一串base64编码,进行base64解码就可以了
远程包含
和php://input类似
看到了flag,就去cat它
命令注入
源码
<?php$res = FALSE;if (isset($_GET['ip']) && $_GET['ip']) {$cmd = "ping -c 4 {$_GET['ip']}";exec($cmd, $res);
}?>
get传参传入参数ip
ping -c 4
是一个常见的命令,用于向指定的 IP 地址发送 4 个 ICMP 数据包。
也就是拼接了一个字符串,让用户输入ip就能执行ping命令
exec($cmd, $res);
:
调用 exec
函数执行存储在 $cmd
中的命令。
exec
函数会执行一个外部命令,并将命令的最后一行输出存储在 $res
数组中。
所以传入ip地址以及一个命令
用管道符进行分隔,来使后面的可以被执行,因为使用exec函数,那么ls命令可以被执行
过滤cat
源码
与上一题相似,get传参传入参数ip,管道符|直接执行后面的语句,我们随便用个ip,然后ls查看目录
看到了flag文件,cat它
但是源码中正则表达式将cat给过滤掉了,所以我们用tac
tac:从下往上查看
cat:从上往下查看
但是没看到有flag,我们就看源码
过滤空格
源码同样get传参,参数ip,正则表达式将空格过滤掉了
所以我们就用同样的方法查看目录
看到了flag文件,cat它
但是通常我们cat文件是cat <文件名>
但是这里过滤了空格,用$IFS$4
这样就可以查看flag文件里
空格过滤绕过:
1、大括号{}:
{cat,flag.php}
2、$IFS代替空格:
$IFS$9,${IFS},$IFS这三个都行
Linux下有一个特殊的环境变量叫做IFS,叫做内部字段分隔符 (internal field separator)。
?cmd=ls$IFS-I
单纯$IFS2,IFS2被bash解释器当做变量名,输不出来结果,加一个{}就固定了变量名
?cmd=ls${IFS}-l
$IFS$9后面加个$与{}类似,起截断作用,$9是当前系统shell进程第九个参数持有者始终为空字符串。
?cmd=ls${IFS}$9-l3、重定向字符<,<>
4、%09绕过(相当于Tab键)
过滤目录分隔符
;(命令分隔符): 无论前一个命令 cmd_1 是否成功,都会执行下一个命令 cmd_2。例: echo "Hello"
源码
<?php$res = FALSE;if (isset($_GET['ip']) && $_GET['ip']) {$ip = $_GET['ip'];$m = [];if (!preg_match_all("/\//", $ip, $m)) {$cmd = "ping -c 4 {$ip}";exec($cmd, $res);} else {$res = $m;}
}
?>
由于源码中禁用了分隔符\,所以我们不能直接访问某文件夹下的文件
但是我们可以进入某文件夹,只要没有穿越,就可以访问文件了
所以,我们先查看该级目录查看得到了一个目录,有flag,那么我们就进入后并cat这个flag
同样是没有直接看到flag,但是可以看到有一条空的数组的显示,那么就看源码
过滤运算符
源码
<?php$res = FALSE;if (isset($_GET['ip']) && $_GET['ip']) {$ip = $_GET['ip'];$m = [];if (!preg_match_all("/(\||\&)/", $ip, $m)) {$cmd = "ping -c 4 {$ip}";exec($cmd, $res);} else {$res = $m;}
}
?>
看源码,可以知道被禁用的运算符并不多 ,仅仅只是|和&
也就是说我们还有其他的没被禁用,比如;
所以我们就利用;来使后面的代码被执行
综合练习
源码
<?php$res = FALSE;if (isset($_GET['ip']) && $_GET['ip']) {$ip = $_GET['ip'];$m = [];if (!preg_match_all("/(\||&|;| |\/|cat|flag|ctfhub)/", $ip, $m)) {$cmd = "ping -c 4 {$ip}";exec($cmd, $res);} else {$res = $m;}
}
?>
被禁用了| ,\ ,& , 空格 ,/, ; cat ,flag ,ctfhub
管道符|,&,;都被禁用了,但是我们需要考虑用什么去替代他们实现
%0a可以替代管道符
所以得到:
看到了flag所在,我们再去查看一下flag_is_here目录
用*绕过flag,${IFS}绕过空格
得到了flag所在的文件,再进行cat
但是需要用tac来进行cat的绕过