Natas30 Writeup(sql注入)

Natas30:

本关是一个登录页面,查看源码,可以发现关键代码。

if ('POST' eq request_method && param('username') && param('password')){
    my $dbh = DBI->connect( "DBI:mysql:natas30","natas30", "<censored>", {'RaiseError' => 1});
    my $query="Select * FROM users where username =".$dbh->quote(param('username')) . " and password =".$dbh->quote(param('password')); 

    my $sth = $dbh->prepare($query);
    $sth->execute();
    my $ver = $sth->fetch();
    if ($ver){
        print "win!<br>";
        print "here is your result:<br>";
        print @$ver;
    }
    else{
        print "fail :(";
    }
    $sth->finish();
    $dbh->disconnect();
}

问题出在$dbh->quote(param('password'))这里。

在Perl中,可以使用param('name')方法获取post表单中name参数的值,但是这个方法有一个特点,那就是

当我们输入name=foo时,param('name')方法返回的是name的值foo;
当我们输入name=foo&name=bar时,param('name')方法返回的是name的值列表["foo","bar"]。

在Perl中,quote()方法的传参类型可以为列表,如果将列表传递给该方法,则quote()会将其解释为单独的参数。比如

@list = ("a", "b")
quote(@list)

相当于

quote("a", "b")

Perl的quote($string)方法被用来“转义”包含在string中的任何特殊字符并增加所需的外部的引号。这里使用quote方法的本意是将用户的输入放在引号中以防止sql注入。但是当quote()可以接收两个参数时,它的用法变为:第一个参数表示将要被quote的数据,第二个参数表示一个SQL数据类型,决定如何quote。如果第二个参数是非字符串类型(如NUMERIC),则quote将传递其第一个参数,而不带任何引号。这就构成了SQL注入的机会。

所以,如果调用quote(param('password')方法,我们可以通过抓包并给password赋两个值的方法来给quote()传入两个参数值。其中第二个参数为1个数字(比如2),使第一个参数值不带任何引号直接注入到SQL中,从而得到flag。

构造POST:username=natas31&password='xxx' or 1=1 &password=2

flag:hay7aecuungiuKaezuathuk9biin0pu1

参考:

https://security.stackexchange.com/questions/175703/is-this-perl-database-connection-vulnerable-to-sql-injection/175872#175872
https://stackoverflow.com/questions/40273267/is-perl-function-dbh-quote-still-secure/40275686#40275686
https://blog.csdn.net/baidu_35297930/article/details/99974886?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

猜你喜欢

转载自www.cnblogs.com/zhengna/p/12363119.html