
Um cliente prático para ADWS em Golang.
Um cliente prático para ADWS em Golang.
Sopa implementa a pilha de protocolos ADWS (MS-NNS + MC-NMF + SOAP), expondo os seguintes recursos de linha de comando:
query: executa buscas por filtro LDAP via loop Enumerate + Pull do WS-Enumeration com projeção de atributos, controle de escopo (Base/OneLevel/Subtree) e paginaçãoget: obtém um único objeto por DN via WS-Transfer Getcreate: cria objetos via ResourceFactory do WS-Transfer (tipos internos: user, computer, group, OU, container; ou objetos personalizados a partir de um template YAML via IMDA AddRequest)delete: remove um objeto por DN via WS-Transfer Deleteattr: adiciona, substitui ou remove valores individuais de atributos em um objeto existente via WS-Transfer Put$ go install github.com/Macmod/sopa/cmd/sopa@latest
# Auth flags (-u, -p, -d, -k, -H, -c, ...) are omitted for brevity - see Authentication section.
# Search objects by LDAP filter
$ sopa [auth_flags] query --dc <DC> --filter '(objectClass=*)'
# Fetch a single object by DN
$ sopa [auth_flags] get --dc <DC> --dn '<DN>'
# Delete an object by DN
$ sopa [auth_flags] delete --dc <DC> --dn '<DN>'
# Edit attribute values
$ 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>
# Create objects
$ 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>
# Set / change account passwords (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>
# Translate DN <-> canonical name (MS-ADCAP)
# (this call is mostly useless but kept for completeness 😄)
$ sopa [auth_flags] translate-name --dc <DC> --offered DistinguishedName --desired CanonicalName '<DN>'
# Principal group memberships (MS-ADCAP)
$ sopa [auth_flags] groups --dc <DC> --dn '<DN>' --membership --authz
# Group members (MS-ADCAP)
$ sopa [auth_flags] members --dc <DC> --dn '<GROUP_DN>' --recursive
# Toggle optional AD feature, e.g. Recycle Bin (MS-ADCAP)
$ sopa [auth_flags] optfeature --dc <DC> --feature-id <FEATURE_GUID> --enable
# Topology info (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>
# ADWS service endpoint metadata (unauthenticated - auth flags not needed)
$ sopa mex --dc <DC>
Execute sopa sem um subcomando para abrir um shell interativo. Ele reutiliza uma única conexão para todos os comandos e oferece preenchimento com tab.
$ 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 ou Ctrl-D para sair do shell.
Exemplo de template: examples/custom-create.example.yaml
Esquema do template (YAML):
parentDN (string, obrigatório): DN do contêinerrdn (string, obrigatório): DN relativo para o novo objeto (ex.: CN=Foo)attributes (lista, obrigatório): cada item possui:
name (string, obrigatório): nome do atributo (cn ou addata:cn)type (string, opcional): string|int|bool|base64|hex (ou xsd:* explícito), padrão stringvalue (string) ou values (lista de strings)Notas:
ad:relativeDistinguishedName ou ad:container-hierarchy-parent no template (são injetados automaticamente).hex são convertidos para xsd:base64Binary.value: "".--dc aceita um FQDN, um endereço IP ou pode ser omitido.
Como o hostname do DC às vezes não está disponível no DNS padrão da rede, é fortemente recomendado passar sempre --dns <IP-DO-DC> para que o sopa use o próprio servidor DNS do DC para todas as consultas:
# Opção 1: deixar o sopa resolver tudo através do DNS do DC
$ sopa query --dns 192.168.1.10 -d corp.local -u user -p pass --filter '(objectClass=user)'
Quando --dc é omitido e --domain é fornecido, o sopa descobre um DC
automaticamente consultando registros SRV:
_ldap._tcp.<domain> (tentado primeiro)
_kerberos._tcp.<domain> (fallback)
O destino do registro de maior prioridade é usado. Isso exige que o
servidor DNS apontado por --dns consiga responder a essas consultas SRV – o próprio
servidor DNS integrado do DC (quando presente) deve ser capaz disso.
# Opção 2: fornecer DC explicitamente sem Kerberos
$ sopa info version --dc 192.168.1.10 --domain corp.local -u user -p pass
Quando um IP é fornecido para --dc, o IP sempre é resolvido para um FQDN via uma consulta PTR reversa – o filtro de endereço WCF do endpoint ADWS exige um FQDN no cabeçalho wsa:To independentemente do método de autenticação.
Essa consulta PTR também passa por --dns, portanto, uma zona reversa
corretamente configurada no DC é necessária:
# Opção 3: entrada IP – consulta PTR resolve 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 as operações de DNS na pilha – descoberta de DC, resolução PTR, conexão TCP ADWS
e conexões KDC Kerberos – usam o mesmo resolvedor construído a partir de --dns /
--dns-tcp.
O sopa suporta os seguintes modos de credenciais:
# Password
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -p <PASS> <subcommand> [...]
# NT hash
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -H <NT_HASH> <subcommand> [...]
# AES session key (Kerberos is implied)
# 32 hex chars = AES-128, 64 hex chars = AES-256
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --aes-key <HEX_KEY> <subcommand> [...]
# Kerberos ccache (Kerberos is implied)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -c <CCACHE_PATH> <subcommand> [...]
# PFX certificate (Kerberos is implied / via PKINIT)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --pfx <CERT.pfx> --pfx-password <PFX_PASS> <subcommand> [...]
# PEM certificate (Kerberos is implied / via PKINIT)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --cert <CERT.pem> --key <KEY.pem> <subcommand> [...]
Todas as conexões TCP (ADWS, Kerberos, DNS) podem ser tuneladas através de um proxy SOCKS5 via -x / --socks5:
# Route everything through a SOCKS5 proxy
$ sopa -x 127.0.0.1:1080 --dc dc.corp.local -d corp.local -u user -p pass query --filter '(objectClass=user)'
# Use the DC's own DNS through the proxy, then connect via 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)'
# Keep DNS local (e.g. DNS already reachable without proxy), only proxy TCP connections
$ 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)'
Contribuições são bem-vindas através da abertura de uma issue ou envio de um pull request.
A ideia de escrever esta ferramenta veio de uma onda de ferramentas focadas em ADWS, principalmente para fins de evasão. Em teoria, tudo o que pode ser feito com essas ferramentas também pode ser feito com o sopa, mas se você deseja realizar ações mais complexas/específicas, confira-as também:
ssp implementou o fluxo de autenticação com GSSAPI de forma transparente.A Licença MIT (MIT)
Copyright (c) 2023 Artur Henrique Marzano Gonzaga
A permissão é concedida, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e dos arquivos de documentação associados (o "Software"), para lidar com o Software sem restrições, incluindo, sem limitação, os direitos de usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender cópias do Software, e permitir que pessoas a quem o Software seja fornecido o façam, sujeitas às seguintes condições:
O aviso de copyright acima e este aviso de permissão devem ser incluídos em todas as cópias ou partes substanciais do Software.
O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO FIM E NÃO VIOLAÇÃO. EM NENHUM CASO OS AUTORES OU DETENTORES DOS DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUALQUER REIVINDICAÇÃO, DANOS OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ATO ILÍCITO OU DE OUTRA FORMA, DECORRENTE DE, OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTRAS NEGOCIAÇÕES NO SOFTWARE.
set-password: define uma senha de conta via MS-ADCAP SetPasswordchange-password: altera a senha de uma conta (requer a senha antiga) via MS-ADCAP ChangePasswordtranslate-name: converte entre formatos DN e nome canônico via TranslateNamegroups: lista associações a grupos ou grupos de autorização de um principal via GetADPrincipalGroupMembership / GetADPrincipalAuthorizationGroupmembers: enumera membros de um grupo (opcionalmente recursivo) via GetADGroupMemberoptfeature: ativa/desativa recursos opcionais do AD (ex.: Lixeira) via ChangeOptionalFeatureinfo: recupera metadados de topologia (versão, domínio, floresta, lista de DCs) via GetVersion, GetADDomain, GetADForest, GetADDomainControllersmex: obtém metadados do endpoint do serviço ADWS via uma requisição WS-MetadataExchange não autenticada| Bandeira | Descrição |
|---|
--dns <host[:porta]> | Servidor DNS personalizado para todas as consultas (SRV, PTR, direta). Padrão para porta 53. |
--dns-tcp | Forçar consultas DNS via TCP em vez de UDP. Útil quando UDP está bloqueado ou as respostas SRV são grandes. |
-x / --socks5 <host:porta> | Roteia todas as conexões TCP através de um proxy SOCKS5. Consultas DNS também são tuneladas através do proxy, a menos que --no-proxy-dns esteja definido. |
--no-proxy-dns | Quando --socks5 está ativo, resolve DNS através do resolvedor local do sistema em vez do proxy. |
--dns-timeout <duração> | Tempo limite para operações de DNS (padrão 10s). |
--tcp-timeout <duração> | Tempo limite para dial TCP e operações do protocolo ADWS (padrão 30s). |