
Un cliente práctico para ADWS en Golang.
Un cliente práctico para ADWS en Golang.
Sopa implementa la pila de protocolos ADWS (MS-NNS + MC-NMF + SOAP), exponiendo las siguientes funcionalidades desde línea de comandos:
query: ejecuta búsquedas por filtro LDAP mediante el bucle WS-Enumeration Enumerate + Pull con proyección de atributos, control de alcance (Base/OneLevel/Subtree) y paginación.get: obtiene un único objeto por DN mediante WS-Transfer Getcreate: crea objetos mediante ResourceFactory de WS-Transfer (tipos incorporados: user, computer, group, OU, container; u objetos personalizados desde una plantilla YAML mediante IMDA AddRequest)delete: elimina un objeto por DN mediante WS-Transfer Deleteattr: añade, reemplaza o elimina valores de atributos individuales en un objeto existente mediante WS-Transfer Put$ go install github.com/Macmod/sopa/cmd/sopa@latest
# Los flags de autenticación (-u, -p, -d, -k, -H, -c, ...) se omiten por brevedad - consulte la sección Autenticación.
# Buscar objetos por filtro LDAP
$ sopa [auth_flags] query --dc <DC> --filter '(objectClass=*)'
# Obtener un solo objeto por DN
$ sopa [auth_flags] get --dc <DC> --dn '<DN>'
# Eliminar un objeto por DN
$ sopa [auth_flags] delete --dc <DC> --dn '<DN>'
# Editar valores de atributos
$ sopa [auth_flags] attr add --dc <DC> --dn '<DN>' --attr <ATTR> --value <VALUE>
$ sopa [auth_flags] attr replace --dc <DC> --dn '<DN>' --attr <ATTR> --value <VALUE>
$ sopa [auth_flags] attr delete --dc <DC> --dn '<DN>' --attr <ATTR>
# Crear objetos
$ sopa [auth_flags] create user --dc <DC> --name <CN> --pass <INITIAL_PASS>
$ sopa [auth_flags] create computer --dc <DC> --name <CN>
$ sopa [auth_flags] create group --dc <DC> --name <CN> --type GlobalSecurity
$ sopa [auth_flags] create ou --dc <DC> --name <CN>
$ sopa [auth_flags] create container --dc <DC> --name <CN>
$ sopa [auth_flags] create custom --dc <DC> --template <TEMPLATE.yaml>
# Establecer / cambiar contraseñas de cuenta (MS-ADCAP)
$ sopa [auth_flags] set-password --dc <DC> --dn '<DN>' --new <NEW_PASS>
$ sopa [auth_flags] change-password --dc <DC> --dn '<DN>' --old <OLD_PASS> --new <NEW_PASS>
# Traducir DN <-> nombre canónico (MS-ADCAP)
# (esta llamada es mayormente inútil pero se mantiene por completitud 😄)
$ sopa [auth_flags] translate-name --dc <DC> --offered DistinguishedName --desired CanonicalName '<DN>'
# Membresías de grupo de un principal (MS-ADCAP)
$ sopa [auth_flags] groups --dc <DC> --dn '<DN>' --membership --authz
# Miembros de un grupo (MS-ADCAP)
$ sopa [auth_flags] members --dc <DC> --dn '<GROUP_DN>' --recursive
# Activar/desactivar característica opcional de AD, ej. Papelera de reciclaje (MS-ADCAP)
$ sopa [auth_flags] optfeature --dc <DC> --feature-id <FEATURE_GUID> --enable
# Información de topología (MS-ADCAP)
$ sopa [auth_flags] info version --dc <DC>
$ sopa [auth_flags] info domain --dc <DC>
$ sopa [auth_flags] info forest --dc <DC>
$ sopa [auth_flags] info dcs --dc <DC>
# Metadatos del endpoint del servicio ADWS (no autenticado - no se necesitan flags de autenticación)
$ sopa mex --dc <DC>
Ejecute sopa sin un subcomando para abrir un shell interactivo. Reutiliza una única conexión para todos los comandos y proporciona autocompletado con tabulación.
$ sopa --dc <DC> -u <USER> -p <PASS> -d <DOMAIN>
sopa v1.1.0
Connected dc.corp.local domain=corp.local user=Administrator
Type 'help' for commands or 'exit' to quit.
[corp.local]> query --filter '(objectClass=user)' --attrs sAMAccountName
[corp.local]> get --dn 'CN=Administrator,CN=Users,DC=corp,DC=local'
[corp.local]> exit
Use exit, quit o Ctrl-D para salir del shell.
Plantilla de ejemplo: examples/custom-create.example.yaml
Esquema de la plantilla (YAML):
parentDN (cadena, obligatorio): DN del contenedorrdn (cadena, obligatorio): DN relativo para el nuevo objeto (ej. CN=Foo)attributes (lista, obligatorio): cada elemento tiene:
name (cadena, obligatorio): nombre del atributo (cn o addata:cn)type (cadena, opcional): string|int|bool|base64|hex (o xsd:* explícito), por defecto stringvalue (cadena) o values (lista de cadenas)Notas:
ad:relativeDistinguishedName ni ad:container-hierarchy-parent en la plantilla (se inyectan automáticamente).hex se convierten a xsd:base64Binary.value: "".--dc acepta un FQDN, una dirección IP, o puede omitirse.
Debido a que el nombre de host del DC a veces no está disponible desde el DNS predeterminado de la red, se recomienda encarecidamente pasar siempre --dns <DC-IP> para que sopa use el propio servidor DNS del DC para todas las resoluciones:
# Opción 1: dejar que sopa resuelva todo a través del DNS del DC
$ sopa query --dns 192.168.1.10 -d corp.local -u user -p pass --filter '(objectClass=user)'
Cuando se omite --dc y se proporciona --domain, sopa descubre un DC
automáticamente consultando registros SRV:
_ldap._tcp.<domain> (intentado primero)
_kerberos._tcp.<domain> (fallback)
Se utiliza el destino del registro de mayor prioridad. Esto requiere que el
servidor DNS apuntado por --dns pueda responder esas consultas SRV; el propio
servidor DNS integrado del DC (cuando está presente) debería ser capaz de ello.
# Opción 2: proporcionar DC explícitamente sin Kerberos
$ sopa info version --dc 192.168.1.10 --domain corp.local -u user -p pass
Cuando se proporciona una IP para --dc, la IP siempre se resuelve a un FQDN mediante una consulta PTR inversa; el filtro de dirección WCF del endpoint ADWS requiere un FQDN en el encabezado wsa:To independientemente del método de autenticación.
Esta consulta PTR también pasa por --dns, por lo que se requiere una zona
inversa correctamente configurada en el DC:
# Opción 3: entrada IP - la consulta PTR resuelve 192.168.1.10 -> dc.corp.local
$ sopa info version --dc 192.168.1.10 --dns 192.168.1.10 --domain corp.local -u user -p pass
Todas las operaciones DNS en la pila (descubrimiento de DC, resolución PTR, conexión TCP ADWS y conexiones KDC de Kerberos) utilizan el mismo resolvedor construido a partir de --dns / --dns-tcp.
sopa soporta los siguientes modos de credenciales:
# Contraseña
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -p <PASS> <subcommand> [...]
# Hash NT
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -H <NT_HASH> <subcommand> [...]
# Clave de sesión AES (Kerberos está implícito)
# 32 caracteres hex = AES-128, 64 caracteres hex = AES-256
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --aes-key <HEX_KEY> <subcommand> [...]
# Ccache de Kerberos (Kerberos está implícito)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -c <CCACHE_PATH> <subcommand> [...]
# Certificado PFX (Kerberos está implícito / vía PKINIT)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --pfx <CERT.pfx> --pfx-password <PFX_PASS> <subcommand> [...]
# Certificado PEM (Kerberos está implícito / vía PKINIT)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --cert <CERT.pem> --key <KEY.pem> <subcommand> [...]
Todas las conexiones TCP (ADWS, Kerberos, DNS) pueden tunelizarse a través de un proxy SOCKS5 mediante -x / --socks5:
# Enrutar todo a través de un proxy SOCKS5
$ sopa -x 127.0.0.1:1080 --dc dc.corp.local -d corp.local -u user -p pass query --filter '(objectClass=user)'
# Usar el propio DNS del DC a través del proxy, luego conectar a través del proxy
$ sopa -x 127.0.0.1:1080 --dns 192.168.1.10 --dc 192.168.1.10 -d corp.local -u user -p pass query --filter '(objectClass=user)'
# Mantener DNS local (ej. DNS ya accesible sin proxy), solo proxy para conexiones TCP
$ sopa -x 127.0.0.1:1080 --no-proxy-dns --dc dc.corp.local -d corp.local -u user -p pass query --filter '(objectClass=user)'
Las contribuciones son bienvenidas abriendo un issue o enviando un pull request.
La idea de escribir esta herramienta surgió de una oleada de herramientas centradas en ADWS, principalmente con fines de evasión. En teoría, todo lo que se puede hacer con ellas también se puede hacer con sopa, pero si desea realizar acciones más complejas/específicas, écheles un vistazo también:
ssp implementó el flujo de autenticación con GSSAPI de manera fluida.La Licencia MIT (MIT)
Copyright (c) 2023 Artur Henrique Marzano Gonzaga
Por la presente se concede permiso, libre de cargos, a cualquier persona que obtenga una copia de este software y los archivos de documentación asociados (el "Software"), para manejar el Software sin restricción, incluyendo sin limitación los derechos de usar, copiar, modificar, fusionar, publicar, distribuir, sublicenciar y/o vender copias del Software, y para permitir a las personas a quienes se les proporcione el Software hacer lo mismo, sujeto a las siguientes condiciones:
El aviso de copyright anterior y este aviso de permiso deberán incluirse en todas las copias o partes sustanciales del Software.
EL SOFTWARE SE PROPORCIONA "TAL CUAL", SIN GARANTÍA DE NINGÚN TIPO, EXPRESA O IMPLÍCITA, INCLUYENDO PERO NO LIMITADO A GARANTÍAS DE COMERCIABILIDAD, IDONEIDAD PARA UN PROPÓSITO PARTICULAR Y NO INFRACCIÓN. EN NINGÚN CASO LOS AUTORES O TITULARES DEL COPYRIGHT SERÁN RESPONSABLES POR CUALQUIER RECLAMO, DAÑO U OTRA RESPONSABILIDAD, YA SEA EN UNA ACCIÓN DE CONTRATO, AGRAVIO O CUALQUIER OTRA ACCIÓN, DERIVADA DE, FUERA DE O EN CONEXIÓN CON EL SOFTWARE O SU USO U OTRO TIPO DE ACCIONES EN EL SOFTWARE.
set-password: establece una contraseña de cuenta mediante MS-ADCAP SetPasswordchange-password: cambia una contraseña de cuenta (requiere la contraseña anterior) mediante MS-ADCAP ChangePasswordtranslate-name: convierte entre DN y nombre canónico mediante TranslateNamegroups: lista membresías de grupo o grupos de autorización de un principal mediante GetADPrincipalGroupMembership / GetADPrincipalAuthorizationGroupmembers: enumera miembros de un grupo (opcionalmente recursivos) mediante GetADGroupMemberoptfeature: activa o desactiva características opcionales de AD (ej. Papelera de reciclaje) mediante ChangeOptionalFeatureinfo: recupera metadatos de topología (versión, dominio, bosque, lista de DC) mediante GetVersion, GetADDomain, GetADForest, GetADDomainControllersmex: obtiene metadatos del endpoint del servicio ADWS mediante una solicitud WS-MetadataExchange no autenticada| Flag | Descripción |
|---|
--dns <host[:port]> | Servidor DNS personalizado para todas las consultas (SRV, PTR, directas). Puerto por defecto 53. |
--dns-tcp | Forzar consultas DNS sobre TCP en lugar de UDP. Útil cuando UDP está bloqueado o las respuestas SRV son grandes. |
-x / --socks5 <host:port> | Enrutar todas las conexiones TCP a través de un proxy SOCKS5. Las consultas DNS también se tunelizan a través del proxy a menos que se establezca --no-proxy-dns. |
--no-proxy-dns | Cuando --socks5 está activo, resolver DNS a través del resolvedor local del sistema en lugar del proxy. |
--dns-timeout <duration> | Tiempo de espera para operaciones DNS (por defecto 10s). |
--tcp-timeout <duration> | Tiempo de espera para conexión TCP y operaciones del protocolo ADWS (por defecto 30s). |