zoukankan      html  css  js  c++  java
  • Natas31 Writeup(Perl 远程命令执行)

    Natas31:

    源码如下:

    my $cgi = CGI->new;
    if ($cgi->upload('file')) {
        my $file = $cgi->param('file');
        print '<table class="sortable table table-hover table-striped">';
        $i=0;
        while (<$file>) {
            my @elements=split /,/, $_;
    
            if($i==0){ # header
                print "<tr>";
                foreach(@elements){
                    print "<th>".$cgi->escapeHTML($_)."</th>";   
                }
                print "</tr>";
            }
            else{ # table content
                print "<tr>";
                foreach(@elements){
                    print "<td>".$cgi->escapeHTML($_)."</td>";   
                }
                print "</tr>";
            }
            $i+=1;
        }
        print '</table>';
    }
    else{
    print <<END;
    

    源码是将CSV文件里的数据拆分为表格形式。首先split函数按照“,”将csv中的每行进行分割,返回一个字符串列表。然后遍历列表中的字符串,将其分别使用escapeHTML()函数进行转义。最后将转义后的字符串填入表格中,用print函数输出到屏幕。

    进一步找出关键代码如下:

    //上传文件,打印内容
    
    my $cgi = CGI->new;						//创建新的CGI实例
    
    if ($cgi->upload('file')) {				//检查文件是否上传
        my $file = $cgi->param('file');		//获取文件描述符
    	
    	while (<$file>) {					//遍历文件的每一行
    		print "$_";						//打印当前行内容
    	}
    }
    

    这5行代码所做的是,用户上传文件到服务器,然后服务器返回文件内容。在此过程中,服务器并没有保存或者移动这个文件,仅仅是显示了其内容,看起来没有什么不安全的地方。但是事实上真的安全吗?当然不是。

    首先,【if ($cgi->upload('file')) {】这行代码中,我们期望upload()负责检查“file”参数值所代表的文件是否已上传,然而实际上upload()检查的是某一“file”参数值所代表的文件是否已上传(用户可构造多个file参数)。换句话说,upload()并不要求所有的file参数都是文件,它只要求其中一个file参数是文件即可。这意味着,我们可以构造2个file参数,一个上传文件,另一个赋一个变量值,这样也可以通过upload()的校验。

    然后,【my $file = $cgi->param('file');】这行代码中,我们期望param()返回上传文件的文件描述符,然而实际上,如果我们构造2个file参数,一个上传文件,另一个赋一个变量值。那么param()返回我们输入的所有file参数值的列表。但是$file不能包含两个值,所以在给$file赋值时,程序会取列表中的第一个值赋给$file。所以如果给第一个file参数赋变量值,第二个file参数赋文件描述符,则$file会被赋值为我们输入的变量值,而不是上传的文件描述符。这意味着,此时$file变成了一个常规字符串!

    接着,【while (<$file>) {】这行代码中,我们本来期望遍历文件的每一行,但由于此时$file是一个常规字符串,事实上,“<>”仅对文件起作用,对字符串不起作用。但是有一个特例,除非这个字符串是“ARGV”。当字符串是“ARGV”时,“<>”会遍历URL中?后面的每个值(比如POST /test.cgi?/etc/file1 /etc/file2),并把它们当做文件路径插入到一个open()调用中。这意味着,此时我们可以查看任何我们想看的文件内容,而不是仅仅查看我们上传的文件内容。

    最后,再说说open()函数。open()的本意是打开一个字符串所代表的文件,但是当在字符串后面加一个“|”的话,open()就会执行这个字符串(比如POST /test.cgi?ipconfig|),就像调用一个exec()一样。

    因此,我们可以使用如下2种方法获取flag。

    方法一:直接在URL后面输入路径打开密码文件。

     

    方法二:在URL后面调用cat命令打开密码文件。

    flag:no1vohsheCaiv3ieH4em1ahchisainge

    事实上,上面5行代码来自CGI.PM官方文档,它既没有调用exec()函数,也没有保存文件,仅仅是使用了print打印,谁能想到这几行代码可以被骇客利用形成这么大的漏洞呢?这并不是开发者的错,而是Perl语言本身的问题。Perl拥有默默用光列表,混淆数据类型,执行用户输入等等缺陷,并且至今没有被修复。所以,不要再使用Perl语言!至少不要再使用CGI环境。

    参考:

    https://www.youtube.com/watch?v=BYl3-c2JSL8(主要参考这个)
    https://www.blackhat.com/docs/asia-16/materials/asia-16-Rubin-The-Perl-Jam-2-The-Camel-Strikes-Back.pdf
    https://blog.csdn.net/baidu_35297930/article/details/99974886

  • 相关阅读:
    前端基础之CSS
    前端基础之HTML
    Http状态码解释
    Python操作MySQL
    MySQL忘记root密码的解决办法
    关闭MySQL数据库的几种方法
    prompt更改MySQL登陆后的提示符
    JQ例子:旋转木马
    JQ属性和css部分测试
    JQ选择器逐一测试
  • 原文地址:https://www.cnblogs.com/zhengna/p/12364167.html
Copyright © 2011-2022 走看看