This article is about how I found a vulnerability on Apple forgot password endpoint that allowed me to takeover an iCloud account. The vulnerability is completely patched by Apple security team and it no longer works. Apple Security Team rewarded me $18,000 USD as a part of their bounty program but I refused to receive it. Please read the article to know why I refused the bounty.
Update 27 March 2022
There wasn’t any response from them for months so I created a new ticket on 21st July 2021 stating that the HSMs would be still vulnerable to insider threats. After back and forth emails, Apple security team setup a call to discuss about this issue, they clarified the HSMs aren’t vulnerable due to quorum voting across multiple HSMs located globally.
Even if there is voting across multiple machines, it doesn’t prevent race condition. The randomly picked HSM checks only the other members of the club, whether another transaction is in progress and not itself, so sending concurrent requests to the picked HSM will allow us to bypass the rate limit. Apple responded that HSMs doesn’t handle concurrent requests as stated below
I tested in multiple aspects of this use case and couldn’t confirm what they claim. When concurrent srp init and recover calls hit the escrow proxy, either all of them should be dropped or all of them should be processed serially but only one of them gets executed and others are dropped. This clearly indicates the host or the proxy is filtering the concurrent requests. I am not sure whether Apple HSM really doesn’t support concurrent processing and I didn’t want to invest anymore time on this as they are not transparent from the beginning.
As you can see in the above email screenshot, they said they didn’t consider 2FA bypass and other rate limit bypass patches that are resulted from my report as it was not included in my initial report.
That wasn’t fair. If someone didn’t report this in the first place, none of them would have been patched. Their investigation was result of the report and not the other way. What I had in my mind while writing the report was an account takeover vulnerability which included 3 endpoints bypass, I didn’t care about 2FA since it is not as critical as account takeover, so I focused only on that. Most fair bounty programs reward the maximum impact caused by the underlying vulnerability, not just what the report showcases. For example, Facebook rewards the maximum impact created by the underlying vulnerability after internal investigation. The following bug was a low severity issue (reward would be around $1000), after investigation they found a sophisticated RCE which is obviously critical so they rewarded $80,000 instead of the normal low severity payout.
I asked them with the same example but they skip this part in their emails and respond only to the HSM queries. I waited for months and there wasn’t any responses as expected. I decided to not participate in Apple’s bug bounty program until they change their polices and be transparent.
After my Instagram account takeover vulnerability, I realized that many other services are vulnerable to race hazard based brute forcing. So I kept reporting the same with the affected service providers like Microsoft, Apple and a few others.
Many people mistook this vulnerability as typical brute force attack but it isn’t. Here we are sending multiple concurrent requests to the server to exploit the race condition vulnerability present in the rate limits making it possible to bypass it.
Now lets see what I found in Apple.
The forgot password option of Apple ID allows us to change our password using 6 digit OTP sent to our mobile number and email address respectively. Once we enter the correct OTP we will be able to change the password.
For security reasons, apple will prompt us to enter the trusted phone number along with email address to request OTP.
So to exploit this vulnerability, we need to know the trusted phone number as well as their email address to request OTP and will have to try all the possibilities of the 6 digit code, that would be around 1 million attempts (10 ^ 6).
As for as my testing, the forgot password endpoint had pretty strong rate limits. If we enter more than 5 attempts, our account will be locked for the next few hours, even rotating the IP didn’t help.
Then I tried for race hazard based brute forcing by sending simultaneous POST requests to apple server and found a few more limitations.
To my surprise, apple have rate limits for concurrent POST requests from single IP address, not just to the forget password endpoint but to the entire apple server. We cannot send more than 6 concurrent POST requests, it will be dropped. It will not just be dropped but our IP address will be blacklisted for future POST requests with 503 error.
Oh my god! That is too much 🤯
So I thought they aren’t vulnerable to this type of attack 😔 but still had some hope since these are generic rate limits across the server and not specific to the code validation endpoint.
After some testing, I found a few things
- iforgot.apple.com resolves to 6 IP addresses across the globe – (184.108.40.206, 220.127.116.11, 18.104.22.168, 22.214.171.124, 126.96.36.199, 188.8.131.52).
- There were two rate limits we have seen above, one is triggered when we send more than 5 requests to forgot password endpoint (http://iforgot.apple.com/password/verify/smscode) and another one is across the apple server when we send more than 6 concurrent POST requests.
- Both these rate limits are specific to apple server IP which means we can still send requests (with in limits though) to another apple server IP.
- We can send upto 6 concurrent requests to an apple server IP (by binding iforgot.apple.com to the IP) from single client IP address as per their limits. There are 6 apple IP address resolved as mentioned above. So we can send upto 36 requests across the 6 apple IP address (6 x 6 = 36) from single IP address.
- Therefore, the attacker would require 28K IP addresses to send up to 1 million requests to successfully verify the 6 digit code.
28k IP addresses looks easy if you use cloud service providers, but here comes the hardest part, apple server has a strange behavior when we try to send POST requests from cloud service providers like AWS, Google cloud, etc.
They reject the POST request with 502 Bad gateway without even checking the request URI or body. I tried changing IPs but all of them returned same response code, which means they have blacklisted the entire ASN of some cloud service providers if am not wrong 🙄
It makes the attack harder for those who rely on reputed cloud services like AWS. I kept trying various providers and finally found a few service providers their network IPs are not blacklisted.
Then I tried to send multiple concurrent POST requests from different IP address to verify the bypass.
And it worked!!! 🎉🎉🎉 Now I can change the password of any Apple ID with just their trusted phone number 😇
Of course the attack isn’t easy to do, we need to have a proper setup to successfully exploit this vulnerability. First we need to bypass the SMS 6 digit code then 6 digit code received in the email address. Both bypasses are based on same method and environment so we need not change anything while trying the second bypass. Even if the user has two factor authentication enabled, we will still be able to access their account, because 2FA endpoint also shares the rate limit and was vulnerable. The same vulnerability was also present in the password validation endpoint.
I reported this information with detailed reproduction steps and a video demonstrating the bypass to Apple security team on July 1st, 2020. Apple security team acknowledged and triaged the issue with in few minutes of report.
I didn’t get any updates from Apple after triage so I kept following up for status updates and they said they are working on a fix on Sep 9th, 2020.
Again, no updates for next 5 months and then this email came when I asked for status
They said they are planning to address the issue in upcoming security update. I was wondering what is taking so long for them to react to a critical vulnerability.
I kept retesting the vulnerability to know whether its fixed instead of relying on them. I tested on April 1st, 2021 and realized a patch for the vulnerability was released to production but still there were no updates from Apple. I asked them whether the issue is patched and the response is same as they have no status updates to share.
I was patient and waiting for them to update the status. After a month, I wrote them that the issue was patched on April 1st itself and why am not being updated about it, I also told that I wanted to publish the report to my blog.
Apple security team asked me whether it is possible to share the draft of the article with them before publishing. That is when things started to go unexpected.
After sharing the draft, they denied my claim saying that this vulnerability do not allow to takeover majority of the icloud accounts. Here’s their response
As you can see in the email screenshot, their analysis revealed that it only works against iCloud accounts that has not been used in passcode / password protected Apple devices.
I argued that even if the device passcode (4 digit or 6 digit) is asked instead of 6 digit code sent to email, it will still share the same rate limits and would be vulnerable to race condition based brute forcing attacks. We will also be able to discover the passcode of the associated Apple device.
I also noticed a few changes in their support page regarding forgot password.
The above screenshot shows how the page looks now but it wasn’t the same before my report.
In October 2020, that page looked like this
Link from web archive : http://web.archive.org/web/20201005172245/https://support.apple.com/en-in/HT201487
“In some cases” is prefixed to the paragraph on October 2020, that is exactly after I was told that they are working on a fix in September 2020.
It looks like everything was planned, the page was updated to support their claim of only limited users were vulnerable. That page wasn’t updated for years but getting a minor update after my report. It doesn’t look like a coincidence.
When I asked about it, they said the updates are made due to changes in iOS 14. What does resetting password using trusted email / phone number has to do with iOS 14 I asked. If that is true, are trusted phone number and email used to reset the password before iOS 14? If that’s the case, my report is applicable to all Apple accounts. I didn’t get any answer from them.
I was disappointed and told them that I am going to publish the blog post with all the details without waiting for their approval. Here’s the reply I got from them.
They arranged a call with Apple team engineers to explain what they found in their analysis and also to answer any questions I may have.
During the call, I asked why it is different from the vulnerability I found. They said that the passcode is not being sent to any server endpoint and is verified in the device itself. I argued that there is no way for a random apple device to know another device’s passcode without contacting Apple server. They said it is true that the data is sent to server but it is verified using a cryptographic operation and they cannot reveal more than that due to security concerns.
I asked what if we find out the encryption process through reverse engineering to replicate it and brute force the Apple server with concurrent requests. I didn’t get any definite answer for that question. They concluded that the only way to brute force the passcode is through brute forcing the Apple device which is not possible due to the local system rate limits.
I couldn’t accept what Apple engineers said, logically, it should be possible to replicate what Apple device is doing while sending the passcode data to server.
I thought to verify it myself to prove them. If what they said is true, passcode validation endpoint should be vulnerable to race condition based brute forcing. After a few hours of testing I found that they have SSL pinning specific to the passcode validation endpoint, so the traffic sent to the server cannot be read by MITM proxy like burp / charles.
I figured out that Apple uses SRP (Secure Remote Password), a PAKE protocol to verify the user knows the right passcode without actually sending it to the server. So what the engineers said is right, they aren’t sending the passcode directly to server. Instead, both server and client do some mathematical calculations using the previously known data to derive at a key (more like diffie-hellman key exchange).
Without getting into the specifics of SRP, let me get straight to what is necessary in our context.
- Apple server has two stored values namely verifier and salt specific to each user created at the time of setting or updating the passcode.
- Whenever a user initiates a SRP authentication with username and a ephemeral value A, Apple server responds back with the salt of the specific user and a ephemeral value B.
- Client uses the salt obtained from server to calculate the key prescribed by SRP-6a.
- Server uses the salt and verifier to calculate the key prescribed by SRP-6a.
- Finally they both prove to each other that the derived key are same.
Read more about the detailed calculations of SRP-6a here.
SRP is known to prevent bruteforce attacks as it has user-specific salt and a verifier, so even if someone steals our database, they will still need to perform a CPU intensive bruteforce for each user to discover the password one by one. That gives enough time for the affected vendor to react to it.
But, in our case, we don’t have to bruteforce a large number of accounts. Bruteforcing single user is enough to get into their iCloud account as well as finding their passcode.
Brute forcing is possible only when you have both salt and verifier specific to the target user. After bypassing the SMS passcode we can easily impersonate as the target user and obtain the salt. But the problem here is verifier. We should either somehow obtain the verifier from server or bypass the rate limit on key verifying endpoint.
If the rate limit is bypassed, we can keep on trying different combinations of key obtained using the precomputed values of the passcode until we arrive at the matching key. Obviously, it requires a lot of computation to derive a key of each 4 or 6 digit numeric passcodes (from 0000/000000 to 9999/999999).
When we enter the passcode in an iPhone / iPad during password reset, the device initiates SRP authentication by sending the user session token obtained from the successful SMS verification. The server responds back with the salt of the respective user. The passcode and the salt are hashed to then derive the final key which is sent to https://p50-escrowproxy.icloud.com/escrowproxy/api/recover to check whether it matches the key computed (using ephemeral, salt and verifier) on the server.
And the POST request sent to verify the key looked like this
String tag has all the data mentioned above but are sent in DATA BLOB format. The first thing I wanted to check is rate limit before decoding the values of BLOB. I sent the request 30 times concurrently to check whether the endpoint was vulnerable.
To my shock, it wasn’t vulnerable. Out of 30 requests, 29 of them were rejected with internal server error.
Rate limiting would be performed in the Apple server itself or in HSM (hardware security module). Either way, the rate limit logic should be programmed as such to prevent race hazard. There is very bleak chance for this endpoint to be not vulnerable to race hazard before my report because all the other endpoints I tested was vulnerable – SMS code validation, email code validation, two factor authentication, password validation was all vulnerable.
If they did patch it after my report, the vulnerability became a lot more severe than what I initially thought. Through bruteforcing the passcode, we will be able to identify the correct passcode by differentiating the responses. So we not only can takeover any iCloud account but also discover the passcode of the Apple device associated with it. Even though the attack is complex, this vulnerability could hack any iPhone / iPad that has 4 digit / 6 digit numeric passcode if my assumption is right.
Since it is now validating the concurrent requests properly, there is no way for me to verify my claim, the only way I can confirm this is by writing to Apple but they aren’t giving any response in this regard.
I got the bounty email from Apple on June 4th, 2021.
The actual bounty mentioned for iCloud account takeover in Apple’s website is $100,000 USD. Extracting sensitive data from locked Apple device is $250,000 USD. My report covered both the scenarios (assuming the passcode endpoint was patched after my report). Even if they chose to award the maximum impact out of the two cases, it should still be $250,000 USD.
Selling these kind of vulnerabilities to government agencies or private bounty programs could have made a lot more money. But I chose the ethical way and I didn’t expect anything more than the outlined bounty amounts by Apple.
But $18,000 USD is not even close to the actual bounty. Lets say all my assumptions are wrong and Apple passcode verifying endpoint wasn’t vulnerable before my report. Even then the given bounty is not fair looking at the impact of the vulnerability as given below.
- Bypassed the two factor authentication. It is literally like 2FA doesn’t exist due to the bypass. People who are all relying on 2FA are vulnerable. This itself is a major vulnerability.
- Bypassed the password validation rate limits. All the Apple ID accounts that use common / weak / hacked passwords are vulnerable even if they have two factor authentication enabled. Once hacked, the attacker can track the location of the device as well as wipe the device remotely. 2014 celebrities iCloud hack is majorly because of weak passwords.
- Bypassed the SMS verification. If we know the passcode or password of the device associated with the iCloud account. Lets say any of your friends or relatives knows your device passcode, using this vulnerability, they can takeover your iCloud account and also can erase your entire device remotely over the internet without having physical access to it.
- We can takeover all Apple IDs that are not associated with a passcode protected Apple device due to both SMS and email verification code bypass, which means
- Any apple device without passcode or password, like anyone who turned off or didn’t set the passcode / password.
- Any Apple ID created without apple device, like in browsers or in an android app and not been used in password protected apple devices
- For example, 50 Million+ android users have downloaded Apple music app. In those, majority of them may not have used Apple devices. They are still Apple users and their information like credit cards, billing address, subscription details, etc could be exposed.
They need not reward the upper cap of the iCloud account takeover ($100k) but it should at least be close to it considering the impact it has created.
After all my hard work and almost a year of waiting, I didn’t get what I deserved because of Apple’s unfair judgement. So I refused to receive the bounty and told them it is unfair. I asked them to reconsider the bounty decision or let me publish the report with all the information. There wasn’t any response to my emails. So I have decided to publish my article without waiting for their response indefinitely.
Therefore, I shared my research with Apple for FREE of cost instead of an unfair price.
I request Apple security team to be more transparent and fair at least in the future. I would like to thank Apple for patching the vulnerability.
I repeat, the vulnerability is completely fixed and the scenarios described above no longer works. Thank you for reading the article! Please let me know your thoughts in comments.