Natas 11
That’s a lot of code! Let’s see what it does. Best way is to follow the code execution, so functions will be ignored till they’re actually being called.
<?
$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);
?>
What does this code do?
-
$defaultdata: Array containing two values,
showpasswordstring and
bgcolor` contaning the div background value. -
Line 37:
$data is loaded via the
loadData function on line 18, a temporary array$mydata
is used to store the default values (“no”, “#ffffff”). If the cookie sent in the HTTP request contains a field calleddata
, it tries to decode it as a JSON object. The value has first to be decoded in base 64, then XORed by callingxor_encrypt
. If the JSON is a valid array and contains bothshownopassword
/bgcolor
fields, it’s then written to$mydata
, thus overriding the default values. -
Line 39: If
bgcolor
key is passed in the request and matches the regex (for HEX colors string), it’s then saved in the$data
array. -
Line 45:
saveData
stores the cookie with the updated values.
<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>";
}
?>
<form>
Background color: <input name=bgcolor value="<?=$data['bgcolor']?>">
<input type=submit value="Set color">
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
Note: HTML is then generated and data is loaded from the array $defaultdata
.
One important thing to know about XOR encoding is that it’s vulnerable to known-plaintext attack.
plaintext XOR key = cyphertext
plaintext XOR cyphertext = key
1. Preprocessing data
What we want is to XOR our plain text ($_data) _with the cyphertext ($_COOKIE["data"])
, but we’ll need to undo any preprocessing before XORing them.
- Cyphertext needs to be decoded:
base64_decode($_COOKIE["data"]))
- Default data needs to be json encoded:
json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));
2. Getting the key
Normally, a long repetitive key is used for XORing, we want to figure out the key, so we can re-encode the data and submit the manipulated cookie, setting the showpassword
parameter to “yes”.
We’ll be reusing/refactoring some PHP code:
<?php
$cookie = "ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=";
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;
}
echo xor_encrypt(base64_decode($cookie));
?>
Next, we’ll execute this code.
$ php -f p.php
qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq
We got our key!
3. Encoding the new data
For this step I had to append a couple more strings of qw8J
, using the key provided in the previous snipped will not generate the correct string.
<?php
$data = array( "showpassword"=>"yes", "bgcolor"=>"#ffffff");
function xor_encrypt($in) {
$key = 'qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq';
$text = $in;
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
echo base64_encode(xor_encrypt(json_encode($data)));
?>
$ php -f p.php
ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
4. Submitting the new cookie and getting the password
In your browser’s javascript console, edit the data cookie by writing:
document.cookie="data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK"
Refresh the page and you got the password.
Password is: EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3.