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, showpassword string 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 called data, it tries to decode it as a JSON object. The value has first to be decoded in base 64, then XORed by calling xor_encrypt. If the JSON is a valid array and contains both shownopassword / 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.

  1. Cyphertext needs to be decoded:
      base64_decode($_COOKIE["data"]))
    
  2. 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  

In your browser’s javascript console, edit the data cookie by writing:

document.cookie="data=ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK"

Refresh the page and you got the password.

9

Password is: EDXp0pS26wLKHZy1rDBPUZk0RKfLGIR3.