Ransomware Payments

The article “How ransomware gangs negotiate payments” by Kolawole Samuel Adebayo on Fast Company, discusses the intricacies behind ransomware attacks and the methods used by attackers to negotiate payments. The CEO of White Knight Labs, Greg Hatcher, contributes to the article with his expert insights. According to Greg Hatcher, ransomware attackers typically dictate the method of communication and payment, which is almost always Tor and cryptocurrency due to the anonymity those platforms provide. He explains that the encrypted data from the victim’s critical systems allows attackers to swiftly define these communication and payment channels. Hatcher also describes the challenges involved in tracing illicit ransom payments. Even with the public ledger characteristic of blockchain technologies, tracing these transactions remains an “expensive and time-intensive” task. This is primarily due to the multitude of wallets involved in the transactions and the overall anonymity that cryptocurrencies present, making it difficult to follow the money trail. Greg Hatcher provides valuable insights into the shadowy mechanics of ransomware negotiations and the accompanying challenges involved in fighting this growing form of cybercrime.
Mockingjay Memory Allocation Primitive
A new post from Security Joes brought attention to a process injection technique previously underutilized in offensive security. The RWX injection primitive, now dubbed “Mockingjay,” offers attackers an advantage to evade unbacked executable memory detection. The core idea behind this technique, reusing RWX regions from legitimate modules, is a valuable alternative to existing memory allocation and protection primitives. The success of injection into RWX memory depends heavily on the module and memory region selected by the operator. RWX injection is similar to module stomping but may require novel detection techniques in optimal scenarios. Packed binaries are the most common targets for this technique. This blog offers guidance for selecting the appropriate targets, along with an enumeration script and a functional injection template. Previous Work To be clear, I did not develop this technique or even popularize it. I had success with RWX injection in the past, and now that it has become popular again, a post seemed justified. The initial idea for RWX injection appears to have originated from Unknown Cheats. A 2018 post from namazo describes an anticheat bypass to avoid detections that rely on pointers to unbacked memory. A working injector was uploaded to GitHub a year later. Most recently, Security Joes uploaded their blog post on “Mockingjay,” which generated interest in the security community. RWX Injection Process injection requires three to four primitives: 1. Allocate or find memory for code. 2. Write code to the memory. 3. Change the memory permissions (may not be required if already executable). 4. Execute the code. RWX injection fulfills steps one and three. You will still need to write code to the RWX region and execute it. Using a module with RWX memory is beneficial because an executable on disk backs it. Module stomping also takes advantage of this attribute, but it’s more likely vendors can validate the data of memory that isn’t meant to be writeable. To prevent this technique, some anticheat vendors apparently blocked all DLLs with RWX memory regions and made exceptions as necessary. This is an excellent solution for protecting a single application, but it likely isn’t an option for security vendors. Discovering Module Targets Potential targets of this attack are PE files with at least one section marked RWX by its characteristic flags in the PE header. – IMAGE_SCN_MEM_EXECUTE – 0x20000000 – IMAGE_SCN_MEM_READ – 0x40000000 – IMAGE_SCN_MEM_WRITE – 0x80000000 We can search for this manually with a tool such as PE-bear. The “Characteristics” column of the “Section Hdrs” tab conveniently lists the value for each section and translates it to the familiar “RWX” format. The manual process is slow, but we can automate it using the pefile Python package. This programmatic method can also check whether the module is signed and retrieve the region and raw data sizes. We uploaded a Python script to GitHub with these capabilities. The best option would be a signed DLL with enough space to hold shellcode and only a minimal amount of raw data. However, any PE file with an RWX memory region may work. These criteria only reduce the likelihood of detection or instability and improve operational usefulness. It’s important to consider the effects of loading a module to ensure process safety. For instance, if a target DLL is injected, its DllMain function may run and impact the host process. No affected PE files were found in C:\Windows\System32 on Windows 11, but we identified signed third-party modules that met the criteria. – ISSetup.dll (.rsrc) – 135KB – PEbiosinterface32.dll (UPX0) – 4.3MB – libnxusb.dll (.textbss) – 1MB – GoTo Opener.exe (UPX0) – 839KB – Spotify.exe (.data) – 6.8MB PEbiosinterface32.dll is similar to the example in namazo’s blog post. Any PE file packed with UPX (and likely any other packer) is a potential target for the technique. POC You can find our local and remote injection templates on GitHub. RWX injection is straightforward once you have identified a suitable target. In either local or remote injection, the process is as follows. 1. Load the identified module into a target process. 2. Calculate the virtual address of the RWX section using the module base address and RVA of the target section. 3. Copy shellcode to the RWX section. 4. Initiate execution of the shellcode. As you can tell, the methodology has room for substantial variation. Our templates demonstrate a simple method for testing, but the primitives used for module load, memory write, and execution could easily be replaced. The code shows the RWX injection technique but likely won’t bypass any security products without modifying the other primitives. Closing Thoughts Although not a new concept, RWX injection has been overlooked by security professionals until recently. Awareness of public techniques is crucial to ensure security vendors effectively address them. While this memory allocation and protection primitive may be difficult to detect, there are still opportunities for defenders to identify execution methods or post-exploitation activity. Credits – Apparent origin of RWX injection: [Release] Some internal detection vectors bypass (unknowncheats.me) – Recent blog that brought attention to the technique: Process Mockingjay: Echoing RWX In Userland To Achieve Code Execution (securityjoes.com)
Developing Winsock Communication in Malware
Winsock is an API (Application Programming Interface) that provides a standardized interface for network programming in the Windows operating system. It enables applications to establish network connections and send and receive data over various protocols such as TCP/IP, UDP, and more. The flexibility and wide adoption of Winsock makes it an attractive choice for malware authors seeking to establish covert communication channels. In this article, we will explore a sample code that demonstrates a basic implementation of end-to-end communication using the Winsock protocol. As the code is ported to BOF, it replaces the default Named Pipes that Cobalt Strike uses with Winsock. Initializing the Winsock server // Initialize WinsockWSAStartup(MAKEWORD(2, 2), &wsaData) != 0; This code initializes the Winsock library by calling the WSAStartup function. These lines set up the server’s address and port information and bind the socket to this address. The code assigns the address family (AF_INET for IPv4) to serverAddress.sin_family. INADDR_ANY is used to bind the socket to all available network interfaces on the server machine, allowing it to accept connections from any IP address. The port number is set to SERVER_PORT using serverAddress.sin_port. The htons function is used to convert the port number to network byte order. The bind function is then called to associate the socket with the server address and port. It takes the socket descriptor (serverSocket), a pointer to the server address structure ((struct sockaddr*)&serverAddress), and the size of the server address structure (sizeof(serverAddress)). bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress); // Listen for incoming connectionslisten(serverSocket, SOMAXCONN); The listen function puts the server socket into a passive listening state. The serverSocket parameter is the socket descriptor that was previously created and bound. SOMAXCONN represents the maximum number of clients that can wait to be accepted by the server. Retrieving the command The code enters a while loop that continues indefinitely until the entire message is received or an error occurs. The recv function is called to receive data from the client socket. It reads data into the buffer starting from the current position buffer + totalBytesRead. It specifies the maximum number of bytes to read as MAX_BUFFER_SIZE – totalBytesRead. The purpose of this code is to read a message sent by the client in chunks until the entire message is received. It allows for the reception of messages that may be larger than the buffer size (MAX_BUFFER_SIZE) by reading the data in multiple iterations. Executing commands The CreateProcessA function is used to create a new process and allows you to specify the command-line parameters for the process. The first parameter NULL specifies that the new process will inherit the environment variables of the calling process. The second parameter (LPSTR)command specifies the command-line string that determines the executable and its arguments. Once executed, ReadFile is used to parse the output at the end of the pipe. Sending the output back This line extracts the socket descriptor from the clientSocketPtr pointer and assigns it to the variable clientSocket. The clientSocketPtr is a void pointer that points to the memory location where the socket descriptor is stored. By using type casting (SOCKET*), the code interprets the pointer value as a pointer to a SOCKET data type and dereferences it to obtain the actual socket descriptor value. This socket descriptor represents the connection between the server and the client. The == SOCKET_ERROR part is a comparison that checks if the return value of the send function is equal to SOCKET_ERROR. This comparison is commonly used to check if the send operation encountered an error. If the comparison is true, it indicates that there was an error in sending the data. Network analysis In our public repository we were able to replace the default Named Pipe communication that Cobalt Strike uses with Winsocket. After loading the CNA script, using “socky” command and the first argument, which is the command to be executed, we are able to send and receive the desired output via Winsocket: For each command sent, it will create 11 packets for the end-to-end communication. In this case we filtered the results to display only the TCP Port 8888 (the port we are using for the communication): Analyzing the packets easily leads to the commands and the results (as no encryption was used). Conclusion In conclusion, this article has provided an overview of Winsock, an API that facilitates network programming in the Windows operating system. Throughout the article, we have examined a sample code that demonstrates a basic implementation of end-to-end communication using the Winsock protocol. By porting the code to BOF (Beacon Object Files), it replaces the default Named Pipes utilized by Cobalt Strike with Winsock. The whole project can be found in our repository.