: level 26 → level 27

http://natas27.natas.labs.overthewire.org

Username과 Password를 받는 폼이 있다.

Username과 Password를 올바르게 입력하면 DB table의 내용을 출력한다.

Password가 틀리면 Wrong password for user: (username)이 출력된다.

Username이 존재하지 않으면 입력한 값을 바탕으로 새로운 계정을 생성한다.

 

<html>
<head>
<!-- This stuff in the header has nothing to do with the level -->
<link rel="stylesheet" type="text/css" href="http://natas.labs.overthewire.org/css/level.css">
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/jquery-ui.css" />
<link rel="stylesheet" href="http://natas.labs.overthewire.org/css/wechall.css" />
<script src="http://natas.labs.overthewire.org/js/jquery-1.9.1.js"></script>
<script src="http://natas.labs.overthewire.org/js/jquery-ui.js"></script>
<script src=http://natas.labs.overthewire.org/js/wechall-data.js></script><script src="http://natas.labs.overthewire.org/js/wechall.js"></script>
<script>var wechallinfo = { "level": "natas27", "pass": "<censored>" };</script></head>
<body>
<h1>natas27</h1>
<div id="content">
<?

// morla / 10111
// database gets cleared every 5 min 


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


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);
} else {
?>

<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password" type="password"><br>
<input type="submit" value="login" />
</form>
<? } ?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>

 

소스코드를 보면 위쪽에 테이블의 정보가 공개되어 있다.

users table에 2개의 열이 존재하는데 자료형이 모두 varchar이다.

MySQL에서 데이터타입이 varchar인 열은 지정해둔 문자열의 크기를 초과하는 후행 공백은 삭제하고 삽입한다는 특징이 있다.

위 소스코드에서 varchar의 크기는 64로 지정했으므로 natas28뒤에 공백을 추가하여 문자열의 크기가 64를 초과하게 만들면 테이블에 삽입될 때 후행 공백은 모두 삭제하고 natas28만 삽입할 수 있다.

 

 

 

테이블에 데이터를 삽입하는 방법은 존재하지 않은 username을 입력하는 것이다.

존재하지 않는 username을 입력하면 validUser함수에 의해서 입력한 데이터가 테이블에 생성된다.

따라서 후행 공백을 포함한 natas28과 pw를 함께 입력하면 이때는 테이블에 삽입되기 전이므로 validUser함수에 의해서 입력한 데이터가 테이블에 추가되고, 후행 공백은 모두 삭제될 것이다.

 

natas28 생성

 

 

 

 

 

이제 username에 natas28과 아까 작성한 password를 함께 입력하면 checkCredentials함수에 의해서 해당 조건문이 참이 되고, 그 아래 dumpData함수가 실행되면서 제일 위쪽에 위치한 natas28의 data를 출력하게 된다.

 

 

natas28 password: JWwR438wkgTsNKBbcJoowyysdM82YjeF

 

 

 

 

'Study > Web Hacking' 카테고리의 다른 글

[Webhacking.kr] old-05  (0) 2021.09.11
[Webhacking.kr] old-07  (0) 2021.09.11
[LOS] nightmare  (0) 2021.08.24
[natas] Level 25 -> Level 26  (0) 2021.08.22
[LOS] zombie assassin  (0) 2021.08.19
복사했습니다!