HackThisSite - Extended Basic Mission 02

Challenge

You have this function, provide the value which must be POST-ed as filename to obtain the desired results: Get the source code of hackthissite.org/index.php

给出一个把 POST 参数 filename 拼上 .php 后读取文件的函数,要求给出 filename 的值,读到站点根 index.php 的源码。

1
2
3
<?php
$lvl_text = file_get_contents($_POST['filename'].'.php');
?>

Solution

file_get_contents 把一个路径当文件读成字符串,返回的是原始字节,不经过 PHP 解释器,所以读 .php 文件拿到的是源码。这正是题面要的 source code:读 index.php 得到它磁盘上的内容,而不是它渲染出来的页面。

路径完全由 $_POST['filename'] 决定,程序只做两件事:拼上 .php、然后读。没有任何目录白名单,也没有过滤 ..

函数固定追加 .php,乍看像扩展名黑名单。但 file_get_contents 不执行 PHP,读 .php 文件本来就是拿源码;而目标 index.php 的文件名里正好带 .php:追加的后缀恰好对得上,不构成障碍。真正要解决的是路径:提交处理脚本在 /missions/extbasic/ 下,目标是站点根的 index.php

处理脚本位于站点根的下面两级,往上爬两级再指名 index

1
/missions/extbasic/  ->  ..  ->  /missions/  ->  ..  ->  /

Key points

  • $_POST['filename'] 未经校验进入 file_get_contents,构成路径遍历;用户控制的路径要先规范化再校验是否落在允许目录内(realpath 后做前缀比对)。
  • file_get_contents 读的是源码而不是执行结果,所以给 .php 目标补 .php 后缀不构成防护:这里的扩展名过滤是错觉。
  • ../ 的层数取决于处理脚本相对目标的深度:本关处理脚本在 /missions/extbasic/,距站点根两级,故用 ../../
  • 现代 PHP 里 %00 空字节截断早已失效(PHP 5.3.4 起字符串不再被 NUL 截断),本关也不需要它:目标本身就以 .php 结尾。
../../index