Executing CSRF With Phone Validation

3 years ago 186
BOOK THIS SPACE FOR AD
ARTICLE AD

How to Programmatically Harvest the OTP

Greg Gibson

When I submit a vulnerability on a Bug Bounty program, I typically seek to build an exploit that automates as much of the Proof of Concept as possible to:

Ensure it’s 100% clear the exploit can do what I’m claiming.Simplify reproduction for both the triage team and the company — if the reproduction steps require the team to simply navigate to a URL you supply, you can eliminate any confusion.Have fun! Building things is a great way to learn new tech.

I recently identified a Cross Origin Resource Sharing (CORS) vulnerability on an API that allowed a user to add a phone number to their account. In what is a fairly common flow, the user first would submit their phone number, the application would text a six digit One Time Password (OTP) to that phone number, and the user would then enter the OTP into the website to prove it was in fact their legitimate phone number.

This flow can provide both validation — by ensuring users enter a phone number they control, and security — as it makes it difficult for an attacker to take advantage of a Cross Site Request Forgery (CSRF) vulnerability as you must make two distinct API calls with a dynamic value triggered by the first (and importantly delivered out of band) to be submitted in the second.

I spent a few hours attempting to use AWS Pinpoint and Twilio long codes (that is a normal 10 digit US phone number) to receive the OTP to no avail and my assumption at this point is there are certain checks in place that limit this B2B type messaging, instead only engaging with actual mobile numbers.

Enter Google Voice

I’ve used Google Voice for a few years and my de facto standard is to forward all incoming SMS to my personal phone number — an added convenience that allows me to text normally through the iOS messaging app versus switching into the Google Voice app.

The target application also had no issues sending the OTP to my Google Voice number so I began experimenting with using Google Voice as an intermediary between the application and Twilio. Google needed to send a OTP to my Twilio number to validate it much in the same way as the application wanted to validate my Google number. Using the Twilio API I was able to harvest the code and complete the forwarding. You can read more about setting up SMS forwarding directly from Google Support: https://support.google.com/voice/answer/9182115.

Architecture

The key to making this exploit realistic and seamless is programmatically retrieving the OTP — and doing it quickly which required building both the client side “malicious” JavaScript to execute the API calls as well as setting up a third attacker controlled API that could retrieve the OTP.

The basic architecture is shown above with the following flow:

Victim visits a webpage running the malicious script.JavaScript sends an HTTPS POST request with JSON body including the attacker’s phone number to the target application. This triggers a preflight OPTIONS request, but is ultimately allowed via the Access-Control-Allow-Origin headers echoing the request origin.The target application sends a OTP to the attacker’s Google Voice number, which then forwards that SMS to Twilio.JavaScript sends a HTTPS GET request to the attacker’s API, which triggers Lambda to harvest the code from Twilio and return it in the HTTPS response.JavaScript sends the final HTTPS POST request to the target application with the attacker’s phone number and OTP to validate.

Client Side Code

I’m by no means a JavaScript developer — rather I can hack things together well enough to make my exploits work. That said, a few keys to making this work were forcing JavaScript to block and wait to ensure the three API calls occurred in order, and only when ready (versus the asynchronous free for all that typical JS can be).

**Note: Both the Client and Server Side code snippets contain the basic working code I used. However, I’ve removed and changed some things for simplicity and readability. If you want to duplicate this effort, use these as a baseline.**

I setup each API call as a standalone function which would call the next function only when the request had completed successfully — ie the first API call must complete before the second API call is triggered. Additionally, in the poll_twilio function, I added recursion to reattempt the call to the attacker API until the OTP code was successfully returned — this would allow for the OTP to work it’s way from the target application to Twilio and prevent the exploit from breaking if there were any delays along the way.

Server Side Code

Within the Lambda, the code only needs to do a few things — poll Twilio for any messages, parse them to see if the OTP code has been received, and return an appropriate response (either 200 or 404) depending on the result. Twilio DOES provide a Python SDK but for such a simple integration I chose the REST API.

A few design decisions I made were to delete EVERY message EVERY time. You can’t assume only OTP messages will be delivered to Twilio if you have forwarding configured on an existing number. I also wanted to ensure subsequent exploit instances were not attempting to either sort through a huge message queue or finding old, formerly valid OTP codes and returning them as valid.

However, at scale this wouldn’t work. If multiple victims were being exploited simultaneously you’d need a better way to find the right OTP code which is outside of the scope of this proof of concept.

Final Thoughts

Although not mentioned, you will need to familiarize yourself with AWS API Gateway and also setup a trial account with Twilio to build this exploit yourself. My client side code was simply hosted in S3 as an effectively blank webpage containing only the script.

Although this entire POC may not have been necessary to demonstrate the exploit, both the Triage team and the Program commented on the quality of the work. Additionally,other vulnerabilities that are currently mitigated with the use of OTP and could be reliably exploited with this automation.

I’m not very active on Social Media, but you can find me on LinkedIn, Bugcrowd, or hanging out in various security Slack or Discord servers!

Read Entire Article