最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
powerview.py:实践指南
时间:2026-09-11 17:36:02 编辑:袖梨 来源:一聚教程网
工作中遇到相关需求时,powerview.py值得先读说明,因为它主要用于Powerview 增强版。在日常自动化场景里,常见问题是输入边界、依赖和失败处理如果不清楚就很难稳定复用,这正是评估时需要盯住的地方。更实际的做法是用一项范围明确的真实任务完成最小试跑,同时核对配置时间、输出质量、异常信息和维护痕迹,不要直接在关键项目上。我会把它列入愿意先做小范围验证并复查原始文档的团队的候选清单,而不是仅凭项目介绍直接纳入生产。

安装 | 基本用法 | 混淆 | 模块 | 日志记录 | 用户定义规则 | MCP | 插件 | 致谢
概述
PowerView.py 是很棒的原始 PowerView.ps1 脚本的替代品。 PowerView 中使用的大多数模块都可以在这里找到(一些标志已更改)。主要目标是实现交互式会话,而无需重复向 ldap 进行身份验证。
安装
https://github.com/aniqfakhrul/powerview.py/wiki/Installation-Guide
基本用法
[!NOTE] 请注意,一些 kerberos 功能仍然无法正常运行,但它仍然可以完成大部分工作。详细用法可以参见Wiki部分
- 初始化连接
powerview range.net/lowpriv:[email protected] [-k] [--use-ldap | --使用 ldaps | --使用GC | --使用-gc-ldaps | --使用-adws]
- 保持持久连接
[!TIP] 默认情况下禁用连接持久性。 LDAP 会话在不活动后超时。使用
--keepalive-interval发送维护会话状态的定期查询。
- 启动网页界面
powerview range.net/lowpriv:[email protected] --web [--web-host 0.0.0.0] [--web-port 3000] [--web-auth 用户:password1234]
- 使用特定身份验证初始化连接。请注意,仅当您直接从此 分支 安装
ldap3库时,--use-sign-and-seal和--use-channel-binding才可用
powerview range.net/lowpriv:[email protected] [--使用通道绑定 | --使用签名和盖章 | --使用简单身份验证]
- 使用 schannel 进行初始化。
--pfx标志接受 pfx 格式的证书文件。
[!NOTE]
powerview 将在第一次尝试时尝试加载没有密码的证书。如果失败,会提示输入密码。因此,不需要密码参数
powerview 10.10.10.10 --pfx administrator.pfx
- 查询特定用户
Get-DomainUser Administrator
Get-DomainUser -Identity Administrator
- 指定搜索属性
Get-DomainUser -Properties samaccountname,description
- 过滤结果
Get-DomainUser -Where 'samaccountname [contains][in][eq] admins'
- 计数结果
Get-DomainUser -Count
- 输出结果到文件
Get-DomainUser -OutFile ~/domain_user.txt
- 将输出格式化为表格。
Get-DomainUser -Properties samaccountname,memberof -TableView
Get-DomainUser -Properties samaccountname,memberof -TableView [csv,md,html,latex]
- 设置模块
Set-DomainObject -Identity "adminuser" -Set 'servicePrincipalname=http/web.ws.local'
Set-DomainObject -Identity "adminuser" -Append 'servicePrincipalname=http/web.ws.local'
Set-DomainObject -Identity "adminuser" -Clear 'servicePrincipalname'
# Reading from local file
Set-DomainObject -Identity "adminuser" -Set 'servicePrincipalname=@/path/to/local/file'
Set-DomainObject -Identity "adminuser" -Append 'servicePrincipalname=@/path/to/local/file'
- 中继方式
powerview 10.10.10.10 --relay [--relay-host] [--relay-port] [--use-ldap | --use-ldaps]
[!NOTE]
此演示显示使用printerbug.py进行强制身份验证。您可以使用强制 HTTP 身份验证的其他方法。
混淆
PowerView 使用 ldapx-py 来混淆 LDAP 查询和相关参数,在保留查询意图的同时改变可观察的模式。
- 通过 CLI 启用(默认链)
powerview range.net/lowpriv:[email protected] --obfuscate
- 通过 CLI 启用(自定义链码)
powerview range.net/lowpriv:[email protected] --obfuscate CZXANDR
- 通过网络启用
[!TIP] 在设置中切换
Obfuscate。这适用于活动会话的后续查询。
什么被混淆了
- 过滤器:发送前转换属性名称、运算符和值
- DN:改变搜索库 distinguishedName
- 属性:改变请求的属性列表
默认链(当使用没有值的 --obfuscate 时)
| 目标 | 链条 | 技巧 |
|---|---|---|
| 过滤器 | CZNDR |
案例,Zeros,aNR,德摩根,重新排序 |
| BaseDN | CX |
案例,heX编码 |
| 属性 | CR |
案例,重新订购 |
运行 ldapx codes --all 查看所有可用的混淆代码。
[!NOTE] 在大多数情况下,结果在功能上是等效的,但 approximation/wildcard 扩展可以扩大匹配范围。某些代码(G、O、S)可能与 ldap3 不兼容 - 请谨慎使用。
[!WARNING] 过度的混淆可能会被严格的服务器或中介工具拒绝。仅在需要时使用。
- ldapx-py:LDAP 查询混淆库 — https://github.com/j0hnZ3RA/ldapx-py
- ldapx:用于参考的灵活 LDAP 代理 — https://github.com/Macmod/ldapx
- 研究:MaLDAPtive:混淆与反混淆(DEF CON 32 讲)— https://[email protected]/watch?v=mKRS5Iyy7Qo
- 作者:Sabajete Elezaj — https://x.com/sabi_elezi, Daniel Bohannon — https://x.com/danielhbohannon
模块可用(到目前为止?)
PV >
Add-ADComputer Get-ADObject Get-EventLogChannel Login-As Set-ADObject
Add-ADUser Get-CA Get-EventLogPublisher Logoff-Session Set-ADObjectDN
Add-CATemplate Get-CATemplate Get-ExchangeDatabase Reboot-Computer Set-CATemplate
Add-CATemplateAcl Get-DMSA Get-ExchangeMailbox Remove-ADComputer Set-DomainCATemplate
Add-DMSA Get-Domain Get-ExchangeServer Remove-ADObject Set-DomainComputerPassword
Add-DomainCATemplate Get-DomainCA Get-GMSA Remove-ADUser Set-DomainDNSRecord
Add-DomainCATemplateAcl Get-DomainCATemplate Get-GPOLocalGroup Remove-CATemplate Set-DomainObject
Add-DomainComputer Get-DomainComputer Get-GPOSettings Remove-DMSA Set-DomainObjectDN
Add-DomainDMSA Get-DomainController Get-LocalUser Remove-DomainCATemplate Set-DomainObjectOwner
Add-DomainDNSRecord Get-DomainDMSA Get-NamedPipes Remove-DomainComputer Set-DomainRBCD
Add-DomainGMSA Get-DomainDNSRecord Get-NetComputerInfo Remove-DomainDMSA Set-DomainUserPassword
Add-DomainGPO Get-DomainDNSZone Get-NetLoggedOn Remove-DomainDNSRecord Set-NetService
Add-DomainGroup Get-DomainForeignGroupMember Get-NetProcess Remove-DomainGMSA Set-ObjectOwner
Add-DomainGroupMember Get-DomainForeignUser Get-NetService Remove-DomainGroupMember Set-RBCD
Add-DomainObjectAcl Get-DomainGMSA Get-NetSession Remove-DomainObject Set-ShadowCred
Add-DomainOU Get-DomainGPO Get-NetShare Remove-DomainObjectAcl Set-ShadowCredential
Add-DomainUser Get-DomainGPOLocalGroup Get-NetTerminalSession Remove-DomainOU Shutdown-Computer
Add-GMSA Get-DomainGPOSettings Get-ObjectAcl Remove-DomainUser Start-NetService
Add-GPLink Get-DomainGroup Get-ObjectOwner Remove-GMSA Stop-Computer
Add-GPO Get-DomainGroupMember Get-RBCD Remove-GPLink Stop-NetProcess
Add-GroupMember Get-DomainObject Get-RegLoggedOn Remove-GroupMember Stop-NetService
Add-NetService Get-DomainObjectAcl Get-SCCM Remove-NetService Unlock-ADAccount
Add-ObjectAcl Get-DomainObjectOwner Get-ShadowCred Remove-NetSession clear
Add-OU Get-DomainOU Get-ShadowCredential Remove-NetTerminalSession exit
Clear-Cache Get-DomainRBCD Get-TrustKey Remove-ObjectAcl get_pool_stats
ConvertFrom-SID Get-DomainSCCM Get-WDS Remove-OU history
ConvertFrom-UACValue Get-DomainTrust Invoke-ASREPRoast Remove-ShadowCred taskkill
Disable-DomainDNSRecord Get-DomainTrustKey Invoke-DFSCoerce Remove-ShadowCredential tasklist
Get-DomainTrustMapping
Find-ForeignGroup Get-DomainUser Invoke-Kerberoast Restart-Computer
Find-ForeignUser Get-DomainWDS Invoke-MessageBox Restore-ADObject
Find-LocalAdminAccess Get-EventLog Invoke-PrinterBug Restore-DomainObject
Domain/LDAP 功能
| 模块 | 别名 | 描述 |
|---|---|---|
| 获取-DomainUser | 查询AD中所有用户或特定用户对象 | |
| 获取-DomainComputer | 查询AD中所有计算机或特定计算机对象 | |
| 获取-DomainGroup | 查询AD中所有组或特定组对象 | |
| 获取-DomainGroupMember | 查询特定域组的成员 | |
| 获取-DomainOU | 查询OUs中的所有OUs或AD中特定的OU对象 | |
| 获取域名 | 查询域名信息 | |
| 获取-DomainController | 查询可用的域控制器 | |
| 获取-DomainDNSRecord | 查询可用记录。如果不指定-ZoneName,它将递归所有DNS区域 | |
| 获取-DomainDNSZone | 查询域中可用的DNS区域 | |
| 获取-DomainObject | 获取-ADObject | 查询AD中所有或指定域对象 |
| 获取-DomainObjectAcl | 获取-ObjectAcl | 查询 ACLs 指定的 AD 对象 |
| 获取-DomainSCCM | 获取-SCCM | 查询 SCCM |
| 获取-DomainRBCD | 获取-RBCD | 查找配置为基于资源的约束委派的帐户 |
| 获取-DomainObjectOwner | 获取-ObjectOwner | 查询AD对象的所有者 |
| 获取-DomainGMSA | 获取-GMSA | 查询组托管服务帐户 (gMSA) 并检索其密码 blob |
| 获取-DomainDMSA | 获取-GDSA | 查询委派托管服务帐户 (dMSA) |
| 删除-DomainGMSA | 删除-GMSA | 从域中删除现有的组托管服务帐户 (GMSA) |
| 删除-DomainDMSA | 删除-DMSA | 从域中删除现有的委派托管服务帐户 (dMSA) |
| 删除-DomainDNSRecord | 删除域名DNS记录 | |
| 删除-DomainComputer | 删除-ADComputer | 删除域计算机 |
| 删除-DomainGroupMember | 删除-GroupMember | 删除特定域组的成员 |
| 删除-DomainOU | 删除-OU | 删除 OUs 或 AD 中的特定 OU 对象 |
| 删除-DomainObjectAcl | 删除-ObjectAcl | 删除指定 AD 对象的 ACLs |
| 删除-DomainObject | 删除-ADObject | 删除指定的域对象 |
| 删除-DomainUser | 删除-ADUser | Remove specified Domain User in AD |
| 套装-DomainDNSRecord | 设置域名DNS记录 | |
| 套装-DomainUserPassword | 为指定域用户设置密码 | |
| 套装-DomainComputerPassword | 设置指定域计算机的密码 | |
| 套装-DomainObject | 套装-ADObject | 为AD中的指定域对象设置 |
| 套装-DomainObjectDN | 套装-ADObjectDN | 修改对象的 distinguishedName 属性以及更改 OU |
| 套装-DomainObjectOwner | 套装-ObjectOwner | 设置 AD 对象的所有者 |
| 套装-ShadowCredential | 套装-ShadowCred | 管理域对象的 msDS-KeyCredentialLink(影子凭证) |
| 获取-ShadowCredential | 获取-ShadowCred | 列出域对象或所有对象的影子凭据 (msDS-KeyCredentialLink) |
| 删除-ShadowCredential | 删除-ShadowCred | 通过 DeviceId 删除影子凭据或从域对象中清除所有凭据 |
| 添加-DomainDNSRecord | 添加域名DNS记录 | |
| 禁用-DomainDNSRecord | 通过指向无效地址禁用 DNS 记录 | |
| 添加-DomainGMSA | 添加-GMSA | 在域中创建新的组托管服务帐户 (gMSA) |
| 添加-DomainDMSA | 添加-GMSA | 在域中创建新的委派托管服务帐户 (dMSA) |
| 添加-DomainUser | 添加-ADUser | 在 AD 中添加新的域用户 |
| 添加-DomainComputer | 添加-ADComputer | 在 AD 中添加新的域计算机 |
| 添加-DomainGroupMember | 添加-GroupMember | 在AD指定域组中添加新成员 |
| 添加-DomainOU | 添加-OU | 在 AD 中添加新的 OU 对象 |
| 添加-DomainGPO | 添加-GPO | 在 AD 中添加新的 GPO 对象 |
| 添加-DomainObjectAcl | 添加-ObjectAcl | 目前支持的权限有:All、DCsync、RBCD、ShadowCred、WriteMembers |
| 清除缓存 | 清除缓存 |
GPO 功能
| 模块 | 别名 | 描述 |
|---|---|---|
| 获取-DomainGPO | Query for domain group policy objects | |
| 获取-DomainGPOLocalGroup | 获取-GPOLocalGroup | 通过Restricted Groups或Group Policy preferences查询域内所有修改本地组成员身份的GPOs |
| 添加-GPLink | 创建指向 OU 的新 GPO 链接 | |
| 删除-GPLink | 从 OU 中删除 GPO 链接 |
计算机枚举函数
| 模块 | 别名 | 描述 |
|---|---|---|
| 获取-NetSession | [MS-SRVS]查询本地或远程计算机的会话信息 | |
| 获取-NetShare | 查询本地或远程计算机上打开的共享 | |
| 获取-NetLoggedOn | [MS-WKST]查询本地或远程计算机的登录用户 | |
| 获取-EventLog | [MS-EVEN6] 通过RPC从远程计算机查询Windows事件日志 | |
| 获取-EventLogChannel | [MS-EVEN6] 通过安全产品检测列出远程计算机上的事件日志通道 | |
| 获取-EventLogPublisher | [MS-EVEN6] 通过安全产品检测列出远程计算机上的事件日志发布者 | |
| 获取-NetService | [MS-SCMR] 查询本地或远程计算机上正在运行的服务 | |
| 停止-NetService | [MS-SCMR] 停止本地或远程计算机上的特定服务 | |
| 获取-NetProcess | 任务列表 | [MS-TSTS] 查询本地或远程计算机正在运行的进程 |
| 停止-NetProcess | 任务终止 | [MS-TSTS] 终止本地或远程计算机上的特定进程 |
| 获取-NetTerminalSession | [MS-TSTS] 查询本地或远程计算机上的活动终端会话 | |
| 删除-NetTerminalSession | [MS-TSTS] 终止本地或远程计算机上的特定终端会话 | |
| 停止计算机 | 关机-电脑 | [MS-TSTS] 关闭远程计算机 |
| 重新启动计算机 | 重启电脑 | [MS-TSTS] 重新启动远程计算机 |
ADCS 功能
| 模块 | 别名 | 描述 |
|---|---|---|
| 获取-DomainCATemplate | 获取-CATemplate | 查询可用的 CA 模板。支持过滤易受攻击的模板 |
| 获取-DomainCA | 获取-CA | 查询证书颁发机构(CA) |
| 删除-DomainCATemplate | 删除-CATemplate | 删除指定域 CA 模板 |
| 套装-DomainCATemplate | 套装-CATemplate | 修改 CA 模板的域对象的属性 |
| 添加-DomainCATemplate | 添加-CATemplate | 添加新域 CA 模板 |
| 添加-DomainCATemplateAcl | 添加-CATemplateAcl | 将ACL添加到证书模板中。目前支持的权限有“全部”、“注册”、“写入” |
交换功能
| 模块 | 别名 | 描述 |
|---|---|---|
| 获取-ExchangeServer | 获取交换 | 检索域中可用交换服务器的列表 |
域信任功能
| 模块 | 别名 | 描述 |
|---|---|---|
| 获取-DomainTrust | 查询所有域信任 | |
| 获取-DomainTrustMapping | 递归映射当前域可访问的所有信任。跳入每个信任合作伙伴并使用 SourceName / TargetName 列(镜像 PowerView.ps1 的 Get-DomainTrustMapping)展平结果。使用 -NoRecurse 限制起始域。 |
|
| 获取-DomainForeignUser | 查找-ForeignUser | 查询位于用户域之外的组中的用户 |
| 获取-DomainForeignGroupMember | 查找-ForeignGroup | 查询组域之外的用户的组并查找外部成员 |
其他功能
| 模块 | 别名 | 描述 |
|---|---|---|
| ConvertFrom-SID | 将给定安全标识符 (SID) 转换为 user/group 名称 | |
| ConvertFrom-UACValue | 将 UAC int 值转换为人类可读的形式 | |
| 获取-NamedPipes | 列出特定计算机的命名管道 | |
| 调用-DFSCoerce | 通过 MS-DFSNM NetrDfsRemoveStdRoot() 强制机器帐户身份验证 | |
| 调用 Kerberoast | 请求指定服务主体名称的 kerberos 票证 (SPN) | |
| 调用-PrinterBug | 触发MS-RPRN RpcRemoteFindFirstPrinterChangeNotificationEx函数强制服务器对指定机器进行身份验证 | |
| 解锁-ADAccount | 通过修改lockoutTime属性解锁域帐户 | |
| 查找-LocalAdminAccess | 查找本地域中当前具有本地管理员访问权限的计算机 |
记录
我们永远不会错过记录来跟踪已完成的操作。默认情况下,powerview会在当前用户主目录_(~)_中创建一个.powerview文件夹。每个日志文件都是根据当前日期生成的。
示例路径:/root/.powerview/logs/bionic.local/2024-02-13.log
漏洞检测
PowerView.py 包括一个集成的漏洞检测系统,可自动识别常见的 Active Directory 安全问题。查询对象时,漏洞将显示在输出中:
漏洞:[VULN-026]具有高计算机帐户配额的域(允许用户添加计算机帐户)(MEDIUM)
[VULN-029] Domain with weak minimum password length policy (less than 8 characters) (HIGH)
用户定义的规则
您可以通过修改PowerView存储目录(~/.powerview/vulns.json)中的vulns.json文件来定义自定义漏洞检测规则。
每个漏洞规则具有以下结构:
"rule_name": {
"description": "Human-readable description of the vulnerability",
"rules": [
{
"attribute": "attributeName",
"condition": "condition_type",
"value": "value_to_check"
},
{
"attribute": "anotherAttribute",
"condition": "another_condition",
"value": "another_value"
}
],
"exclusions": [
{
"attribute": "attributeName",
"condition": "condition_type",
"value": "value_to_exclude"
}
],
"severity": "low|medium|high|critical",
"id": "VULN-XXX",
"rule_operator": "AND|OR",
"exclusion_operator": "AND|OR",
"details": "Optional detailed explanation of the vulnerability and remediation steps"
}
规则组件:
- 规则:检测漏洞必须满足的条件列表
- 排除:条件列表,如果满足这些条件,即使对象符合规则,也会将其排除在检测之外
- rule_operator:如何组合多个规则(默认:“OR”)
- "AND": All rules must match
- "OR": Any rule can match
- exclusion_operator:如何组合多个排除(默认值:“OR”)
- “OR”:任何排除都可以匹配以排除该对象
- “AND”:所有排除项必须匹配才能排除该对象
- negate:可选布尔值 (True/False),可以添加到任何规则以反转其结果
Supported Conditions:
| 条件 | 描述 |
|---|---|
exists |
属性存在 |
not_exists |
属性不存在 |
equals |
Exact match (case-insensitive) |
not_equals |
不完全匹配 |
contains |
Substring match (case-insensitive) |
not_contains |
没有子串匹配 |
startswith |
以字符串开头(不区分大小写) |
endswith |
以字符串结尾(不区分大小写) |
older_than |
Date is older than specified number of days |
newer_than |
Date is newer than specified number of days |
greater_than |
数值大于指定值 |
less_than |
数值小于指定值 |
greater_than_or_equal |
数值大于或等于指定值 |
less_than_or_equal |
数值小于或等于指定值 |
has_flag |
位标志设置为数值 |
missing_flag |
Bit flag is not set in a numeric value |
any_flag_set |
设置任何指定的标志 |
all_flags_set |
所有指定的标志均已设置 |
多个值:
您可以使用以下方法为一个条件指定多个值:
- 竖线分隔的字符串:
"value": "value1|值2|值3" - 列表格式:
"value": ["value1", "value2", "value3"]
规则示例:
"weak_password_policy": {
"description": "Domain with weak minimum password length policy (less than 8 characters)",
"rules": [
{
"attribute": "objectClass",
"condition": "contains",
"value": "domainDNS"
},
{
"attribute": "minPwdLength",
"condition": "less_than",
"value": 8
}
],
"exclusions": [],
"severity": "high",
"id": "VULN-029",
"rule_operator": "AND"
}
MCP
[!注意] 这没有捆绑在基础项目安装中。您可以运行
pip3 install .[mcp] or pip3 install powerview[mcp]以包含 MCP 功能。
这启用了模型上下文协议服务器,允许 AI 代理通过可流 HTTP 传输的标准化接口与 PowerView 功能进行交互。有关更多详细信息,请参阅 MCP 文档。
- 启动MCP服务器
powerview domain.local/lowpriv:[email protected] --mcp [--mcp-主机 0.0.0.0] [--mcp-端口 8888] [--mcp-路径 powerview]
MCP 服务器通过标准化工具接口公开 PowerView 的大部分功能。这包括以下能力:
- 查询和枚举Active Directory对象(用户、计算机、组、OUs)
- 检索有关域信任、GPOs 和组成员身份的信息
- 搜索安全漏洞和错误配置
- ...
克劳德桌面
Claude Desktop 尚不支持基于 HTTP 的传输 Github。您可能想要使用 mcp-proxy。
- 安装
mcp-proxy
# Option 1: With uv (recommended)
uv tool install mcp-proxy
# Option 2: With pipx (alternative)
pipx install mcp-proxy
- 修改
%APPDATA%Claudeclaude_desktop_config.json
{
"mcpServers": {
"Powerview": {
"command": "mcp-proxy",
"args": ["http://10.10.10.10:5000/powerview"]
}
}
}
光标
您可以在 MCP 选项按钮下的光标设置中修改此设置。
[!提示] 启用 YOLO 模式以启用自主模式,这样您就不必每次都单击“运行工具”按钮。在这里阅读更多 here
{
"mcpServers": {
"Powerview": {
"url": "http://127.0.0.1:5000/powerview"
}
}
}
[!警告] 当 MCP 与公共 AI 模型(如 Claude、GPT 等)一起使用时,您的 Active Directory 数据可能会根据这些服务的数据处理策略传输到这些服务并由这些服务记录。使用这些工具时请注意敏感信息的暴露。对于因将 PowerView 连接到第三方 AI 服务而导致的任何数据泄露或安全影响,我们不承担任何责任。自托管FTW!
插件
PowerView 支持基于装饰器的插件系统,可让您添加新命令并挂钩 before/after 现有命令。
它是如何运作的
┌────────────────────────────────┐
│ Plugin Loader │
│ Scans directories on startup │
└──────────────┬─────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ builtin/ plugins │ │ ~/.powerview/ │
│ │ │ plugins/ │
│ dehashed.py │ │ │
│ highlight.py │ │ my_plugin.py │
│ recon.py │ │ ... │
└───────────────────┘ └───────────────────┘
│ │
└───────────────┬───────────────┘
▼
┌──────────────────────┐
│ Sanity Validation │
│ Check signatures & │
│ required decorators │
└──────────┬───────────┘
▼
┌──────────────────────┐
│ Plugin Registry │
│ │
│ commands: {} │
│ before_hooks: {} │
│ after_hooks: {} │
└──────────┬───────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Command Execution Flow │
│ │
│ User Input: "Get-DomainUser -Identity admin" │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ @before hooks │ │
│ │ (modify args) │ │
│ └───────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Core command OR │ │
│ │ @command plugin │ │
│ └───────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ @after hooks │ │
│ │ (modify results) │ │
│ └───────────┬────────────┘ │
│ │ │
│ ▼ │
│ Format & Display │
└─────────────────────────────────────────────────┘
插件是从两个路径自动发现的单个 .py 文件:
| 路径 | 目的 |
|---|---|
powerview/plugins/builtin/ |
随包裹一起发货 |
~/.powerview/plugins/ |
用户管理的插件 |
内置插件
| 插件 | 命令 | 挂钩 | 描述 |
|---|---|---|---|
| 侦察 | Invoke-DomainRecon |
— | 单命令域侦察总结 |
| 亮点 | — | after:Get-DomainUser |
突出显示在用户描述中找到的密码 |
插件管理
Get-Plugin # List all plugins with status
Enable-Plugin -Name <plugin_name> # Enable a disabled plugin
Disable-Plugin -Name <plugin_name> # Disable a plugin at runtime
编写插件
在~/.powerview/plugins/中创建一个.py文件。插件使用三个装饰器:@command 注册新命令,@before 在现有命令之前运行逻辑,@after 在现有命令之后运行逻辑。
# ~/.powerview/plugins/custom_enum.py
from powerview.plugins import command, before, after, PowerviewPlugin
plugin = PowerviewPlugin(
name="CustomEnum",
description="Custom enumeration helpers",
author="yourname",
version="1.0",
)
@command("Get-DomainAdminUser", args=["-Identity", "-Properties", "-SearchBase"],
description="Find users with adminCount=1")
def get_domainadminuser(pv, args=无, 身份=无, 属性=无, searchbase=无):
results = pv.get_domainuser(
identity=identity or "*",
properties=properties or ["sAMAccountName", "adminCount", "memberOf", "description"],
searchbase=searchbase,
)
if results:
return [r for r in results
if str(r.get("attributes", r).get("adminCount", "")) == "1"]
return results
@before("Get-DomainUser", priority=10)
def inject_enabled_filter(pv, args):
"""Automatically filter out disabled accounts."""
if not hasattr(args, 'ldapfilter') or not args.ldapfilter:
args.ldapfilter = "(!(userAccountControl:1.2.840.113556.1.4.803:=2))"
return args
@after("Get-DomainUser", priority=20)
def add_password_age(pv, args, results):
"""Enrich results with password age."""
from datetime import datetime, timezone
if not results:
return results
for entry in results:
attrs = entry.get("attributes", entry)
pwdlast = attrs.get("pwdLastSet")
if isinstance(pwdlast, datetime):
if pwdlast.tzinfo is None:
pwdlast = pwdlast.replace(tzinfo=timezone.utc)
age = (datetime.now(timezone.utc) - pwdlast).days
attrs["PasswordAge"] = f"{age} days"
return results
装饰器:
| 装饰者 | 签名 | 描述 |
|---|---|---|
@command(name, args, description) |
func(pv, args=None, **kwargs) |
注册一个新的动词名词命令 |
@before(command_name, priority) |
func(pv, args) |
在命令之前运行。返回修改后的参数或 None |
@after(command_name, priority) |
func(pv, args, results) |
执行命令后运行。返回修改后的结果或None |
[!NOTE]
@before和@after接受单个命令名称或列表(e.g.、@after(["Get-DomainUser", "Get-DomainComputer"]))。优先级较低的值首先运行。
高级参数定义:
插件参数可以是简单的字符串("-Identity")或用于更精细控制的字典:
@command("Get-CustomThing", args=[
"-Identity",
{"name": "-Days", "type": int, "default": 90, "help": "Threshold in days"},
{"name": "-Verbose", "action": "store_true", "help": "Show details"},
])
[!TIP] 所有插件命令都会自动获取
-OutFile、-TableView和-SortBy标志。