Reverse engineering of wirenet malware


Like many peoples how wishing to level up in reverse engineering, i recently attempted to reverse a malware.

I therefore cloned theZoo (https://github.com/ytisf/theZoo), and started analyzing a randomly chosen sample.

This sample occured to be a wirenet sample. Wirenet, which is a malware targeting Linux and MacOS, was discovered around 2013 and has already been thoroughly analyzed.

There is therefore nothing new here, but i wanted to do this by myself.

So, let’s go ! The binary we’re gonna analyze has the following MD5 hash:

Quite expectedly, the binary occurs to be stripped:

Which means that its .symtab sections (among other) has been removed:

Another classical step when reversing a malware is to use the strings command:

The output contains around 900 lines. Among them, we can find some interesting information who give a fairly clear first idea of what this malware does.

Thus, we see strings who seems dedicated to handle HTTP requests:

strings related to firefox, thunderbird and sqlite, which suggests that the malware might have (passwords/cookies)-stealing functions targeting firefox and thunderbird (firefox stores various information such as cookies, history into sqlite files):

In the same way, the binary contains google-chrome / chromium related paths, which also suggests passwords/cookies stealing functionality:

Looking at the imports section also gives an idea of what the binary does, but here something quite strange occurs:

While the begining of this .dynsym section dump references various functions imports from libc, the end of this dump contains internal functions, such as cpCopyFile, RC4Crypt or SendAuthenticationPacket.

Let’s compile the small program below to illustrate why it is uncommon:

Now if we compare the sections of test (original binary) and test.strip, we see that .symtab and .strtab sections are deleted from test.strip:

First on the original binary:

Then on the stripped one:

The test binary and its stripped version have the identical .dynsym sections:

Note that the myfunc function, internal to test program, does not appear in this section who only contains symbols from libc.

The only section in which myfunc appears is the symtab section of the unstripped binary :

To sum up:

  • Symbols associated to internal functions (such myfunc in this example, and cpCopyFile, RC4Crypt or SendAuthenticationPacket in the malware) of an ELF binary only appear in the .symtab section (while .dynsym section contains symbols imported from external libraries)
  • The .symtab section is removed when stripping a binary
  • Therefore a stripped binary is not supposed to contain symbol/name of its internal functions.
  • Therefore having a malware whose .dynsym section contains symbols of internal functions is quite uncommon.

After some researchs, it appears that it’s in fact possible to build a binary in such a way that its .dynsym section contains symbols of its internal functions: The –export-dynamic of the linker:

While this options gives a possible explanation of having our wirenet sample embedding names of its internal functions, there is no way to be sure what the wirenet developper exactly did.

Now let’s examinate the main() function in IDA.

The first basic block calls InitAESTable, InitTransfersList, ReadSettings and InstallHost subfunction:

We won’t dwell on InitAESTable and InitTransfersList, so let’s directly go to ReadSettings:

This function inits an RC4 decryption context (RC4Setup function), then perform several calls to RC4Crypt to decrypt its configuration, one call per configuration element:

The RC4 context is initialized with the BuildEncryptionKey hardcoded key:

We can reproduce this logic in a small python script to decrypt ourself the configuration of wirenet:

The configuration contains, among other, the following parts:

  • the IP address and TCP port of the C2,
  • the proxy configuration,
  • a password (its purpose will be explained later),
  • the name of a file used as a mutex,
  • a file where keystrokes are registered,
  • a byte (set to 0x237) used as a bitfield who specifies which options are activated.

The next function is InstallHost:

What this function does depends on value of boolSettingByte (see above). InstallHost uses the IsOptionEnabled to test whether an option is enabled or not, each option being represented by a bit of boolSettingByte.

For instance, if IsOptionEnabled & 0x08 is not zero, than persistency via autostart is activated, and an entry is added to $HOME/.config/autostart directory, which is a common persistency mechanism in Ubuntu distribution.

To following functionalities or behaviour can be activated by the boolSettingByte:

  • The malware can itself into $HOME/WIFIADAPT file.
  • Persistency via $HOME/.config/autostart directory,
  • Persistency via the $HOME/.xinitrc file,
  • Keystrokes logging functionality,
  • The malware can daemonize itself via calling setsid() function, who creates a new session dedicated to wirenet.

Once the installation process is finalized, wirenet intializes a mutual authentication with the C2 before being able to handle C2 request.

The mutual authentication uses the following procedure:

Client authentication:

  • wirenet randomly chooses an Initialization Vector and a Salt using the function GenerateRandomData
  • wirenet computes a 256-bits AES key using the function Calculate. This function derivates the key from the hardcoded-password « sm0k4s523syst3m523 » and the randomly chosen salt.
  • wirenet encrypts a test packet, set to « RGI28DQ30QB8Q1F7 » with AES in CFB mode, using the initialization vector and the key
  • wirenet sends a packet containing the salt, the IV and the encrypted test packet
  • the C2 derivates the wirenet AES key using the salt and the password, and decrypts the encrypted test packet using this key and the client IV

Server authentication:

  • The server generates its own salt and uses it to derivate an AES key. The derivation mechanism uses the same function and the same password as wirenet.
  • The server encrypts the test packet using its own AES key and the client IV
  • Finally, it sends a packet who contains its salt and the encrypted test packet

Once authentication is done, all the packets are encrypted. Both wirenet and the C2 use the IV generated by wirenet, but the AES key differs (wirenet uses its AES key and C2 uses its own).

The packets exchanged between wirenet and the C2 share the same structure:

The command_type byte can take these values:

  • 12: list directory
  • 22: rename a file
  • 23: delete a file
  • 24: create a directory
  • 34: get session-related information
  • 36: list process
  • 38: kill a process
  • 39: list windows
  • 49: take a screenshot

This list is not complete and other commands exist, allowing the operator to activate the keylogger, steal the browser password, execute a process…

Command incoming from the C2 are processed in the ProcessData which is essentially a giant switch over command_type, each command being processed by a specific function.

Finally, reversing wirenet allows the develop a moke-C2 in python:

that’s all folk!


Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *