In this post we’re going to take a look at Level 11 of the Natas wargame, hosted by Over The Wire.
What’s Going On?
Upon logging in, we see a message that states that cookies are encrypted with XOR encryption. Additionally, there is a text input, submit button, and a link to the PHP source code of the page. Looking at the prompt on the page, it sounds like if we input a valid RGB color code, the background of the page will change. We can test this with a different code, such as #000000 and see that it works. Now, let’s go a head at look at the PHP source code by following the link.
Looking through the code, we see quite a bit of PHP and some HTML. Additionally, in the HTML section, we see a snippet of PHP which will display the password to the next level if the “showpassword” key of an array called “data” is set to “yes”. Thus, this will be our final target, to set the showpassword key of the data array to yes. So, let’s track back through the PHP code to see where this array comes from.
The last line of the PHP code section is saveData($data); so let’s look at the saveData function, which is defined a few lines above. The saveData function seems to set a cookie called “data” with the value which is the result of calling json_encode(), xor_encrypt(), and base64_encode() in order on the argument passed to saveData. Between these two sections of code, we also see that $data is set to the return value of loadData($defaultData); At the top of the code section, we can see that $defaultData is an array with two keys set, “showpassword”=>”no” and “bgcolor”=>”#ffffff”. Thus, if we can craft a fake array with “showpassword”=>”yes”, encrypt it in the same way as was done in the saveData function, and put that value into our cookie, we should be able to get the password for the next level! However, let’s take a closer look at those encoding functions.
A couple of the functions are basic two way functions, json_encode() and base64_encode() both have opposite direction functions within the normal PHP API. However, xor_encrypt() deserves a little more attention. XOR encryption is a fast bit based encryption scheme which requires a SECRET KEY. Plain text is XOR’d with the key, and a cipher text is output. It also has a reverse operation which is the exact same operation, cipher text XOR’d with the key gives the plain text. This is an attempt to make it so we cannot forge a cookie value, since we cannot encode with the same key by which the cookie will be decoded with, since we don’t know the key. However, by XOR’s nature, it is vulnerable to a known plain text attack. This is because the plain text XOR’d with the cipher text results in the key. So, let’s see how we can take advantage of XOR’s weakness to recover the key, and thus forge our own cookie!
Exploit
The first thing we need to do, to be able to determine the key, is determine the plain and cipher text which were used and produced during the run. We know the plain text was the result of running json_encode(array(“showpassword”=>”no”, “bgcolor”=”#ffffff”)), and that the result, the cipher text, was run through base64_encode and saved to a cookie. So, let’s look up our cookie called data set by the natas11 site and find it’s value. We can then put that value through base64_decode() to get what was the cipher text of the original XOR’d data. Once we have recovered these two, we can go a head and use one as the key and one as the plaintext, and run them through the xor_encrypt function to get the original key that was used. Let’s look at a re-arranged PHP file based off the code of this level, which will recover the key:
<?
$cryptData = base64_decode(“ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D”); //default cookie value
function xor_encrypt($in) {
$key = json_encode(array( “showpassword”=>”no”, “bgcolor”=>”#ffffff”));
$text = $in;
$outText = ”;// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}return $outText;
}print xor_encrypt($cryptData);
?>
The above code does just what was mentioned. It takes the base64_decode() results of the data cookie’s value, and passes it as plain text to the xor_encrypt() function. The xor_encrypt() function uses the json_encode() results on the default array value. After xor_encrypt is run, the results are printed to the screen as shown:
[somebox]$ php recoverKey.php
qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8JqL
We can see it’s a repeated 4 character key. Since XOR encryption uses modulus to wrap around the key, we can shorten it to just the original 4 characters, qw8J, or any number of full repetitions. Notice the random “L” at the end, let’s replace it with what should be there, a “w”.
Next, we need a program which will create a fake, crafted array with the showpassword key set to yes, and fully encode it with json, XOR, and base64, and output it for use as our cookie value. Let’s rip off more code from this level and create a PHP program to do that, such as the following:
[somebox]$ cat forgeCookie.php
<?$data = array( “showpassword”=>”yes”, “bgcolor”=>”#ffffff”);
function xor_encrypt($in) {
$key = “qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw”;
$text = $in;
$outText = ”;// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}return $outText;
}print base64_encode(xor_encrypt(json_encode($data)));
?>
When we go a head and run the above program, we get our desired faked cookie value with showpassword set to yes:
[somebox]$ php forgeCookie.php
ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
Now if we load up the webpage in our browser, such as Chrome, and use something like the Edit This Cookie add-on to change the cookie value, we see the fruits of our labor. The password for the next level is displayed on the screen!
So What?
In this level, a key based encryption algorithm was used as a verification of valid cookie data, before using the cookie data. While a good idea in theory, the way it was executed was flawed since the encryption used has a very simple known plain text attack, and in this instance, we were able to find both the plain and cipher text. Other key based encryption schemes would be better in this situation, such as AES.
2 Responses to Natas Level 11 – XOR “Encryption”