Reversing a Prometei botnet binary with r2 and AI (Part One)

@cryptax
6 min readFeb 7, 2025

--

I’ve just laid my hands on a new malicious sample of February 2, 2025 (1 week ago). It is detected as Linux/Prometei.B. I’m going to reverse it “live” with Radare2 and r2ai. R2ai is an “extension” of Radare2 to get assistance from an AI. I use anthropic:claude-3–5-sonnet-20241022, for which I have an API key.

By “live”, I mean that I am starting the analysis just now, and don’t know where it is going to lead me. I’ll try and have you follow the flow of the research.

Prior Art on Prometei

Searching the web, I find several prior articles on Prometei which have been listed on Malpedia. The botnet seems to have initially emerged on Windows, and then targeted Linux. This article discusses the Linux binaries, which were first discovered in December 2020. So, we are in front of a well-known botnet family, with a new sample in February 2025.

The article explains the sample of 2020 mines Monero cryptocurrency. It is able to install both as standard user, or root. It drops both an infected binary (name: crashed.dump) and a machine identification file (name: CommID). Persistance is achieved via creation of a service named uplugplay + scheduled in cron. The malware contacts a remote C2 (name in 2020: p1.feefreepool[xxx]) and is able to process commands such as start_mining, sysinfo etc. Communication uses HTTP, there’s an encrypted key but the article isn’t clear on how it is used and which encryption algorithm is used. The bot also has the ability to communicate using Tor or I2P.

Ask the AI to decompile the main

I launch r2ai on the sample (./r2ai.sh /home/axelle/samples/prometei/prometei.elf) and ask the AI to decompile the main, using r2ai’s “auto” mode (i.e the AI may interact with r2, under my supervision).

First of all, it asks to list functions and find the main (“afl~main”). This is very reasonable, so I agree to run the command. It does not find any function named main (indeed, such a name is not always present!) so it asks to decompile the entrypoint (“pdf @ entry0”).

The AI thinks it has the main function at 0x004677ba.

The AI decompiles a function it thinks might be the main, but actually it turns out it is a decompression function, so it tries to investigate other functions.

The AI is still trying to locate the function that acts as the main

Ouch! It doesn’t find the main, and decompiles the decompression function, for which I have no interest 😢.

It’s a bit silly: the AI knows the decompression function is probably not interesting (see previous screenshot) but in the end it still finds nothing relevant and decompiles it.

Help the AI

When it starts wrong like that, AIs being stubborn, it’s useless to continue. Rather, I’m going to do some manual reversing and try to guide the AI towards parts I’d be interested in. In terms of cost, so far, I’ve “lost” 3 cents.

First, I notice there are only 4 functions. That’s really not a lot.

There are 4 functions. I disassemble the entry point. And then, I’m going to disassemble the remaining 3 to have a peek.

None of the 4 functions inspire me. And while I do have that function in 0x4677ba, I don’t have the second one the AI looked into at 0x46777c. It doesn’t even look like the beginning of a function. Strange. AI error?

I’m going to try a different angle: strings. I list strings with izz . The last one looks like a JSON object the malware would typically send to the C2.

10500 0x000687b4 0x000687b4 6   7            ascii 0/[p\r[
10501 0x000687e6 0x000687e6 4 5 ascii UPX!
10502 0x000687f0 0x000687f0 5 6 ascii UPX!\r
10503 0x000687fe 0x000687fe 4 5 ascii c;@!
10504 0x00068814 0x00068814 220 220 ascii {"config":1,"id":"uI1k0eaO404gOrE8","enckey":"zBvmGEPv76xLAqYtQp9VhV+kb6gJk0Xidwd0EmiPhcBJ5LIVsGKhUuqKxhH5BImh4yVFdi6BgwumBH4smKrT2h9+tgIsRzXavW77ecnk5pi4bowDSPo+vktwm0il+zwtAhYkRi3UHxJ5bCE1FJUNoVYi/spcXCJ4hLPmv3GXiSc="}

There’s also a UPX string. Maybe the sample is packed with UPX. That’d explain the decompression function… Yes, a little above in the strings we have: “This file is packed with the UPX executable packer”.

10388 0x00067890 0x00067890 29  30           ascii PROT_EXEC|PROT_WRITE failed.\n
10389 0x000678b0 0x000678b0 78 79 ascii $Info: This file is packed with the UPX executable packer http://upx.sf.net $\n
10390 0x000678ff 0x000678ff 75 76 ascii $Id: UPX 3.95 Copyright (C) 1996-2018 the UPX Team. All Rights Reserved. $\n

Oh wait, there are more interesting strings.

10343 0x0006723e 0x0006723e 14  15           ascii ttp://p3.feefr
10344 0x0006724d 0x0006724d 5 6 ascii pool.
10345 0x00067257 0x00067257 12 13 ascii /cgi-bin4rom
10346 0x00067264 0x00067264 4 5 ascii ei.
10347 0x0006726d 0x0006726d 10 11 ascii dummy.zeVo
10348 0x0006727e 0x0006727e 7 8 ascii gb7nijf
10349 0x00067287 0x00067287 11 12 ascii 5rgxdcncj.o
10350 0x0006729a 0x0006729a 8 9 ascii mkhkjxgc
10351 0x000672a3 0x000672a3 10 11 ascii fgu7uhofxz
10352 0x000672b1 0x000672b1 5 6 ascii goawn
10353 0x000672bb 0x000672bb 4 5 ascii cymv
10354 0x000672c0 0x000672c0 10 11 ascii ktqgpxrp?h
10355 0x000672ce 0x000672ce 11 12 ascii 2oq.b32.i2p
10356 0x000672da 0x000672da 5 6 ascii /usrk
10357 0x000672e2 0x000672e2 15 16 ascii /s;upluzlay/Pc%
10358 0x000672f6 0x000672f6 11 12 ascii C~mId1crash
10359 0x00067305 0x00067305 4 5 ascii ed.p

We recognize some typical Prometei string (crashed, feefrpool…), so at least we know we do really have a Prometei sample in our hands.

Sadly, I can’t find any reference for those strings, probably because they are in an unmapped memory area. Radare2 finds no sections nor symbols, I assume this is the work of the UPX packer. Arg. I hate that.

Can the AI unpack?

I run r2ai again and ask it to unpack. I’ve been wanting to show you how smart the AI is from the beginning of this blog post, and it continues to act silly 😢 It doesn’t find the UPX string…

The AI doesn’t believe me and wants to find a UPX string. The command iz shows strings in data sections. It should have tried izz to search in the whole binary…

Fortunately, the AI gives me some advice at unpacking a UPX packed binary.

The AI explains how to unpack the binary

Let’s do that! I install UPX on my system (apt install upx-ucl) and try to unpack. Ouch! It doesn’t unpack.

$ upx -d prometei.elf 
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020

File size Ratio Format Name
-------------------- ------ ----------- -----------
upx: prometei.elf: NotPackedException: not packed by UPX

Unpacked 0 files.

I’ve tried a couple of unpacking tweaks, but so far, I’m stuck at this point and can’t unpack the binary. I’ll write a Part Two when it’s done!

Conclusion

I have already used r2 with AI assistance over several malware (example), and it was usually very helpful. It produced excellent overview, good decompilation and even handled obfuscation. But it’s the first time I have the AI deal with packers, and up to now, the result is disappointing. To be fair, the AI did see there was a decompression function, but it did not spot the UPX string and did not understand the malware was packed.

I’ll follow up on this analysis as soon as I’ve managed to unpack the binary.

IOC: cc7ab872ed9c25d4346b4c58c5ef8ea48c2d7b256f20fe2f0912572208df5c1a

— Cryptax.

--

--

@cryptax
@cryptax

Written by @cryptax

Mobile and IoT malware researcher. The postings on this account are solely my own opinion and do not represent my employer.

No responses yet