Dev | Disassemble | Debug

Lockkey: Technical analysis of a Golang-Ransomware.

Table Of Contents

Background

GOGiyM9WkAAnrXB

Recently, while I was browsing X(previously known as Twitter), I encountered a tweet by one of the malware researchers from the community, who is pretty well known for hunting malware samples, posted about a new ransomware variant known as lockkey, which is programmed in Golang. As I have enjoyed analyzing Golang-based malicious executables recently, I decided to give this new ransomware a go. So, this blog post will contain a technical analysis of the ransomware, its capabilities, and a YARA Rule and TTPs aligned with the MITRE Framework.

Metadata

SHA-256 : eb58cbfca307a9d3cfe718d772f7a53079db87bc8936023d6b7adb8cf7206711

Sample: Available here.

Basic Static Analysis.

image

Once, we are done downloading the sample, we go ahead with loading the sample on Detect-It-Easy an initial triage binary analysis tool, which gives us confidence that this sample is programmed using Golang. Next, we go ahead and check for some artefacts.

image

GEpiHmfNPehj-aQoWitd/sZWzxps9LkqWENj7tz61/mE_KWXQ-UwK0Xa5HpFKC/5EJgSMP8RHTKwJhmft2d

We could, fortunately, find one of the instrumental artefacts in the build ID of this sample, which can be incorporated into the detection rule, while hunting for similar samples on various popular malware corpus like VirusTotal and much more.

Therefore keeping these artefacts in mind, we will move ahead to the ransomware code, using IDA-Freeware.

Looking into the code using IDA-Freeware.

image

We load the sample into IDA-Freeware, and once the initial auto-analysis is completed, we see there’s a main_main function, which is the function we are interested in for now, let us dive into it, and figure out the rest of the code, and look into every interesting function.

image

Just after, we land on the first graph inside the main function, we see the first part of the code 1 which is responsible for setting up the stack frame, local variables and calling GO runtime functions, which are necessary for the program, ending with adding a nop instruction either for alignment or padding.

image

image

In the second part of graph 2, this code is responsible for first loading a data structure containing a list of processes which are to be terminated. Once it is loaded, there is a call to another function known as enc_pkill_Pkill. Let us look into the code, before concluding the working of the function.

image

Initially, it loops through the processes which, it receives as an argument from the previous data structure containing the list of processes.

image

Then, it goes ahead and appends the .exe extension into the processes loaded from the previous data structure, in case they do not have it.

image

image

Then, it goes ahead with appending the taskkill /im /f command to forcibly terminate the process using taskkill system utility, which is executed using os_exec golang command, which is used to run the system commands in Golang code.

Therefore, we can now conclude that the second part of the code in this graph is used to terminate the processes using task-kill post-loading.

image

Then, moving ahead to the next node, we can see that, if the code does not find the processes to terminate, it prints a message Process Not Found to the standard output.

image

Now, moving ahead to the fourth graph node, we can see that in case the processes were terminated, the control flow of the program will pass to this block of code, where we have another function enc_shadowcopy_Delete, being called, let us go through this function before moving ahead.

image

We can see that this function is responsible for executing vssadmin delete shadows /all /quiet which is responsible for deleting all shadow copies.

image

Next, we move ahead to the other graph node, where we can see a function, config_Dirs being called which is responsible for enumerating all the possible directories present on the drives, achieved by looping over the existing drives.

image

Now, we can see that in the fifth[5] node of the graph, we have a simple comparison against the rax register, and the code flow jumps to the sixth[6] node of the graph, let us explore the first function inside the sixth graph node, which is main_main_func1.

image

Initially, as we saw that the code, where it enumerated the directories, this function uses those enumerated directories, at first it prints a Walking message.

image

image

image

Then, using path_filepath_Base it gets the base name of the file from the directory, later when the check is fulfilled, it goes ahead and prints another message known as Good File, which is further processed in a Queue for locking. Now, once this task is complete, it calls another function known as main_main_func1_1. Let us check out the working of the function.

image

image

After, we navigate to the function, main_main_func1_1, we can see that there is a call to another function, known as enc_encryption_EncryptFiles , which is responsible for encrypting all the files pushed into the Queue, in the previous function.

image

image

image

From, the above function, it is now clearly evident that, the code is using AES to encrypt the files, and replacing their extension with .lock . Now, once we have looked into this function, let us go to the caller of this function, which is main_main_func1 function.

image

image

image

Now, after scrolling a little bit after the function(main_main_func1_1) has returned we can see that the config note stored in the .rdata section is being loaded, and finally the contents are written into a file known as ВОССТАНОВИТЬ ФАЙЛЫ.txt using the os_WriteFile function, and with this we, have the work of this function complete, and now it is returned to the caller main_main .

Now, we have explored the functions, resposnible for walking the directories, and encrypting the contents using AES algorithm, we are done with the [6] graph node, and this path continues for all the files which are present on the target machine, over all existing drives. Next, we will move to the last interesting graph which is [7].

image

GOGiyM-WsAA7y6L

Here, we can clearly see that MessageBox API is used print this message ВНИМАНИЕ! , Система вашей компании была полностью скомпрометирована.Все ваши критичес кие данные были зашифрованы. , with a title of the messagebox being Locker , and finally pops the messagbox, which notifies the user’s data have been locked.

With, this we are done exploring the code using IDA-Freeware.

Workflow.

image

YARA Rule.

I did draft a very basic YARA Rule for detecting the ransomware variant, if you find the rule needs fine-tuning or it needs some sort of fixation, please do let me know, thank you in advance!

rule Lockkey {

    meta:
        description = "Detecting Lock-key Ransomware"
        author = "ElementalX"
        date = "2024-05-31"
        rule_version = "1.0"
        malware_type = "Ransomware"

    strings:

        $process_kill = { BA 10 00 00 00 87 51 20 48 8B 0D ?? ?? ?? ?? 48 8B 1D ?? ?? ?? ?? 48 8B 15 ?? ?? ?? ?? 48 89 C8 48 89 D1 E8 ?? ?? ?? ?? }
        $shadow_copydelete = { 48 8D 15 ?? ?? ?? ?? 48 89 94 24 ?? ?? ?? ?? 48 C7 84 24 ?? ?? ?? ?? ?? ?? ?? ?? 48 8D 15 ?? ?? ?? ?? 48 89 94 24 ?? ?? ?? ?? 48 C7 84 24 ?? ?? ?? ?? ?? ?? ?? ?? 48 8D 15 ?? ?? ?? ?? 48 89 94 24 ?? ?? ?? ?? 48 C7 84 24 ?? ?? ?? ?? ?? ?? ?? ?? 48 8D 15 ?? ?? ?? ?? 48 89 94 24 ?? ?? ?? ?? 48 C7 84 24 ?? ?? ?? ?? ?? ?? ?? ?? 48 8D 05 ?? ?? ?? ?? BB ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? ?? BF ?? ?? ?? ?? 48 89 FE E8 ?? ?? ?? ?? }
        $walking_file_encryption = { 44 0F 11 BC 24 ?? ?? ?? ?? 48 8D 15 ?? ?? ?? ?? 48 89 94 24 ?? ?? ?? ?? 48 8D 74 24 30 48 89 B4 24 ?? ?? ?? ?? 48 8B 74 24 48 48 89 B4 24 ?? ?? ?? ?? 48 8B 7C 24 68 48 89 BC 24 ?? ?? ?? ?? 48 8D 8C 24 ?? ?? ?? }
        $ransom_note = "Система вашей компании была полностью скомпрометирована"
        $go_build = "GEpiHmfNPehj-aQoWitd/sZWzxps9LkqWENj7tz61/mE_KWXQ-UwK0Xa5HpFKC/5EJgSMP8RHTKwJhmft2d"
   
   condition:
           uint16(0) == 0x5A4D and
           uint32(uint32(0x3C)) == 0x00004550 and 
           all of them
    }
       

MITRE ATT&CK.

T1057 - Process Discovery.

T1489 - Service Stop.

T1490 - Inhibit System Recovery.

T1082 - System Information Discovery.

T1486 - Data Encrypted for Impact.

Author’s two cents.

It was fun analyzing a golang based simple ransomware, hope you enjoyed reading my approach towards analyzing this ransomware, if you find anything suspicious or wrong, please do reach out to me.

Resources.