-
got-id-200
打开环境
进入场景后有3个链接,点进去都是.pl文件,.pl文件都是用perl编写的网页文件
尝试后发现,Files链接可以上传文件并把文件内容打印出来
想后台应该用了param()函数。
param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的接收变量中。如果我们传入一个ARGV的文件,那么Perl会将传入的参数作为文件名读出来。对正常的上传文件进行修改,可以达到读取任意文件的目的。
这里附上网上大佬们猜测的后台代码:
use strict;
use warnings;
use CGI;
my $cgi= CGI->new;
if ( $cgi->upload( 'file' ) ) {
my $file= $cgi->param( 'file' );
while ( <$file> ) { print "$_"; }
}
我们利用bp抓包
然后增加一个ARGV内容
ARGV内容如下:
-----------------------------203714850424912882901994417149
Content-Disposition: form-data; name="file";
Content-Type:image/jpeg
ARGV
这里注意修改一些东西
-
盲猜,flag在根目录下
2.正常流程做法
直接先读取file.pl文件,盲猜在/var/www/cgi-bin/file.pl试试
发现确实使用了param()函数,然后我们利用bash来进行读取当前目录下的文件。
Payload:?/bin/bash%20-c%20ls${IFS}/|
发现flag 我们读取flag就行
Payload:?cat%20/flag%20|
总结:
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的参数,而不是第一个参数(命令)的参数
举个例子:
bash -c ls /
会执行ls命令,列出当前目录,/会被当做bash的参数,没有意义,会找不到
如果我们想要列出根目录需要 “ls /”时,需要加入$IFS
IFS是linux的特殊变量,默认值是space空格, $是取变量值,$IFS就代表空格
就可以执行“ls /“的命令了
若只有 /bin/bash%20-c%20ls$IFS/ 命令会发现没有返回信息
因为,/etc/passwd本身就是文件,后端代码找到并输出返回在html标签中
而/bin/bash 一旦被访问输出,就是bash运行环境,整个语句的输出结果在shell的缓冲区里,也就是后台服务器才能看到,并不会输出到html标签中。在linux里我们只需要管道操作就可以指定结果的存放位置了。
注:经测试,${IFS}和/bin/bash联用时,不代表空格
Tips:Perl open()函数会默认打开一个管道!
这里利用Perl open()函数打开的管道,进行劫持,通过“|“操作符,把内容引入open()函数已经打开的管道中,就可以输出到html标签中啦!