Natas Level 11 → Level 12

When we login to Natas11, we are greeted with a message “Cookies are protected with XOR encryption”. So we should look at the source code and the cookie value. From burp suite, we can see the Set-Cookie: has a cookie calls data with the following value:

ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D

Next, looking at the source code, we see some php code as follow:

<?
$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);
?>

Let’s look at each function closely.

  • we can see that $defaultdata is an array of two values, “showpassword”=>”no” and “bgcolor”=>”#ffffff”.
  • The function xor_encrypt takes an input $in ($text) and xor (^) with the $key and store the value in $outText. If the $key is shorter than the $text, it will reuse the $key value in a loop. see the line. The $outText is return.
$outText .= $text[$i] ^ $key[$i % strlen($key)];
  • The function loadData takes an input $def ($mydata) and check if “data” array_key_exists in $_COOKIE.
    • If “data” exist, then use the cookie data to decode into $tempdata by the following steps
      • base64_decode
      • xor_encrypt
      • json_decode
    • Verify if the following is true for $tempdata
      • is_array
      • array_key_exists for “showpassword”
      • array_key_exists for “bgcolor”
    • If the above are all true and the bgcolor value is valid, then update $mydata using $tempdata. return $mydata.
  • saveData function takes an input $d and encode it by the following steps
    • json_encode
    • xor_encrypt
    • base64_encode
    • setcookie as “data”
  • The main code will do the following
    • set $data as $defaultdata using loadData
    • saveData($data)
    • check if $data has “showpassword” set to “yes”, if so , show the password for the next level.

The goal is to have the cookie data store an encrypted value of “showpassword”=>”yes”. To do that, we need to know the $key, which is unknown at this point. However, we can get that from the $defaultdata and cookie value. Since xor have the following property

x ^ x = 0
x ^ 0 = x

If we denote m as message ($defaultdata), k as $key and c as the encrypted cookie data. We know m and c but not k, but we can find it using the following:

m ^ k = c
m ^ k ^ m = c ^ m
k = c ^ m

Therefore, if we xor c (“data” cookie value) and m ($defaultdata), we can find out the key and use it to encrypt a new message for the cookie data. Notice the encryption is surrounded by base64 encoding and json encoding.

<?
$cookie = base64_decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw%3D');
$default = json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));
$modify = json_encode(array( "showpassword"=>"yes", "bgcolor"=>"#ffffff"));

function xor_encrypt($in1, $in2) {
 $text = $in1;
 $key = $in2;
 $outText = '';

 // Iterate through each character
 for($i=0;$i<strlen($text);$i++) {
 $outText .= $text[$i] ^ $key[$i % strlen($key)];
 } 
 return $outText;
} 
echo xor_encrypt($cookie, $default);
echo "\r\n";
$realkey = "qw8J";
echo base64_encode(xor_encrypt($modify, $realkey));
echo "\r\n";
?>

Therefore, we must do the same. Reuse the xor_encrypt function by changing $key and $text as json_encode($defaultdata) and base64_decode(cookie data value), we can see the real key repeat as “qw8J”. We change the value from no to yes in our default array and xor encrypt it with “qw8J” to produce a string that we will base64_encode to get our final cookie data that we will send it back to trick the host.

qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8JqL
ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK

Once we do that, we get the next password.

EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3
Advertisements