"How do I kill a process with Powershell?"

One December evening, a friend asks in a group chat how to kill a process if task manager is being non-cooperative. He's trying to test a game someone on Discord asked him to try and the installer is doing weird things. Sounds like infostealer. We tell him to forget the game and revoke Discord sessions now or he gets to create a new Discord account. And then all the other sessions too. He got lucky, there was only some Google searches on his account he didn't recognize. So that story ended relatively happily, but a lot of time and mental health was wasted doing cleanup and making sure the computer is safe to reconnect again. After the first panic he finally tells the game's URL and it's my turn to play. But Mallory nuked the group chat so we lost that history.

Analysis

I have everything prepared from the last time. Static analysis (binwalk, strings) doesn't really yield anything. It seems everything is baked into a chrome.exe and there's no way I'm getting likely obfuscated Javascript out from that. The "best" finding was registry.node which contained string "C:\Users\Administrator\Desktop\Leet Stealer\Api\crypter\script\node_modules\registry-js\build\Release\registry.pdb". At least it confirms we're dealing with an infostealer.

So I run the infostealer through Cuckoo'd VM connected to my "fake internet". Fortunately this one doesn't care about my self-signed fake certs, so mitmproxy works without having to poke anything with x64dbg. In a nutshell, it uploads autofill data, passwords, and cookies, and Discord sessions from various Discord-shaped clients and browsers to file.io and then posts a link to Discord webhook proxy (presumably). Helpfully it also leaves behind the zip it uploaded, so it's easier for the victim to take inventory on what needs to be changed and rotated...

Trolling potential

So, since this operates with simple POST requests instead of websockets, delivering test data would be rather trivial. At first I was a bit sad I've been postponing the fake browser data generator, but then I figured it doesn't really matter. More accurately, there's not need to send any files or anything that resembles real data, since the reporting endpoint is just notification of acquiring new "lootbox". Theory is that if and when they end up to a Discord channel somewhere, by flooding the webhook finding actual loots is at least annoying. There'd also be constant activity on the channel, adding to the annoyance. But the flood content must be somewhat random so it's not trivial to filter out downstream. Bee movie is meme-y and long enough, so I pick that, and to accompany that a list of names from Github. Unfortunately it turned out to be list of female names so that wasn't great for various reasons, but whatever. Put these together with some 20 lines of Python and off we go.

Screenshot of terminal running Python script, showing JSON payload of data being sent and responses from server

So, what's funny here is that while there is a rate-limit, it's relatively short and even tells us to "please try again after a minute". I chose to ignore the limits and just flood through them because it didn't seem to matter. IIRC at some point I slowed it down a bit from maybe 1req/sec to 1req/3sec, hoping to avoid the rate-limit, but I kept still hitting it. Oh well. After some 12 hours the "API key" for the proxy was deactivated.

Advent of CodeInfostealer

But there's more. For one reason or another the Mallory builds multiple different game.zips, even my friend got to test at least two builds of the game. So I kept polling the download directory for new builds and analyzing them. At best I'd be done in 15 minutes per build. Note: One hatch isn't one day like with advent calendars. This whole "adventure" lasted around four days. But it was December so I decided to call it my own advent calendar.

IoCs:

Hatch 2

Points directly at a IP:port/webhooks/<long-ass hexadecimal string>. Doesn't execute properly because my VM doesn't have any juicy data. Only sends "can't open file [...]\Fills.txt".

IoCs:

Hatch 3

Uploads files to file.io, fetch Discord injection from Github(!), report to another type of webhook. Unlike all other samples, this one also tries to install nastier kind of malware. Needed to write another flood.py for this format but it was trivial. And for once I was also responsible citizen and sent abuse report to Github about the repo. Report sent Dec 10th 4:13AM UTC, Github responded Dec 11th 10:41AM UTC that they've nuked the profile. Nice, but my method is still faster at rendering the malware less usable. Github: 30 hours. Endpoint flood: 12 hours. On the other hand getting the Github repos nuked is helpful later.

IoCs:

Hatch 4

Same as hatch 1. New "api key", though.

Hatch 5

Same as hatch 2.

Hatch 6

This one learnt an anti-VM trick. It checks for something with tasklist.exe. Replaced it with true.exe. Empty lists don't contain scary processes. execution continues.

Hatch 7

Same as hatch 2 and 5. Additionally tries to download and execute something from the Github I abuse reported earlier. At this point the repository was deleted.

Hatch 8

Broken build. Wouldn't even run. lol, lmao even.

Hatch 9

New anti-VM trick. Well, this one has been around the whole time but the result was ignored until now. Turns out that VMs return empty memory speed when queried with wmic. Fortunately the mallory asks for "wmic memorychip get speed", so as suggested by a CTF teammate I made a wmic.bat and put it into $PATH:

@echo off
echo Speed=2133

As a side-effect now my GPU is also Speed=2133 and as well as everything else it looks up. Well, at least it's not scary VMware. Another side-effect is that the network status indicator in system tray no longer gives "working Internet" indicator.

This one also tries to get Discord injection from the nuked Github repo. Same IoCs as hatch 2

Hatch 10

Same as hatch 1 and 4, but with new API key. Also wants to download some extra nastiness. No hits in Virustotal, though. Self-identifies as "Panelcrypter" in strings.

Hatch 11

Last hatch came with one last different webhook proxy. This is very different, instead of a free form text field the JSON has bunch of fields which were all for numbers, so I finally figured out what gofile.io urls looks like. I'm not quite sure what happened during this hatch, but the game's site stopped being behind Cloudflare and eventually the domain started to return NXDOMAIN. Either someone else was a responsible citizen and reported it to Cloudflare (and they did something, shocking) or Mallory gave up. But I'm sure someone did send an abuse report somewhere because the domain status is now "clientHold".

As for the webhook proxy, after flooding it for a while they banned my IP. Very nice. My IP is a CGNAT, so they also blocked some hundreds/thousands of other potential victims from getting their credentials leaked.

Anyway, if anyone else is wondering, Gofile URLs are shaped like this
fileid = ''.join(random.choice(string.ascii_uppercase+string.ascii_lowercase+string.digits) for _ in range(6))
download_link = f"https//gofile.io/d/{fileid}"

IoCs: