Attacking Secondary
Contexts in Web
Applications
Sam Curry
whoami
● Sam Curry
(@samwcyo)
● Full time bug bounty hunter
(3 years on-and-off)
● Passionate about application
security/research
(run blog @ samcurry.net)
How I previously thought all HTTP servers worked...
● Application files are stored/accessed in webserver folder
○ /var/www/html/
○ /usr/share/nginx/html/
○ … etc …
● GET /index.html
○ Tries to load in /webserver/index.html
● GET /folder/index.html
○ Tries to load in /webserver/folder/index.html
● Very straightforward and simple
Different ways web applications do routing
● Not actually dealing with stored files, rather using defined routes
Different ways web applications do routing
● Sent across middleware and proxies, sometimes through load balancers...
Different ways web applications do routing
● Fetching content from APIs
○ Sending a 2nd HTTP request
○ Usually a different host
○ Common lack of input validation
● Sometimes carries auth info to API
○ Underlying authentication models
■ Sometimes not present…
Methods for identifying application routing
● Directory traversal
○ Does “/api/../” return something different than “/”?
● Fuzzing using control characters
○ %23 (#), %3f (?), %26 (&), %2e (.), %2f (/), %40 (@)
○ Double/triple URL encoding
● Does the behavior suddenly change for certain directories?
○ Why does “/images/” return different headers than “/”?
● Are there any nice bits of information we can catch?
○ “internal.company.com:8080 returned the following: ‘500 internal server error’”
Identifying application routing - Examples
● We can identify /favicon.ico* is being served through CloudFront
● What if this was being served through an S3 bucket?
○ GET /favicon.ico/..%2f..%2fattackersbucket%2fxss.html
○ (Proxied as https://s3.amazonaws.com/yahoo-bucket/favicon.ico/../../attackersbucket/xss.html)
Identifying application routing - Examples
● Requesting the webroot
behaves totally normally
● Browsing to /api/v1/ reveals
different behavior
○ Different headers, content-type,
etc.
● We can confirm the routing is
separate via traversing
backwards to “/” on the API
server via “/../../../”
Common issues with secondary contexts
● Data is being served across extra layers
○ Introduces translation issues like HTTP request smuggling
○ CRLF injection in weird places
● Developers do not expect users to be able to control parameters/paths
○ Functionality you would normally see in a development environment is accessible
(?debug=1, /server-status)
● Information disclosure
○ Internal HTTP headers, access token
● SSRF and XSS via manipulating response content
○ Finding an open redirect in 2nd context = server issuing/potentially rendering arbitrary request
Identifying application routing - Examples
● Passing in “%23” turns into “#”
and makes the underlying
request fail as the parameters are
dropped
● What control do
we have over the
second request?
● How could this be
exploited by an
attacker?
Identifying application routing - Examples
● Traversing backwards allows us to overwrite the API paths
● Indexing for user ID is based on the session cookie
Identifying application routing - Examples
● We can traverse the internal API, overwrite the user ID, then read a victim’s file
● All other API calls are also accessible
GET /files/..%2f..%2f + victim ID + %2f + victim filename
Common issues attacking secondary contexts
● APIs will oftentimes not normalize request URLs
○ Impossible to traverse API calls
Common issues attacking secondary contexts
● Underlying authentication makes access control issues impossible
○ Even if an API is internal, there isn’t any benefit besides widened attack surface
Identifying application routing - Examples
● HTTP request loads the specified invoice PDF
● IDOR doesn’t work, returns 404 (somewhat interesting)
● Are they doing anything weird/exploitable here?
Identifying application routing - Examples
● GET /my-services/invoices/..%2finvoices%2fINV08179455/pdf
○ This works (200 with PDF content)
● GET /my-services/invoices/..%2f..%2fmy-services%2finvoices%2fINV08179455/pdf
○ This doesn’t (404 without PDF content)
● This doesn’t really prove anything, but it’s interesting
○ If it were traversing on the same box/normally, it’d likely load both
○ This is probably worth at least investigating a little bit
Identifying application routing - Examples
● There’s a possibility a directory
before “/invoices/” is indexing our
uploads
(/:userid/invoices/:invoiceid)
● If we can guess this directory, we
can potentially view other users
invoices
● Lots of things to guess here...
Identifying application routing - Examples
● Error message on another part of
● Intruder (0-1000000) not working the app discloses the following…
{"error":"Id
[email protected]#vj does
● Email not working not have permission to modify the domain
… but ...
● Username not working example.com."}
● Moment of truth...
Identifying application routing - Examples
● Attacker can read anyones PDF if they know their…
○ Email address
○ Invoice number
● An alright bug… I guess....
● Is this behavior anywhere else on the app?
Identifying application routing - Examples
● Definitely a more interesting part of the website
● How is payment information fetched?
Identifying application routing - Examples
● Maybe this is stored the same way, but if so…
○ What is the directory name?
○ How can we retrieve that unique ID?
Identifying application routing - Examples
● Maybe this is stored the same way, but if so…
○ What is the directory name? (/paymentmethods/)
○ How can we retrieve that unique ID?
Identifying application routing - Examples
● GET /subscriptions/:id
+
Same trick from before
=
Traversing to view
payment method IDs
https://www.luminate.com/subscriptions/..%2f..%2f + email + %2f + id
● Maybe this is stored the same way, but if so…
○ What is the directory name? (/paymentmethods/)
○ How can we retrieve that unique ID? (trick with /subscriptions/)
Identifying application routing - Examples
GET /my-services/edit-payment-method?uid=../../
[email protected]%23vj/paymentmethods/2c92a00871083a4600fa287ce52fe
Identifying application routing - Examples
● Escalated severity from reading users invoices to reading payment information
● The only piece of information we need is the victim’s email address
○ The subscription ID can be brute forced
○ We obtain the payment ID from the subscription ID traversal
Exploring all possibilities
● Although directory traversal is useful for these types of bugs,
it isn’t necessary for various attacks
● In some cases, API calls behave similarly to a SQL query evaluating to
true/false
● Impact of course varies per case, but there are lots of interesting possibilities
Case Study - Authy 2FA bypass
● Authy - 2FA service, installable library
● User -> [Client -> Authy]
Case Study - Authy 2FA bypass
● When reading the response from Authy, the server only checked for…
○ JSON {“success”:true}
○ HTTP 200 OK
● How is the users token sent to Authy?
this._request("get", "/protected/json/verify/" + token + "/" + id, {}, callback, qs);
● GET /protected/json returns both 200 OK and JSON {“success”:true}
○ Is it really that simple?
Case Study - Authy 2FA bypass
Universal 2FA bypass for huge portion of Authy libraries
(credit: Egor Homakov, @homakov)
Review
● Lots of unique opportunities in attacking secondary contexts
○ Requests often sent internally
○ Often less restrictive environments
○ Authorization sometimes seemingly arbitrary (200 v.s. 403 when you control route)
● Very complicated problem for developers
○ Requests sent between servers with different behaviors
○ Hard to isolate internal APIs where user data isn’t dangerous
○ Sanitizing for paths is relatively difficult 2-3 proxies deep
● Lots of new research relative to similar approaches
○ Using “Max-Forwards” header to figure out more information about your requests
(https://www.agarri.fr/blog/archives/2011/11/12/traceroute-like_http_scanner/index.html)
Thank you Kernelcon!
● Questions? Maybe answers?