Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
NullGate — Libreria che facilita l'uso di syscall indirette. Un bypass AV/EDR piuttosto interessante come PoC. | Kitploit
Strumenti/GitHubGitHub/0xsch1zo/nullgate
Strumenti di Crittografia/DecrittografiaShellcodePost-ExploitRed TeamingSviluppo PayloadAttacco Avversario
GitHub0xsch1zo/nullgate

NullGate

Libreria che facilita l'uso di syscall indirette. Un bypass AV/EDR piuttosto interessante come PoC.

Vedi Repository
16819301 anno faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

NullGate

Questo progetto implementa un modo comodo e moderno per usare le funzioni NTAPI tramite syscall indirette, accoppiato al metodo FreshyCalls con una piccola variazione per il recupero dinamico dei numeri di syscall. Utilizza inoltre una tecnica che non ho visto menzionata per bypassare la scansione della memoria di Windows Defender. Il progetto implementa un classico PoC di injection di processi usando la libreria. Sono disponibili anche funzioni comode per la crittografia.

Demo

Dimostrazione dell'esempio

Compilazione

Per compilare l'esempio usa -DNULLGATE_BUILD_SAMPLE=ON. Se hai compilato nullgate direttamente, sarà accessibile in <build_dir>/sample.exe; se lo hai compilato come dipendenza, in <build_dir>/_deps/nullgate-build/sample.exe. Su Windows, poiché le destinazioni di build sono strane, probabilmente si troverà nelle stesse directory di base delle posizioni degli esempi, ma probabilmente annidato un po' più in profondità. Prende come argomento un PID nel quale vuoi iniettare lo shellcode.

[!WARNING] Se stai usando Linux devi avere installato il cross-compilatore mingw. Su Arch, per esempio, puoi fare pacman -S mingw-w64-gcc. Poi usa l'opzione -DNULLGATE_CROSSCOMPILE=ON per impostare mingw come compilatore predefinito.

[!TIP] È anche consigliato eseguire lo strip del binario risultante per ridurre la possibilità di rilevamento.

git clone https://github.com/0xsch1zo/NullGate
cd NullGate
cmake . -B build -DNULLGATE_BUILD_SAMPLE=ON
cmake --build build/

Hashser deprecato (versioni 1.1.3 e precedenti)

Può essere compilato usando il flag -DNULLGATE_DEPRECATED_HASHER.

Utilizzo

Aggiungere nullgate al tuo progetto

CMake FetchContent è supportato. Ecco un esempio di un semplice CMakeLists.txt:

cmake_minimum_required(VERSION 3.25)

include(FetchContent)

FetchContent_Declare(nullgate
    GIT_REPOSITORY https://github.com/0xsch1zo/NullGate
    GIT_TAG 1.2.0 
)

FetchContent_MakeAvailable(nullgate)

project(test)

add_executable(test
    main.cpp
)

target_link_libraries(test
    PRIVATE nullgate
)

Il linking è fatto staticamente, quindi non devi preoccuparti che i simboli siano visibili.

[!NOTE] Gli esempi seguenti useranno namespace ng = nullgate

Syscall

L'uso è abbastanza semplice, ecco uno snippet che dimostra la funzionalità principale:

ng::syscalls syscalls;
typedef NTSTATUS NTAPI NtAllocateVirtualMemory(
    _In_ HANDLE ProcessHandle,
    _Inout_ _At_(*BaseAddress,
                 _Readable_bytes_(*RegionSize) _Writable_bytes_(*RegionSize)
                     _Post_readable_byte_size_(*RegionSize)) PVOID *BaseAddress,
    _In_ ULONG_PTR ZeroBits, _Inout_ PSIZE_T RegionSize,
    _In_ ULONG AllocationType, _In_ ULONG PageProtection);

NTSTATUS status = syscalls.SCall<NtAllocateVirtualMemory>(
      ng::obfuscation::fnv1Const("NtAllocateVirtualMemory"), processHandle,
      &buf, 0, &regionSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

C'è type-safety integrata. Devi solo fornire la definizione della funzione NT che vuoi chiamare! Puoi ottenerla facilmente da ntdoc. Questo è il metodo consigliato per usare la libreria.

La precedente interfaccia non deprecata

Per chi non ama la magia nera dei template C++ o simili, l'interfaccia precedente è ancora disponibile:

NTSTATUS status = syscalls.Call(ng::obfuscation::fnv1Const("NtAllocateVirtualMemory"),
                         processHandle, (PVOID)&buf, (ULONG_PTR)0, &regionSize,
                         (ULONG)(MEM_RESERVE | MEM_COMMIT), (ULONG)PAGE_EXECUTE_READWRITE);

Usando questa interfaccia devi fare il cast degli argomenti al tipo giusto; non farlo potrebbe causare problemi.

Crittografia/hashing

Hashing delle chiamate ntapi

constexpr uint64_t hash = ng::obfuscation::fnv1Const("NtAllocateVirtualMemory");

Il metodo fnv1Const dimostrato in precedenza porta le gioie del C++ moderno nel mondo del maldev. È una funzione consteval, quindi è garantito che venga valutata in fase di compilazione, sostituendo il nome di funzione leggibile con un hash fnv1.

Esiste anche un equivalente a runtime chiamato fnv1Runtime, ma ovviamente non aggiunge il vantaggio di offuscare i nomi delle nostre funzioni. Viene usato dall'implementazione per verificare quale funzione all'interno di ntdll ottenere il numero di syscall.

Crittografia xor generale

Ci sono tre routine per la "crittografia" xor:

xorConst
constexpr ng::obfuscation::ConstData xored = ng::obfuscation::xorConst("some string");
std::cout << xored.string();

Possibile output:

<Y:-E&X0

Questa routine, analogamente alla funzione fnv1Const, viene valutata in fase di compilazione, quindi "some string" non apparirà mai nel binario, perché la stringa verrà memorizzata nella sua forma crittografata. Ma ehi, dobbiamo effettivamente usare quei dati! ConstData è un sottile wrapper attorno a byte grezzi di dimensione costante. Ha due metodi: raw() e string(). raw() restituisce un std::vector<unsigned char> e string, come suggerisce il nome, restituisce un std::string.

[!NOTE] Se devi costruire ConstData direttamente con un literal stringa, usa std::to_array per costruire un array intermedio passato a ConstData. Nota comunque che con questo approccio ConstData memorizzerà anche il carattere null aggiuntivo del literal.

Ovviamente abbiamo bisogno di un modo per decrittare e usare questi dati, che è la prossima funzione che tratteremo.

xorRuntime

xorRuntime è la seconda routine disponibile. Come suggerisce il nome, è l'equivalente a runtime di xorConst. Nota che non deve essere usata solo per la decrittazione: funziona in entrambe le direzioni, anche se usarla per la crittografia non offre i vantaggi di offuscare la stringa in fase di compilazione.

ng::obfuscation::ConstData xored = ng::obfuscation::xorConst("some string");
ng::obfuscation::ConstData data = ng::obfuscation::xorRuntime(xored);
assert(data.string() == "some string");

std::string dynamicString = "some data of dynamic size";
auto dynamicData = ng::obfuscation::DynamicData(dynamicString);
auto xoredDynamic = ng::obfuscation::xorRuntime(dynamicData);
auto unxoredDynamic = ng::obfuscation::xorRuntime(xoredDynamic);
assert(unxoredDynamic.string() == dynamicString);

DynamicData ha gli stessi metodi di ConstData con alcuni costruttori aggiuntivi per l'interoperabilità e, come suggerisce il nome, può avere una dimensione non nota in fase di compilazione. xorRuntime accetta sia DynamicData che ConstData.

xorRuntimeDecrypted

Mentre potremmo sempre decrittare a runtime chiamando prima xorConst e passando il risultato a xorRuntime, è un po' noioso. Ecco la soluzione a questo problema, la ciliegina sulla torta: xorRuntimeDecrypted è una funzione comoda per i literal di stringa su cui non serve operare mentre sono nello stato crittografato. Crittografa il literal di stringa in fase di compilazione e poi lo decritta a runtime in un'unica chiamata. Non è fantastico!.

ng::obfuscation::ConstData text = ng::obfuscation::xorRuntimeDecrypted<"some string">();
assert(data.string() == "some string");
La chiave

Qualcuno potrebbe dire: tutto è fantastico, ma dov'è la chiave? In nullgate 1.2 la chiave viene generata casualmente a ogni nuova build effettuata! (cioè quando viene eseguito il comando cmake) Questo riduce ulteriormente la possibilità di essere rilevati tramite firme.

Bypass della scansione della memoria di Windows Defender

Il cuore del problema è che quando chiamiamo NtCreateRemoteThreadEx o NtCreateProcess, viene attivata una scansione della memoria e il nostro payload msfvenom, decisamente ricco di firme, viene rilevato.

Scarica lo strumento