Virtual Patching Session Fixation


    On a recent engagement we gained unrestricted administrative access to a certain proprietary web application by exploiting a Session Fixation flaw. According to the WASC Threat Classification v2, Session Fixation is an attack technique that forces a user's session ID to an explicit value. In other words, by feeding the victim a session token under the attacker's control, the attacker can bypass the authentication phase and gain unauthorized account access as the victim. There are a number of techniques that can be used to feed the token to the victim. The most common is by exploiting a XSS or header injection vulnerability.

    Due to the fact that this was a proprietary application, the client was unable to easily resolve the issue. Today, we will discuss two methods to virtually patch this flaw using ModSecurity. The first approach removes the session token submitted within the authentication request. On some frameworks, the application will automatically assign a new session token if none is submitted when succesfully logging in to the application. This approach uses inter-module communication between ModSecurity and ModHeaders, as shown below.

    # Set the enviroment variable REMOVE_COOKIE if the request is a 
    # login request (e.g. contains the passwd POST parameter) to force
    # the back-end app to issue a new session token
    
    SecRule REQUEST_URI "/login.php" "phase:2,chain, \
      log,msg:'Removing Cookie'"
      SecRule REQUEST_METHOD "^post$" t:none,t:lowercase,chain
        SecRule &ARGS:passwd "@eq 1" setenv:REMOVE_COOKIE
    
    # Have ModHeaders remove the Cookie header if the env variable
    # REMOVE_COOKIE is set
    RequestHeader unset Cookie env=REMOVE_COOKIE
    

    While the above approach is pretty straightforward, it does not work in all situations. The next approach can be used if the application does not set a new session token when an authentication request is submitted without a session token. This method uses the session collection to tie a new token to the existing application-generated session token. There are two parts to this solution, the ModSecurity rules and the Lua script. First, let's look at the ModSec rules.

    # Create the session collection
    SecRule REQUEST_COOKIES:/^ASP.NET/ ^(.+)$ \
        "phase:2,capture,log,pass,\
        setsid:%{TX.0},\
        setvar:SESSION.TIMEOUT=172800,msg:'captured sessid %{TX.0}'"
    
    # If this is a login request, create an additional session token
    # tie it to the SESSION and add it to the TOKEN enviroment variable
    SecRule &ARGS:passwd "@eq 1" "phase:2,chain,log,allow, \
      exec:/opt/modsecurity/etc/customrules/CreateSessionToken.lua, \
      setenv:TOKEN=%{TX.token},setenv:AUTHENTICATED \
      setvar:SESSION.token=%{TX.token}, \
      msg:'Setting token to %{TX.token}'"
      SecRule REQUEST_METHOD POST
    
    # Have ModHeaders set our new session token if the AUTHENTICATED enviroment 
    # variable exists (set in the previous rule)
    Header add Set-Cookie "SessionID=%{TOKEN}e; path=/; HttpOnly; Secure" \
    env=AUTHENTICATED
    
    # Ensure that the request only has one SessionID cookie to prevent cookie
    # stuffing attacks
    SecRule &REQUEST_COOKIES:SessionID "!@eq 1" "phase:4,chain,deny,log,auditlog, \
      msg:'Missing or incorrect number of SessionID cookies'"
      SecRule RESPONSE_BODY Logout
      
    # Enforce all authenticated requests (e.g. has the string "Logout" in the 
    # response body) to have the proper session token
    SecRule RESPONSE_BODY Logout "phase:4,chain,deny,log,auditlog, \
      msg:'SessionID does not match the real Session token'"
      SecRule REQUEST_COOKIES:SessionID "!@streq %{SESSION.token}"
    

    It is difficult to create a "random" token within the ModSecurity rules language, thus the contents of CreateSessionToken.lua is shown below. Although this approach is slightly more complication, it allows us to patch Session Fixation regardless of the functionality in the backend application.

    #!/usr/bin/lua
    
    function main()
    
      -- Create random token value
      local ip = m.getvar("REMOTE_ADDR")
      local md5 = require "md5"
    
      math.randomseed( os.time() )
      randomtoken = md5.sumhexa(ip .. math.random())
      m.log(3, "RandomToken: " .. randomtoken);
      m.setvar("TX.token", randomtoken);
      return 1
    end

Post new comment

The content of this field is kept private and will not be shown publicly.

Most Popular List

06/05/2011 | Written By Gordon Maddern | 62,427 Hits
About a month ago I was chatting on skype to a colleague about a payload for...
15/10/2011 | Written By Ty Miller | 17,649 Hits
Lets say that at some point you decided to adhere to security best practices...
28/06/2011 | Written By Sandeep Nain | 15,477 Hits
Coming from a family of civil engineers, I always knew that it is a rigorous...
24/05/2011 | Written By Gordon Maddern | 8,511 Hits
Skype has patched and released the fix for the Skype bug we found so we can d...

Most Recent Posts List

19/05/2013 | Written By Josh Zlatin | 3,236 Hits
Often when implementing customised ModSecurity solutions we need to...
07/05/2013 | Written By Richard Brown | 364 Hits
The term ‘ethical hacker’ is often misrepresented as the keywords...
05/04/2013 | Written By Gordon Maddern | 489 Hits
I recently had to go in to bat for a client who was told by their PCI auditor...
04/03/2013 | Written By Ty Miller | 2,324 Hits
  If you are anything like me, when you hear "Hacking in the Year 2...