
Un client pratique pour ADWS en Golang.
Un client pratique pour ADWS en Golang.
Sopa implémente la pile de protocoles ADWS (MS-NNS + MC-NMF + SOAP), exposant les fonctionnalités en ligne de commande suivantes :
query : exécute des recherches par filtre LDAP via une boucle WS-Enumeration Enumerate + Pull avec projection d'attributs, contrôle de portée (Base/OneLevel/Subtree) et paginationget : récupère un seul objet par DN via WS-Transfer Getcreate : crée des objets via WS-Transfer ResourceFactory (types intégrés : user, computer, group, OU, container ; ou objets personnalisés à partir d'un modèle YAML via IMDA AddRequest)delete : supprime un objet par DN via WS-Transfer Deleteattr : ajoute, remplace ou supprime des valeurs d'attributs individuelles sur un objet existant via WS-Transfer Put$ go install github.com/Macmod/sopa/cmd/sopa@latest
# Les flags d'authentification (-u, -p, -d, -k, -H, -c, ...) sont omis par souci de concision - voir la section Authentification.
# Rechercher des objets par filtre LDAP
$ sopa [auth_flags] query --dc <DC> --filter '(objectClass=*)'
# Récupérer un seul objet par DN
$ sopa [auth_flags] get --dc <DC> --dn '<DN>'
# Supprimer un objet par DN
$ sopa [auth_flags] delete --dc <DC> --dn '<DN>'
# Modifier les valeurs d'attributs
$ 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>
# Créer des objets
$ 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>
# Définir / changer les mots de passe des comptes (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>
# Traduire DN <-> nom canonique (MS-ADCAP)
# (cet appel est surtout inutile mais conservé pour l'exhaustivité 😄)
$ sopa [auth_flags] translate-name --dc <DC> --offered DistinguishedName --desired CanonicalName '<DN>'
# Appartenances aux groupes d'un principal (MS-ADCAP)
$ sopa [auth_flags] groups --dc <DC> --dn '<DN>' --membership --authz
# Membres d'un groupe (MS-ADCAP)
$ sopa [auth_flags] members --dc <DC> --dn '<GROUP_DN>' --recursive
# Activer/désactiver une fonctionnalité AD optionnelle, ex. Corbeille (MS-ADCAP)
$ sopa [auth_flags] optfeature --dc <DC> --feature-id <FEATURE_GUID> --enable
# Informations de topologie (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>
# Métadonnées du point de terminaison du service ADWS (non authentifié - les flags d'auth ne sont pas nécessaires)
$ sopa mex --dc <DC>
Lancez sopa sans sous-commande pour ouvrir un shell interactif. Il réutilise une seule connexion pour toutes les commandes et fournit l'autocomplétion par tabulation.
$ sopa --dc <DC> -u <USER> -p <PASS> -d <DOMAIN>
sopa v1.1.0
Connecté dc.corp.local domaine=corp.local utilisateur=Administrator
Tapez 'help' pour les commandes ou 'exit' pour quitter.
[corp.local]> query --filter '(objectClass=user)' --attrs sAMAccountName
[corp.local]> get --dn 'CN=Administrator,CN=Users,DC=corp,DC=local'
[corp.local]> exit
Utilisez exit, quit ou Ctrl-D pour quitter le shell.
Exemple de modèle : examples/custom-create.example.yaml
Schéma du modèle (YAML) :
parentDN (chaîne, obligatoire) : DN du conteneurrdn (chaîne, obligatoire) : DN relatif pour le nouvel objet (ex. CN=Foo)attributes (liste, obligatoire) : chaque élément a :
name (chaîne, obligatoire) : nom de l'attribut (cn ou addata:cn)type (chaîne, optionnel) : string|int|bool|base64|hex (ou explicite xsd:*), par défaut stringvalue (chaîne) soit values (liste de chaînes)Remarques :
ad:relativeDistinguishedName ou ad:container-hierarchy-parent dans le modèle (ils sont injectés automatiquement).hex sont converties en xsd:base64Binary.value: "".--dc accepte un FQDN, une adresse IP, ou peut être omis.
Comme le nom d'hôte du DC n'est parfois pas disponible depuis le DNS par défaut du réseau, il est fortement recommandé de toujours passer --dns <DC-IP> afin que sopa utilise le propre serveur DNS du DC pour toutes les résolutions :
# Option 1 : laisser sopa tout résoudre via le DNS du DC
$ sopa query --dns 192.168.1.10 -d corp.local -u user -p pass --filter '(objectClass=user)'
Lorsque --dc est omis et que --domain est fourni, sopa découvre un DC
automatiquement en interrogeant les enregistrements SRV :
_ldap._tcp.<domain> (essayé en premier)
_kerberos._tcp.<domain> (solution de repli)
La cible de l'enregistrement avec la priorité la plus élevée est utilisée. Cela nécessite que le
serveur DNS pointé par --dns puisse répondre à ces requêtes SRV - le propre serveur DNS intégré
du DC (lorsqu'il est présent) devrait être capable de le faire.
# Option 2 : fournir le DC explicitement sans Kerberos
$ sopa info version --dc 192.168.1.10 --domain corp.local -u user -p pass
Lorsqu'une IP est fournie pour --dc, cette IP est toujours résolue en un FQDN via une recherche PTR inverse - le filtre d'adresse WCF du point de terminaison ADWS nécessite un FQDN dans l'en-tête wsa:To, quel que soit le mode d'authentification.
Cette recherche PTR passe également par --dns, donc une zone inverse correctement configurée
sur le DC est nécessaire :
# Option 3 : entrée IP - la recherche PTR résout 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
Toutes les opérations DNS dans la pile - découverte du DC, résolution PTR, connexion TCP ADWS,
et connexions KDC Kerberos - utilisent le même résolveur construit à partir de --dns /
--dns-tcp.
sopa prend en charge les modes d'identification suivants :
# Mot de passe
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -p <PASS> <subcommand> [...]
# Hachage NT
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -H <NT_HASH> <subcommand> [...]
# Clé de session AES (Kerberos est implicite)
# 32 caractères hex = AES-128, 64 caractères hex = AES-256
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --aes-key <HEX_KEY> <subcommand> [...]
# Cache Kerberos ccache (Kerberos est implicite)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> -c <CCACHE_PATH> <subcommand> [...]
# Certificat PFX (Kerberos est implicite / via PKINIT)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --pfx <CERT.pfx> --pfx-password <PFX_PASS> <subcommand> [...]
# Certificat PEM (Kerberos est implicite / via PKINIT)
$ sopa --dc <DC> -d <DOMAIN> -u <USER> --cert <CERT.pem> --key <KEY.pem> <subcommand> [...]
Toutes les connexions TCP (ADWS, Kerberos, DNS) peuvent être tunnelées via un proxy SOCKS5 avec -x / --socks5 :
# Acheminer tout via 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)'
# Utiliser le propre DNS du DC via le proxy, puis se connecter via le 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)'
# Garder le DNS local (ex. DNS déjà accessible sans proxy), uniquement proxy les connexions 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)'
Les contributions sont les bienvenues en ouvrant un problème ou en soumettant une demande de tirage.
L'idée d'écrire cet outil est venue d'une vague d'outils axés sur ADWS, principalement à des fins d'évasion. En théorie, tout ce qui peut être fait avec ces outils peut aussi être fait avec sopa, mais si vous souhaitez effectuer des actions plus complexes/spécifiques, jetez également un œil à ceux-ci :
ssp a implémenté le flux d'authentification avec GSSAPI de manière transparente.Licence MIT (MIT)
Copyright (c) 2023 Artur Henrique Marzano Gonzaga
Par la présente, une autorisation est accordée, gratuitement, à toute personne obtenant une copie de ce logiciel et des fichiers de documentation associés (le "Logiciel"), de traiter le Logiciel sans restriction, y compris, sans limitation, les droits d'utiliser, copier, modifier, fusionner, publier, distribuer, sous-licencier et/ou vendre des copies du Logiciel, et d'autoriser les personnes auxquelles le Logiciel est fourni à le faire, sous réserve des conditions suivantes :
L'avis de copyright ci-dessus et cet avis d'autorisation doivent être inclus dans toutes les copies ou parties substantielles du Logiciel.
LE LOGICIEL EST FOURNI "EN L'ÉTAT", SANS GARANTIE D'AUCUNE SORTE, EXPRESSE OU IMPLICITE, Y COMPRIS, MAIS SANS S'Y LIMITER, LES GARANTIES DE QUALITÉ MARCHANDE, D'ADÉQUATION À UN USAGE PARTICULIER ET D'ABSENCE DE CONTREFAÇON. EN AUCUN CAS LES AUTEURS OU TITULAIRES DU COPYRIGHT NE POURRONT ÊTRE TENUS RESPONSABLES DE TOUTE RÉCLAMATION, DOMMAGE OU AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D'UNE ACTION CONTRACTUELLE, DÉLICTUELLE OU AUTRE, DÉCOULANT DE, OU EN RELATION AVEC LE LOGICIEL OU SON UTILISATION OU AUTRES INTERACTIONS AVEC LE LOGICIEL.
set-password : définit un mot de passe de compte via MS-ADCAP SetPasswordchange-password : change un mot de passe de compte (nécessite l'ancien mot de passe) via MS-ADCAP ChangePasswordtranslate-name : convertit entre les formats DN et nom canonique via TranslateNamegroups : liste les appartenances aux groupes ou les groupes d'autorisation d'un principal via GetADPrincipalGroupMembership / GetADPrincipalAuthorizationGroupmembers : énumère les membres d'un groupe (optionnellement récursif) via GetADGroupMemberoptfeature : active/désactive les fonctionnalités AD optionnelles (ex. Corbeille) via ChangeOptionalFeatureinfo : récupère les métadonnées de topologie (version, domaine, forêt, liste des DC) via GetVersion, GetADDomain, GetADForest, GetADDomainControllersmex : récupère les métadonnées du point de terminaison du service ADWS via une requête WS-MetadataExchange non authentifiée| Drapeau | Description |
|---|
--dns <host[:port]> | Serveur DNS personnalisé pour toutes les recherches (SRV, PTR, directe). Par défaut, port 53. |
--dns-tcp | Forcer les requêtes DNS sur TCP au lieu d'UDP. Utile lorsque l'UDP est bloqué ou que les réponses SRV sont volumineuses. |
-x / --socks5 <host:port> | Acheminer toutes les connexions TCP via un proxy SOCKS5. Les requêtes DNS sont également tunnelées via le proxy sauf si --no-proxy-dns est défini. |
--no-proxy-dns | Lorsque --socks5 est actif, résoudre le DNS via le résolveur système local au lieu du proxy. |
--dns-timeout <duration> | Délai d'expiration pour les opérations DNS (par défaut 10s). |
--tcp-timeout <duration> | Délai d'expiration pour la connexion TCP et les opérations du protocole ADWS (par défaut 30s). |