Researchers at Duo Labs, the advanced research team at Duo Security, discovered that it is possible to bypass PayPal’s two-factor authentication (the Security Key mechanism, in PayPal nomenclature). The vulnerability lies primarily in the authentication flow for the PayPal API web service (api.paypal.com) — an API used by PayPal’s official mobile applications, as well as numerous third-party merchants and apps — but also partially in the official mobile apps themselves.
As of the date of this post (June 25), PayPal has put a workaround in place to limit the impact of the vulnerability, and is actively working on a permanent fix. In light of the vulnerability reporting timeline and the trivial discoverability of the vulnerability, we have elected to publicly disclose this issue, so that users can be informed to the risks to their PayPal account security.
Duo would also like to thank Dan Saltman from EverydayCarry for his assistance in the initial reporting of this issue.
An attacker only needs a victim’s PayPal username and password in order to access a two-factor protected account and send money. The protection offered by the two-factor Security Key mechanism can be bypassed and essentially nullified.
While PayPal’s mobile apps do not currently support 2FA-enabled accounts, it is possible to effectively trick the PayPal mobile applications into ignoring the 2FA flag on the account, subsequently allowing the an attacker to log in without requiring secondary authentication.
We developed a proof-of-concept exploit to leverage this lack of 2FA enforcement, interfacing with the PayPal API directly and effectively mimicking the PayPal mobile app as though it were accessing a non-2FA account. The exploit communicates with two separate PayPal API services — one to authenticate (only with primary credentials), and another to transfer money to a destination account.
Note that the standard browser-based PayPal web interface is not affected by the bypass. However, since an attacker can simply use the underlying API to gain full account access, this distinction is purely academic.
Below is a brief video that that discusses and demonstrates the PayPal two-factor bypass:
The vulnerability lies primarily in the authentication flow for PayPal’s API web services. In particular, api.paypal.com, a REST-ful API which uses OAuth for authentication/authorization, does not directly enforce two-factor authentication requirements server-side when authenticating a user.
As demonstrated in the video, the PayPal iOS application exhibited suspicious behavior by briefly showing the user’s account information and transaction history prior to forcefully logging them out. Based on this behavior, we decided to investigate what was happening communications-wise on the wire. Using Burp, we intercepted and analyzed HTTP/HTTPS traffic between the PayPal mobile apps and remote PayPal web services. In particular, we observed the authentication process, paying close attention to how the service responded to 2FA-enabled accounts versus non-2FA-enabled accounts.
The screenshot below shows a POST request to an OAuth endpoint on api.paypal.com. The POST body contains, among other things, primary credentials (username & password) and some identifying data about the device. This sort of request (to the OAuth endpoint) was consistent with developer documentation on PayPal’s site, so it didn’t stand out as anything unusual.
However, in the screenshot below, which shows the response to the above request, we see a JSON dictionary that was returned containing some additional PayPal service URIs, various tokens (primarily OAuth-related), and some 2FA-related attributes.
Note the red highlight around the “2fa_enabled” attribute. As it turned out, the value of this attribute being set to “true” caused the mobile application to return to the login screen and display an error message, indicating that 2FA was not currently supported:
Similar HTTP requests were generated by the PayPal Android application, and the same error message was displayed for 2FA-enabled accounts:
Using Burp’s match-and-replace feature, we were able to automatically modify the server response to rewrite the “2fa_enabled” value to “false”:
By simply adjusting this value, the mobile clients would then proceed as normal, as though the account had no two-factor authentication whatsoever. Although the underlying vulnerability is present on the server-side, this tweak amounted to client-side “enforcement” of 2FA.
Returning to the initial response right after authentication occurs, we observed an additional session identifier being returned in the JSON dictionary, as highlighted below.
As it turned out, “session_token” is used for authorization against mobileclient.paypal.com, an otherwise (publicly) undocumented SOAP-based API that provides additional account-related functionality, including but not limited to sending money.
We then stepped through the “send money” process in the mobile apps, again capturing traffic with Burp. Through this, we were able to observe the necessary requests/responses and SOAP envelopes (read: painful XML) that make up a PayPal fund transfer from their mobile applications. The funds transfer process turned out to be a four-step exchange, with each request requiring a value unique to the overall transaction.
As an example, the screenshot below shows the aforementioned session identifier being used in the first POST to mobileclient.paypal.com:
As a proof-of-concept, we built a Python script that ultimately mimicked the behavior of a PayPal mobile application and exploited this vulnerability. This script would take in a PayPal username and password, a dollar (USD) amount, and a recipient. The script would then:
- Authenticate to api.paypal.com
- Display some limited account information (including the “wallet,” or linked fund sources, such as bank accounts and debit/credit cards)
- Read the “session_token” value
- Use “session_token” to authenticate to mobileclient.paypal.com and proceed with the steps to initiate and complete sending funds to the target recipient
As shown in the demonstration video, this was done with a 2FA-enabled account, with zero 2FA challenge/enforcement from the server. The screenshot below shows our proof-of-concept script authenticating with a 2FA-enabled account and sending $1.00 USD to a recipient. (Additionally, a UUID is generated and placed in the note/memo of the transaction for correlation purposes).
The screenshot below shows the notification email sent to the recipient:
As of re-testing on June 23, PayPal has implemented a workaround for the vulnerability, with a permanent fix planned for July 28. Currently, 2FA-enabled accounts authenticating against api.paypal.com no longer receive the “session_token” key in the JSON response, effectively restricting access to mobileclient.paypal.com (non-2FA accounts still get the token).
However, wallet information was still being returned, meaning the 2FA-bypass was still partially valid, though an attacker is limited in their capability. The screenshot below shows the output of our PoC script when re-testing, highlighting the 2FA flag, and displaying wallet information (note the absence of the “session_token” key in the response):
Using official PayPal mobile apps, we also see more descriptive error information returned, reflecting the change in the authentication flow of PayPal’s API services, as shown below:
As of re-testing once again on June 24, PayPal implemented additional mitigations, completely restricting the user’s wallet information from being returned. The screenshot below shows the output of our PoC script when re-testing on June 24. The absence of the “access_token” key seems to restrict any subsequent operations on api.paypal.com, including accessing wallet data.
While two-factor authentication, when done right, provides great value for protecting users and businesses, design and implementation flaws such as this bypass can negate that value. Users may be lulled into a false sense of security, unaware that a security feature isn’t truly living up to its promise. With the sheer number of primary credentials being compromised and dumped onto the Internet, strengthening account security with a well-designed two-factor authentication solution is paramount.
We hope that PayPal’s planned fix will rectify this vulnerability and lead to full support of two-factor authentication in their official mobile applications and third-party merchant apps.
2014-03-28: Dan Saltman (EverydayCarry.com) discovers a two-factor bypass in the PayPal mobile application for iOS — toggling airplane mode after supplying only primary credentials (for two-factor enabled account) causes the application to remain logged in
2014-03-29: Dan reports the issue to PayPal via their Bug Bounty program. The case is assigned as EIBBP-27440.
2014-04-10: Dan requests a status update from PayPal; no response
2014-04-22: Dan contacts Duo Security for assistance in validating/reproducing the issue and leveraging any contacts at PayPal to make progress on the case.
2014-04-22: Duo successfully reproduces Dan’s iOS-specific findings.
2014-04-23: Duo reaches out to a contact at PayPal, citing Dan’s case number; inquiry is forwarded to the eBay/PayPal Bug Bounty team.
2014-04-23: Duo also reproduces the 2FA bypass in the PayPal mobile app for Android.
2014-04-25: Duo receives a response from the Bug Bounty team via eBay’s web-based Secured Email system, indicating that the case is still under investigation.
2014-04-25: Dan receives an automated e-mail from PayPal’s bug tracker showing the issue as “in progress”.
2014-04-28: Duo again reaches out to the Bug Bounty team, offering to share supporting data (proxy logs, mobile application logs, screen recordings, etc.), as well as information about the Android-centric bypass.
2014-04:28 The Bug Bounty team replies indicating that they are unable to provide case information to anyone other than the original reporter.
2014-05-15: Duo opens a new case through the eBay/PayPal bug bounty site. The submission cites the iOS-related case, provides an overview of the underlying/bigger issue, and includes screenshots of the proof-of-concept exploit. The case is assigned as EIBBP-28093.
2014-05-22: Duo contacts the Bug Bounty team requesting a status update; no response.
2014-05-29: Duo once again contacts the Bug Bounty team requesting a status update.
2014-05-29: The Bug Bounty team replies indicating that they had attempted to request more information on May 22, as the screenshots were truncated during upload. (For unknown reasons, this message was not received by Duo, perhaps due to an error in the eBay Secured Email system.)
2014-05-29: Duo re-sends the screenshots.
2014-05-29: The Bug Bounty replies requesting a copy of the proof-of-concept exploit script.
2014-05-29: Duo sends the proof-of-concept script to the Bug Bounty team.
2014-06-03: Duo sends another status inquiry to the bug bounty team.
2014-06-03: The Bug Bounty team replies with additional case information, and indicates the submission is eligible for a bounty.
2014-06-09: Duo inquires to the Bug Bounty team about a fix timeline.
2014-06-09: Duo notifies contact at PayPal, setting a public disclosure date of June 25.
2014-06-10: PayPal contact replies to Duo and includes a Bug Bounty program manager on the same email thread.
2014-06-10: Duo acknowledges the reply, offers to answer any questions or concerns.
2014-06-10: Bug Bounty program manager replies, indicating that development teams are still reviewing the bugs that have been submitted to determine fix windows.
2014-06-16: An initial bounty payment is sent to Duo via PayPal.
2014-06-16: Duo replies to the Bug Bounty program manager acknowledging the initial payment and reminding them of the intent to disclose on June 25.
2014-06-16: The Bug Bounty program manager replies indicating that development teams are working on a fix but are unable to commit to any particular timeline.
2014-06-18: Duo replies to the Bug Bounty program manager re-stating the intent to disclose on June 25. Duo also re-tests the issue, noting that PayPal has implemented a partial workaround which limits the attack.
2014-06-19: PayPal contact (including Bug Bounty program manager) replies, noting a targeted fix date of July 28, along with a request for Duo to delay public disclosure.
2014-06-20: Duo replies, again re-stating the intent to disclose on June 25.
2014-06-24: PayPal notifies Duo that additional mitigations have been put in place which no longer allow for retrieval of user’s wallet data, further limiting the attack.
2014-06-24: Duo acknowledges the update/notification from PayPal and re-tests the issue. Duo notes that while the core bypass issue remains, interaction with the API is no longer possible, including no longer being able to access wallet data.
2014-06-25: Vulnerability write-up is shared publicly and posted to the Duo Security blog.