1. Introduction
Proofpoint's security researchers discovered and analyzed this new malware and named it NerbianRAT. This malware uses anti-analysis and anti-reversing features. It is a 64-bit program written in Golang and primarily spreads by impersonating emails sent by the World Health Organization regarding COVID-19-related security measures. It spreads through Word documents with VBA macros in email attachments.
2. Sample execution flow
3. Sample IOCs
Name: ee1bbd856bf72a79221baa0f7e97aafb6051129905d62d74a37ae7754fccc3db.doc
Size: 280469 bytes (273 KiB)
MD5: d7888fea6047b662a30bf00edac4c3ee
SHA1: 8137670512be55796f612e41602f505955b0bb0c
SHA256: ee1bbd856bf72a79221baa0f7e97aafb6051129905d62d74a37ae7754fccc3db
Name: MoUsoCore.exe
Size: 5867008 bytes (5729 KiB)
MD5: 5d5bc970f975341558b8d2c225ca0115
SHA1: 4f74826ed56cda233cfc12b86fd1b7da4a9f2e56
SHA256: 902c65435b6b44cfda1156b0e7c6a30b2785fa4f2cbb9b1944a66f5146ec7aa5
Name: UpdateUAV.exe
Size: 3642880 bytes (3557 KiB)
MD5: 9cca59eec5af63e42cd845b67cf6df89
SHA1: 178aad6c7918cc495a908944e79143a913630890
SHA256: 1b8c9e7c150bacd466fbe7f12b39883821f23b67cae0a427a57dc37e5ea4390f
4. Analysis of malicious code
4.1 Analysis of doc macro code
Double-click to open the doc file and find that it is a document with macros. The document induces the user to click to enable the macro script
Here, I use the olevba script to analyze the vba code of this word document
The olevba script has analyzed the main function of this vba code. From the decoded Base64 string, we can roughly judge that this vba script uses powershell to download the payload from C2 and write it to the local folder for execution
This vba code has three functions, GetByte and DecodeBase64, which are used for decoding Base64
The main Document_Open entry function, we can see that many strings are defined, but they are all Base64 encoded. Before use, these strings call the DecodeBase64 function for decoding
After decoding the Base64 string and optimizing the code, we can see the logic more clearly. The main logic is the command line in the red box, which uses cmd.exe to write the powershell command line to %temp%\util.bat, then execute the bat script, download the file from hxxps://www[.]fernandestechnical[.]com/pub/media/gitlog to %appdata%\UpdateUAV.exe and execute it, and after executing UpdateUAV.exe, delete %temp%\util.bat and %appdata%\UpdateUAV.exe
4.2 Analysis of UpdateUAV.exe
We examined the dropper file downloaded from C2. Through the detailed information, we can see that the file details are disguised as a Windows system program. Here, we can also find that the original file of this dropper is nsoobe.exe
Using the DIE tool to view UpdateUAV.exe, we found that this program is a 64-bit program and uses UPX3.9.6 compression shell for packing
I used the UPX -d command to directly perform automatic unzipping. If a modified version of UPX is encountered, manual unzipping is required, and the file size after unzipping expanded to nearly double
After peeling off the shell, we used the DIE tool to check that this UpdateUAV.exe is written in Golang, and the Go compiler version is 1.15.0 or above
To determine the exact Go compiler version, you can search for the stringgo1.
Keywords, it can be seen that UpdateUAV.exe uses the go1.17.3 compiler, note that this method may be invalid when encountering samples with removed symbol information and severe obfuscation
Here, we directly use IDA to open the file for analysis. By viewing the main function, we find that the symbol information of this Golang program is all there, and the code is not encrypted or obfuscated. We can even analyze the approximate function of the function through the function symbol name, such as the function main_hideWindows can be inferred to be hiding the process window
We use x64dbg for dynamic debugging. Here, for the convenience of debugging, we manually close the random base address, open the PE file with 010Editor, change the first byte before the DllCharacteristics in the extended header of the Nt header to 00 to close the random base address of the PE file, which was originally 60 81
We change it to 00 81 and save it, and we have successfully closed the random base address
At this time, we export the symbol information in IDA to a MAP file and import it into x64dbg. Open IDA, select File->Produce file->Create MAP file, then select the save location, and check all the boxes to confirm
Then, use the SwissArmyKnife plugin of x64dbg to import the just generated MAP file
After x64dbg imports the MAP file, by checking the address of the main function in IDA and setting a breakpoint, the import of the MAP file into x64dbg allows us to synchronize the analysis with IDA better
Firstly, let's analyze the hideWindows function. The name of the function suggests that this function is to hide the console window, and first uses GetConsoleWindow to get the console window handle
Finally, the ShowWindowAsync function is called with the SW_HIDE parameter to hide the console window
Next, let's analyze the checkEnvironment function, and we can see that this function calls the third-party package chacal from GitHub
We found that the chacal package is a Golang anti-virtual machine framework
The checkEnvironment function is mainly implemented by 5 functions, among which two functions are for process detection of security tools, and the other three functions are mainly for anti-virtual machine detection
The antidebug_processList function called a third-party package go_ps to traverse Windows processes
Used the CreateToolhelp32Snapshot function to create a process snapshot, and then used the Process32First and Process32Next function combination to traverse the process
Process32Next to traverse the next process
After traversing the process, call the github_com_p3tr0v_chacal_utils_PList function for comparison
First, compare the string length of the process blacklist list, if the length is the same, then call the runtime_memequal function to compare the strings
The process blacklist list contains a total of 42 items as follows, the logic of antimem_processList function and antidebug_processList function is the same, but antimem_processList only detects the process tools for DUMP process memory such as DumpIt.exe, RAMMap.exe, RAMMap64.exe, vmmap.exe, so the picture is not attached
The IsVirtualDisk function first calls the queryWMI function, which encapsulates two functions: first, it calls the CreateQuery function to create a WMI WQL query statement
Then, call the wmi_Query function to query the network card information using the WMI WQL statement
Finally, call the ContainsInList function to compare whether the network card is a virtual network card on the list of virtual network cards, the blacklist list of virtual network cards contains three: virtual, vmware, vbox
Next, analyze the ByMacAddress function, which first calls the getMacAddr function to query the MAC address of the local machine
Then, call the ContainsPrefix function to compare the MAC address of the local machine and the blacklist list
Next, analyze the diskTotalSize function, from the function symbol, it can be guessed that this function is used to detect the hard disk size, and from the function parameter 0x64 in decimal, it can be guessed that the detection size is 100GB
By analyzing the internal diskTotalSize function, it also calls the queryWMI function to query hard disk information, and then compares whether the local hard disk is less than 100GB, my virtual machine hard disk size is 99GB in hexadecimal 0x63
If all the above anti-debug detection passes, then use IsDebuggerPresent to detect whether the current process is being debugged, and also calls the time_Since function and the time_Now function at the beginning of the function to detect the function running time to judge whether the process is being debugged
The checkLocation function uses a GET requesthxxps://json[.]geoiplookup[.]io
The website retrieves the public IP address归属地 in JSON format, but this website blocks IP addresses with ASN 4134, so the returned value is an error code
Normally, if the IP address of the local machine is obtained, it will be compared with the regions in the list, and we can see that in this list, only two specific regions, London and Russia, the words in the middle are some unsuitable for children
A total of 7 words in the list were compared, and it can be guessed from the 2nd to the 6th word that the author of this malicious software may be a racialist
The strings_Index function is called for one-by-one comparison
The checkLocation function detects if the IP address is not in the list, it will call the downloadNerbian function to download the main program of NerbianRAT from the C2 server
Analyze the downloadNerbian function, this function will first use the RedFile function to openC:\\ProgramData\\USOShared\\MoUsoCore.exe
The file in the path
If the file does not exist, it will be downloaded from C2, and if the file exists, it will also judge whether the first two bytes of this file are 4D5A (MZSignature) to determine whether this file is a PE file
The downloadFile function is called to download NerbianRAT from C2
If the first download from C2 fails, it will call cmd to use curl to download from C2
After the C2 download is completed, the file will be read and the first two bytes of the file header will be checked for 4D5A (MZSignature) to determine whether it is a PE file
The last function is to create a scheduled task to achieve persistent operation, first, through CMD calling the formatted command to create a scheduled task
We can open the scheduled task to see that the trigger condition is to run once every hour
The trigger operation is to start the NerbianRAT downloaded from C2
If the creation of the scheduled task is successful, it will directly trigger the execution of running NerbianRAT, up to this point, the dropper program UpdateUAV.exe is analyzed
4.3 Analysis of MoUsoCore.exe
Next, we analyze the main program of NerbianRAT, NerbianRAT also uses UPX compression shell and the same process of unshell, this sample removes most of the symbol information, but we can still search throughgithub
The keyword search function of MoUsoCore.exe can view the used go open source package, and through the following packages, we can roughly determine the approximate function of NerbianRAT
The smbios package provides detection and access to the data and structure of system management BIOS (SMBIOS) and desktop management interface (DMI): github[.]com/digitalocean/go-smbios
Windows WMI provides the WQL interface: github[.]com/StackExchange/wmi
Desktop screenshot: github[.]com/kbinani/screenshot
Golang's Windows API encapsulation: github[.]com/AllenDang/w32
Golang's win32 ole implementation: github[.]com/go-ole/go-ole
Golang's Windows API encapsulation: github[.]com/lxn/win
Golang has a special function initialization function, with the definition formatfcun init()
This function will be executed before the main function, and the same package can define multiple init functions. The compiler will automatically rename them during compilation. It can be seen that there are two init initialization functions in the main package
The main_init_0 function uses a hardcoded AesGCM encryption mode key to decrypt many strings that need to be used
Decrypts using gcmAsm_open
It can be seen that the decrypted result is an IP address, which should be related to C2, and then multiple decryption operations are performed to decrypt the remaining encrypted strings
Now let's start analyzing the main function, the first function call main_I4JkbFMH is a process detection blacklist
The github open-source StackExchange package is used through WQL statementsSELECT * FROM Win32_Process
Query the local machine process
Compare the process blacklist list
Next, analyze the main_H5NzwUxN function, first obtaining the BIOS information of the local machine, and then hashing the obtained BIOS information using the MD5 algorithm
Then the MD5 value type is converted to hexadecimal
Then the getCurrentProcessId function is used to get the PID of the current process, and the PID is also hashed with MD5
Similarly, the MD5 value type is converted to hexadecimal
Then a unique ID is generated
Then the generated unique ID is converted to uppercase letters
The function main_H5NzwUxN collects host names and other information
The function main_JgJWgOp calls the ReadFile function to readargs_c.txt
If this file does not exist, the program jumps to the next part, and it is not clear what the function of this file may be, possibly for storing collected information later
The function main_ZPBgbOEQ readsC:\ProgramData\Microsoft OneDrive\setup\rev.sav
file, which may also be used to store some collected data
The function main_DNKvpcvy implements encryption and decryption as well as sending and receiving network requests. It first formatted an IP address, which may be the IP address of the C2 server
Towards C2hxxps://www[.]fernandestechnical[.]com/pub/health_check[.]php
Send a GET request to determine if C2 is alive
Send a GET request to C2
If C2 returns status code 200, then C2 is alive
C2 and the keep-alive heartbeat packet of the local machine
The local IP address is obtained
Next, 0x98-size content is encrypted using RSA-2048
The RSA public key is hard-coded
The RSA encrypted Buff is 0x100
Then, a buffer of 0x14C size is concatenated
Next, AesCBC mode encryption is used, with 4 bytes of padding code 0x4 added to reach 0x150 size
Encryption is performed using a hard-coded 32-byte Aes key
Data encrypted with a hard-coded AesCBC key is used
Randomly generated 0x10-size data is written to the header of the buffer encrypted with AesCBC
Concatenate again to write '8563' to the header of the buffer
The function 'main_P6EwC8SB' is used to encrypt the data of the 'auth_post', 'data_post', 'addr_post', and 'port_post' fields. This AesCBC mode encryption key is randomly generated 32 bytes
After encrypting with AesCBC mode
Next, a 70-byte random number is generated
Base64 encoding is used to encode the data encrypted with AesCBC mode
Randomly generated 70-byte data is filled into the header, and the 32-byte random key for AesCBC mode encryption is stored after the 70-byte data, with the subsequent data being the encrypted data encoded with Base64
The function 'main_GNd3j2oz' is used to generate the data of the 'session_key' field. It first calls the go-smbios package to obtain bios hardware information and uses MD5 hashing
Convert MD5 to hexadecimal
After that, the 0x40-byte global variable and the MD5 value of bios information and the string 'windows' are formatted, and then Base64 encoding is directly applied to these data
Concatenate the POST request data to be sent
Send POST request to C2
The screenshot feature is implemented using the screenshot open-source library
Screenshot feature
Here, I used Golang to write a decryption script. The data of the 'session_key' field is encoded with Base64 alone, while the data of the other four fields can be decrypted using this script. 'auth_post' and 'data_post' use three layers of encryption, with the first layer's data encrypted using RSA-2048, the second layer 'req' using a hard-coded AesCBC key for encryption, and the third layer '8563' using randomly generated AesCBC encryption. Therefore, we can decrypt up to two layers at most.
package main
import (
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
func main() {
// The encrypted data of the addr_post field
allcryptDataBase64 := "EcgOPkkOHFylaFoLaqoXmbKPGOzvddbJMlnTtEtlScAdeewEFwzdITJsRYdYEushByrcQJCtuqdlGSeQyCjNieJBeQSnVwNcDhtQrh06LdGa3uyRHexahEL05goQ=="
// The first 70 bytes of the encrypted data are garbage data, and the 32 bytes after the garbage data are the AesCBC encryption key
aesCBCKey := allcryptDataBase64[70 : 70+32]
// The data to be decrypted is 70 garbage bytes + 32 bytes of Base64 encoded AesCBC key
cryptDataBase64 := allcryptDataBase64[70+32:]
// Decode the encrypted data using Base64
cryptData, _ := base64.StdEncoding.DecodeString(string(cryptDataBase64))
// Use AesCBC to decrypt data
decryptData := AesDecryptCBC(cryptData, []byte(aesCBCKey))
// Print decrypted data
fmt.Printf("%x\n", decryptData)
// Decrypt the second layer data: call when decrypting auth_post and data_post data
DecryptoSecData(decryptData)
}
func DecryptoSecData(decryptData []byte) {
// Decrypt the second layer encryption
// Hard-coded AesCBCKey
gaesCBCKeyBase64 := "F+h/WB8d+NYSnWX9UM6z3WxOHCIwd819TFldpsPfkrI="
// Decode the second layer hard-coded AesCBC key
gaesCBCKey, _ := base64.StdEncoding.DecodeString(string(gaesCBCKeyBase64))
// The second layer data to be decrypted
secCryptData := decryptData[8:]
// Use AesCBC to decrypt data
secDecryptData := AesDecryptCBC(secCryptData, []byte(gaesCBCKey))
fmt.Println("Second layer data decryption--------------------------------------")
// Print decrypted data
fmt.Printf("%x", secDecryptData)
}
// AesCBC mode decryption function
func AesDecryptCBC(encrypted []byte, key []byte) (decrypted []byte) {
// Block cipher
block, _ := aes.NewCipher(key)
// Get the length of the key block
blockSize := block.BlockSize()
// Encryption mode
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
// Create an array
decrypted = make([]byte, len(encrypted))
// Decrypt
blockMode.CryptBlocks(decrypted, encrypted)
// Remove padding
decrypted = PKCS5UnPadding(decrypted)
return decrypted
}
// Remove padding
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
5. Summary
NerbianRAT uses one of the main methods of spreading malicious software, which is to spread through Word documents with VBA macros attached to email attachments. Many overseas APT organizations also use this method for targeted attacks. The cross-platform compiled programming language Go is increasingly being adopted by malicious software developers. Go's numerous open-source packages can achieve rapid development. NerbianRAT uses many anti-reversal and anti-virtual machine features, which increase the time and difficulty of analysis, and uses encryption methods combined with RSA and AES to transmit data. For such malicious software spreading methods, the only thing that can be done is to strengthen email address filtering and attachment detection, and to increase the popularization of information security education.
JAVA Security | In-depth analysis of the underlying mechanism of Runtime.exec command execution
Detailed explanation of house of emma exploitation techniques (analysis of 21 Huxiang Cup instances)
A brief analysis of the Fire绒 mistakenly killing explorer.exe event.
Database入门:Master the five basic operations of MySQL database and easily navigate the data world!

评论已关闭