How I Hacked WhatsApp Web in 3 Days
It was in October 2020 when I was stuck at home for obvious reasons and had little to do in my free time. With so much free time, I wanted to challenge my mind: I wanted to do some white hat hacking again after a few years of not having enough time for this hobby.
In 2016, I found a vulnerability in Meta’s OAuth library and was now looking for another good challenge. Because I use WhatsApp daily, I thought I might as well try to break WhatsApp.
Day 1
My initial idea was to test XSS in their messaging system. WhatsApp supports rich text features on mobile and the web, such as bold text, italic text, images, and lists, so this looked promising. Many websites had XSS vulnerabilities years ago; however, with the rise of frameworks such as ReactJS, these became less common. I opened WhatsApp on my mobile and also in my browser and started sending myself messages, hoping for some good results. Debugging on WhatsApp Web was much easier, as it worked with Chrome Devtools out of the box.
I’ve tried to break the UI by inserting some HTML and JavaScript snippets, like the one below. My goal was not to gain access to any account, just to break something, see an error in the console, or see a broken UI, which would be a good sign that I’m looking in the right direction.
':;"><h1>XSS
`'"});
//]]!> -->
After tens of messages, nothing broke the UI. If at least one error appeared in the console, I would jump so high I’d hit the ceiling. While doing this, I realized WhatsApp supports markdown, so I tried to identify the package they use to display the markdown content and maybe find some known vulnerabilities in the package.
Unfortunately, no luck.
Day 2
I was slightly disappointed with absolutely no findings but still very motivated. I‘ve noticed WhatsApp shows a nice preview of a website whenever you send someone a link. Maybe XSS could be in the preview?
I quickly set up my server in PHP (yes, you read correctly. PHP. There are like 1000 companies offering free hosting for PHP, but not that many offering free hosting for NodeJS, and there was no need to flex with Docker, so let’s continue). The server was very simple and was only built to debug the WhatsApp link preview feature. Imagine something like this.
<?php
echo "<meta name=\"title\" value=\"{$_GET['title']}\" />";
echo "<meta name=\"description\" value=\"{$_GET['description']}\" />";
echo "<meta name=\"keywords\" value=\"{$_GET['keywords']}\" />";
// etc
When the server was running, I could start sending myself messages with links that looked like the followinghttps://example.com?title=‘“;”><h1>XSS
and was hoping for something to break and print big text XSS.
Unfortunately, again, after many attempts, no luck was on my side.
Day 3
Kinda hopeless on the 3rd day. I was just thinking and playing around to see what features WhatsApp had and what could be abused by an attacker. E.g., message previews, gifs, emojis, file uploads, and file previews… As I was digging around, I looked at profile pictures. There’s not much that could be abused with images (right? right?). I had a look at where the profile pictures are coming from and noticed that, probably for performance reasons, there is a service worker running that allows you to scale down profile pictures.
The profile pictures are scaled down in your contact list, but when you open the profile detail, you see the full picture. There was nothing wrong with the pictures, but given that WhatsApp uses Service Worker, I had another file to look through to find some vulnerabilities.
I’ve noticed an interesting caching mechanism. I imagine this was used to save some data and avoid network requests when these are unnecessary. Service Workers are a good layer to do this kind of logic. How did it work?
Imagine the following URL https://web.whatsapp.com/pp?e=https://web.whatsapp.com/image-profile-1.jpg&t=1&u=1&i=1&n=1
.
If you visit this URL the first time, it fetches the image from the internet, and when you visit it again, the Service Worker will serve you a cached version.
After some digging, I noticed the caching mechanism does not work for images only but basically for any files. If I could only put my malicious URL in the e
param and then have WhatsApp display the HTML from my website, it would be a win! However, there was a catch. The catch was that the e
param could not be any URL, only a whitelisted URL by their content-security-policy
header.
I went through all the whitelisted domains and was hoping to find a domain where I could upload some content and have the content displayed by the serviceworker. Again, no luck in that.
As a last try, I tried to put data:
URL into the e
param and to my surprise, the content in the data:
URL was displayed. WHOAAAA!
What are data:
URLs? Imagine a URL that looks like this data:text/html,<h1>hello</h1>
. To some it may not look like a valid URL, but these are supported by many modern browsers. If you copy the URL and put it into your web browser, you’ll see a title saying hello.
What I did next was I crafted a URL with a <script>
tag executing alert(1)
to prove there was an XSS vulnerability. The URL may have looked like this.
https://web.whatsapp.com/pp?e=data:text/html,<script>alert(1)</script>&t=1&u=1&i=1&n=1
After opening the URL, I saw a sweet alert saying 1
which was a good enough proof of an XSS vulnerability.
I quickly wrote all the steps to replicate the vulnerability and opened a ticket with Facebook support. I reported the issue on Saturday, October 31, 2020, and quickly got a message on Monday, November 2, 2020, that the issue had been fixed. I’ve been asked to confirm if the issue was fixed, which I’ve confirmed. On Monday, December 7, 2020, I was awarded a bug bounty reward.
Potential impact of the vulnerability
With an XSS vulnerability, the attacker usually has full access to your account for the duration of the session (unless the attacker decides to steal your session—which in some cases may or may not be possible). If the attacker sends you a link and you click on it, then he could read all your messages, send messages on your behalf, or see your contact list.
I hope you’ve enjoyed this article.
Send me a hello at miso.szorad@gmail.com if you want to get in touch.