Macmod/sopa

GitHub: Macmod/sopa

Sopa 是一个基于 Golang 实现的 ADWS 协议客户端,用于通过 SOAP/Web Services 接口对 Active Directory 进行查询、对象管理和拓扑信息检索。

Stars: 54 | Forks: 1

sopa

A practical client for ADWS in Golang.

GitHub Release Go Version Code Size License Build Status Go Report Card GitHub Downloads Twitter Follow

Sopa 实现了 ADWS 协议栈([MS-NNS](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nns) + [MC-NMF](https://learn.microsoft.com/en-us/openspecs/windows_protocols/mc-nmf) + SOAP),提供以下命令行功能: - **对象搜索与检索** - `query`:通过 WS-Enumeration `Enumerate` + `Pull` 循环运行 LDAP 过滤器搜索,支持属性投影、范围控制(Base/OneLevel/Subtree)和分页 - `get`:通过 WS-Transfer `Get` 根据 DN 获取单个对象 - **对象生命周期** - `create`:通过 WS-Transfer `ResourceFactory` 创建对象(内置类型:user、computer、group、OU、container;或通过 IMDA `AddRequest` 从 YAML 模板创建自定义对象) - `delete`:通过 WS-Transfer `Delete` 根据 DN 删除对象 - **属性编辑** - `attr`:通过 WS-Transfer `Put` 在现有对象上添加、替换或删除单个属性值 - **账户管理** - `set-password`:通过 MS-ADCAP `SetPassword` 设置账户密码 - `change-password`:通过 MS-ADCAP `ChangePassword` 更改账户密码(需要旧密码) - **ADCAP 自定义操作** - `translate-name`:通过 `TranslateName` 在 DN 和规范名称格式之间进行转换 - `groups`:通过 `GetADPrincipalGroupMembership` / `GetADPrincipalAuthorizationGroup` 列出主体的组成员身份或授权组 - `members`:通过 `GetADGroupMember` 枚举组成员(可选择递归) - `optfeature`:通过 `ChangeOptionalFeature` 切换可选的 AD 功能(例如 Recycle Bin) - `info`:通过 `GetVersion`、`GetADDomain`、`GetADForest`、`GetADDomainControllers` 检索拓扑元数据(版本、域、林、DC 列表) - **服务元数据** - `mex`:通过未经身份验证的 WS-MetadataExchange 请求获取 ADWS 服务端点元数据 # 安装说明 ``` $ go install github.com/Macmod/sopa/cmd/sopa@latest ``` # 用法 ``` # 为简洁起见,Auth flags (-u, -p, -d, -k, -H, -c, ...) 已省略 - 参见 Authentication 部分。 # 通过 LDAP filter 搜索对象 $ sopa [auth_flags] query --dc --filter '(objectClass=*)' # 通过 DN 获取单个对象 $ sopa [auth_flags] get --dc --dn '' # 通过 DN 删除对象 $ sopa [auth_flags] delete --dc --dn '' # 编辑属性值 $ sopa [auth_flags] attr add --dc --dn '' --attr --value $ sopa [auth_flags] attr replace --dc --dn '' --attr --value $ sopa [auth_flags] attr delete --dc --dn '' --attr # 创建对象 $ sopa [auth_flags] create user --dc --name --pass $ sopa [auth_flags] create computer --dc --name $ sopa [auth_flags] create group --dc --name --type GlobalSecurity $ sopa [auth_flags] create ou --dc --name $ sopa [auth_flags] create container --dc --name $ sopa [auth_flags] create custom --dc --template # 设置 / 更改账户密码 (MS-ADCAP) $ sopa [auth_flags] set-password --dc --dn '' --new $ sopa [auth_flags] change-password --dc --dn '' --old --new # DN <-> 规范名称转换 (MS-ADCAP) # (此调用基本没用,但为了完整性予以保留 😄) $ sopa [auth_flags] translate-name --dc --offered DistinguishedName --desired CanonicalName '' # Principal 的组成员身份 (MS-ADCAP) $ sopa [auth_flags] groups --dc --dn '' --membership --authz # 组成员 (MS-ADCAP) $ sopa [auth_flags] members --dc --dn '' --recursive # 切换可选的 AD 功能,例如 Recycle Bin (MS-ADCAP) $ sopa [auth_flags] optfeature --dc --feature-id --enable # Topology 信息 (MS-ADCAP) $ sopa [auth_flags] info version --dc $ sopa [auth_flags] info domain --dc $ sopa [auth_flags] info forest --dc $ sopa [auth_flags] info dcs --dc # ADWS 服务端点元数据(无需认证 - 不需要 auth flags) $ sopa mex --dc ``` ## 交互式 shell 运行 `sopa` 而不加子命令即可打开交互式 shell。它会在所有命令中复用单个连接,并提供 Tab 补全功能。 ``` $ sopa --dc -u -p -d 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 ``` 使用 `exit`、`quit` 或 Ctrl-D 退出 shell。 ## 自定义对象创建 模板示例:[examples/custom-create.example.yaml](examples/custom-create.example.yaml) 模板 schema(YAML): - `parentDN`(字符串,必填):容器 DN - `rdn`(字符串,必填):新对象的相对 DN(例如 `CN=Foo`) - `attributes`(列表,必填):每一项包含: - `name`(字符串,必填):属性名称(`cn` 或 `addata:cn`) - `type`(字符串,可选):`string|int|bool|base64|hex`(或明确的 `xsd:*`),默认为 `string` - `value`(字符串)或 `values`(字符串列表) 注意事项: - 不要在模板中包含 `ad:relativeDistinguishedName` 或 `ad:container-hierarchy-parent`(它们会被自动注入)。 - `hex` 值会被转换为 `xsd:base64Binary`。 - 要显式设置空字符串,请使用 `value: ""`。 ## DC 发现与 DNS `--dc` 接受 **FQDN**、**IP 地址**,或者可以**省略**。 由于从网络的默认 DNS 有时无法获取 DC 的主机名,强烈建议始终传入 `--dns `,以便 sopa 在所有查找中使用 DC 自身的 DNS 服务器: ``` # 选项 1:让 sopa 通过 DC 的 DNS 解析所有内容 $ sopa query --dns 192.168.1.10 -d corp.local -u user -p pass --filter '(objectClass=user)' ``` 当省略 `--dc` 并提供 `--domain` 时,sopa 会通过查询 SRV 记录自动发现 DC: ``` _ldap._tcp. (tried first) _kerberos._tcp. (fallback) ``` 将使用最高优先级记录的目标。这要求由 `--dns` 指向的 DNS 服务器能够应答这些 SRV 查询——DC 自身的集成 DNS 服务器(如果存在)应该具备此能力。 ``` # 选项 2:显式提供 DC 且不使用 Kerberos $ sopa info version --dc 192.168.1.10 --domain corp.local -u user -p pass ``` 当为 `--dc` 提供 IP 时,始终会通过**反向 PTR 查询**将该 IP 解析为 FQDN——无论采用何种身份验证方法,ADWS 端点的 WCF 地址过滤器都要求在 `wsa:To` 标头中提供 FQDN。 此 PTR 查询也会通过 `--dns` 进行,因此要求 DC 上配置了正确的反向区域: ``` # 选项 3:IP 输入 - PTR 查找解析 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 ``` 协议栈中的所有 DNS 操作——DC 发现、PTR 解析、ADWS TCP 拨号以及 Kerberos KDC 连接——都使用由 `--dns` / `--dns-tcp` 构建的同一个解析器。 | 标志 | 描述 | |------|-------------| | `--dns ` | 用于所有查找(SRV、PTR、正向)的自定义 DNS 服务器。默认端口为 53。 | | `--dns-tcp` | 强制通过 TCP 而非 UDP 进行 DNS 查询。适用于 UDP 被阻止或 SRV 响应过大的情况。 | | `-x / --socks5 ` | 通过 SOCKS5 代理路由所有 TCP 连接。除非设置了 `--no-proxy-dns`,否则 DNS 查询也将通过代理进行隧道传输。 | | `--no-proxy-dns` | 当 `--socks5` 处于活动状态时,通过本地系统解析器解析 DNS,而不是通过代理。 | | `--dns-timeout ` | DNS 操作的超时时间(默认为 10 秒)。 | | `--tcp-timeout ` | TCP 拨号和 ADWS 协议操作的超时时间(默认为 30 秒)。 | # 身份验证 `sopa` 支持以下凭据模式: ``` # 密码 $ sopa --dc -d -u -p [...] # NT hash $ sopa --dc -d -u -H [...] # AES session key(隐含 Kerberos) # 32 位 hex chars = AES-128,64 位 hex chars = AES-256 $ sopa --dc -d -u --aes-key [...] # Kerberos ccache(隐含 Kerberos) $ sopa --dc -d -u -c [...] # PFX 证书(隐含 Kerberos / 通过 PKINIT) $ sopa --dc -d -u --pfx --pfx-password [...] # PEM 证书(隐含 Kerberos / 通过 PKINIT) $ sopa --dc -d -u --cert --key [...] ``` # SOCKS5 所有 TCP 连接(ADWS、Kerberos、DNS)均可通过 `-x` / `--socks5` 经由 SOCKS5 代理进行隧道传输: ``` # 通过 SOCKS5 proxy 路由所有流量 $ sopa -x 127.0.0.1:1080 --dc dc.corp.local -d corp.local -u user -p pass query --filter '(objectClass=user)' # 通过代理使用 DC 自己的 DNS,然后通过代理进行连接 $ 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)' # 保持 DNS 本地解析(例如 DNS 已经可以在没有代理的情况下访问),仅对 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)' ``` # 其他 ADWS 工具 编写此工具的想法源于一波主要用于规避目的的 ADWS 专用工具浪潮。理论上,使用这些工具可以做到的事情,同样也可以使用 `sopa` 完成,但如果您想执行更复杂或特定的操作,也请查看它们: * [wh0amitz/SharpADWS](https://github.com/wh0amitz/SharpADWS) * [logangoins/SOAPy](https://github.com/logangoins/SOAPy) * [FalconForceTeam/SOAPHound](https://github.com/FalconForceTeam/SOAPHound) * [mverschu/adwsdomaindump](https://github.com/mverschu/adwsdomaindump) # 参考资料 - [MS-NNS](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nns):.NET NegotiateStream Protocol - [MS-NMF](https://learn.microsoft.com/en-us/openspecs/windows_protocols/mc-nmf):.NET Message Framing Protocol - [MS-ADDM](https://learn.microsoft.com/zh-cn/openspecs/windows_protocols/ms-addm):Active Directory Web Services: Data Model and Common Elements - [MS-WSDS](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wsds):WS-Enumeration: Directory Services Protocol Extensions - [MS-WSTIM](https://learn.microsoft.com/zh-cn/openspecs/windows_protocols/ms-wstim):WS-Transfer: Identity Management Operations for Directory Access Extensions - [MS-ADCAP](https://learn.microsoft.com/zh-cn/openspecs/windows_protocols/ms-adcap):Active Directory Web Services Custom Action Protocol - [MS-ADTS](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts):Active Directory Technical Specification # 许可证 The MIT License (MIT) 版权所有 (c) 2023 Artur Henrique Marzano Gonzaga 特此向任何获得本软件及相关文档文件(以下简称“软件”)副本的人免费授予许可,允许其无限制地使用本软件,包括但不限于使用、复制、修改、合并、发布、分发、再授权和/或销售软件副本的权利,并允许向其提供软件的人员在满足以下条件的前提下这样做: 上述版权声明和本许可声明应包含在软件的所有副本或重要部分中。 本软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、特定用途适用性和非侵权性的保证。在任何情况下,作者或版权持有人均不对因本软件或使用本软件或其他交易引起的或与之相关的任何索赔、损害或其他责任承担责任,无论是在合同诉讼、侵权行为还是其他诉讼中。
标签:Active Directory, ADWS协议, EVTX分析, Golang, HTTP, Plaso, 安全编程, 目录服务, 网络客户端