跳转到主要内容

Python DPAPI NG 解密库

项目描述

dpapi_ng - Python DPAPI-NG 解/加密库

Test workflow codecov PyPI version License

DPAPI NG 库,也称为 CNG DPAPI,是 Python 中的解密和加密库。它旨在模拟 NCryptUnprotectSecretNCryptProtectSecret 的行为。它可以在非 Windows 主机上用于解密/加密 DPAPI NG 受保护的秘密,例如 PFX 用户受保护的密码或 LAPS 加密的密码。它可以使用域根密钥的离线副本解密任何 DPAPI NG blob,或者使用提供的用户的凭据通过 RPC 获取所需信息进行解密/加密。

目前仅支持以下保护描述符

类型 用途
SID 只有 SID 用户或 SID 组的成员可以解密秘密

此实现遵循 MS-GKDI 组密钥分发协议

要求

如何安装

要安装具有所有基本功能的 dpapi-ng,请运行

python -m pip install dpapi-ng

Kerberos 身份验证

Kerberos 身份验证支持默认情况下不会安装,因为它依赖于系统库和有效的编译器。可以通过安装以下包来安装 krb5 库和编译器

# Debian/Ubuntu
apt-get install gcc python3-dev libkrb5-dev

# Centos/RHEL
yum install gcc python-devel krb5-devel

# Fedora
dnf install gcc python-devel krb5-devel

# Arch Linux
pacman -S gcc krb5

安装完成后,可以使用以下命令安装 Kerberos Python 扩展

python -m pip install dpapi-ng[kerberos]

Kerberos 还需要配置以与域通信,但这超出了本页的范围。

从源代码安装

git clone https://github.com/jborean93/dpapi-ng.git
cd dpapi-ng
pip install -e .

示例

提供了同步和 asyncio API 以解密/加密 blob。

import dpapi_ng


### DECRYPTION ###
dpapi_ng_blob = b"..."
decrypted_blob = dpapi_ng.ncrypt_unprotect_secret(dpapi_ng_blob)

# async equivalent to the above
decrypted_blob = await dpapi_ng.async_ncrypt_unprotect_secret(dpapi_ng_blob)


### ENCRYPTION ###
data = b"..."
target_sid = "S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX"
dpapi_ng_blob = dpapi_ng.ncrypt_protect_secret(data, target_sid)

# async equivalent to the above
dpapi_ng_blob = await dpapi_ng.async_ncrypt_protect_secret(data, target_sid)

要解密 blob,需要从生成 blob 的域控制器检索 blob 中指定的密钥。要加密 blob,需要检索目标 SID 的组密钥。对于解密,将自动通过 DNS SRV 查找 _ldap._tcp.dc._msdcs.{domain_name}(其中域名称在 DPAPI-NG blob 中找到或在 server 关键字参数中指定)来检索域控制器的主机名。对于加密,域控制器的名称可以是使用 domain_name 关键字参数进行 DNS SRV 查找的,是直接使用 server 关键字参数,或者使用系统的搜索域(如果可用)。它将尝试使用当前用户标识符进行身份验证,在 Linux 上只有当 kinit 已经被调用以检索用户的票据时才会存在。如果没有可用的身份,则可以使用 usernamepassword 关键字参数指定自定义用户。

以下关键字参数可用于 ncrypt_unprotect_secretasync_ncrypt_unprotect_secretncrypt_protect_secretasync_ncrypt_protect_secret

  • server:如果需要检索密钥,请使用此服务器作为 RPC 目标
  • username:用于 RPC 连接的认证用户名
  • password:用于 RPC 连接的认证密码
  • auth_protocol:用于 RPC 连接的认证协议(negotiatekerberosntlm
  • cache:用于存储检索到的密钥以供将来操作的缓存

此外,ncrypt_protect_secretasync_ncrypt_protect_secret 还需要以下附加关键字参数。

  • domain_name:用于查找检索密钥信息时使用的 RPC 目标时的域/森林名称
  • root_key_identifier:根密钥标识符 UUID,对于使缓存对这些函数起作用是必需的

还可以通过提供存储在域中的根密钥来加密和解密 DPAPI-NG blob。这可以通过离线攻击或以域管理员用户身份运行时通过 LDAP 查询来实现。要使用 PowerShell 获取域根密钥,可以运行以下命令:

$configurationContext = (Get-ADRootDSE).configurationNamingContext
$getParams = @{
    LDAPFilter = '(objectClass=msKds-ProvRootKey)'
    SearchBase = "CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,$configurationContext"
    SearchScope = 'OneLevel'
    Properties = @(
        'cn'
        'msKds-KDFAlgorithmID'
        'msKds-KDFParam'
        'msKds-SecretAgreementAlgorithmID'
        'msKds-SecretAgreementParam'
        'msKds-PrivateKeyLength'
        'msKds-PublicKeyLength'
        'msKds-RootKeyData'
    )
}
Get-ADObject @getParams | ForEach-Object {
    [PSCustomObject]@{
        Version = 1
        RootKeyId = [Guid]::new($_.cn)
        KdfAlgorithm = $_.'msKds-KDFAlgorithmID'
        KdfParameters = [System.Convert]::ToBase64String($_.'msKds-KDFParam')
        SecretAgreementAlgorithm = $_.'msKds-SecretAgreementAlgorithmID'
        SecretAgreementParameters = [System.Convert]::ToBase64String($_.'msKds-SecretAgreementParam')
        PrivateKeyLength = $_.'msKds-PrivateKeyLength'
        PublicKeyLength = $_.'msKds-PublicKeyLength'
        RootKeyData = [System.Convert]::ToBase64String($_.'msKds-RootKeyData')
    }
}

以下 ldapsearch 命令可以在 Windows 外部使用

ldapsearch \
    -b 'CN=Master Root Keys,CN=Group Key Distribution Service,CN=Services,CN=Configuration,DC=domain,DC=test' \
    -s one \
    '(objectClass=msKds-ProvRootKey)' \
    cn \
    msKds-KDFAlgorithmID \
    msKds-KDFParam \
    msKds-SecretAgreementAlgorithmID \
    msKds-SecretAgreementParam \
    msKds-PrivateKeyLength \
    msKds-PublicKeyLength \
    msKds-RootKeyData

注意:ldapsearch 可能需要 -H 和用户绑定信息才能成功。

检索到的信息可以存储在缓存中,并用于后续的 ncrypt_protect_secretncrypt_unprotect_secret 调用。

import uuid

import dpapi_ng

cache = dpapi_ng.KeyCache()

root_key_id = uuid.UUID("76ec8b2d-d444-4f67-9db7-2f62b4358b35")
cache.load_key(
    b"...",                             # msKds-RootKeydata
    root_key_id,                        # cn
    version=1,
    kdf_algorithm="SP800_108_CTR_HMAC", # msKds-KDFAlgorithmID
    kdf_parameters=b"...",              # msKds-KDFParam
    secret_algorithm="DH",              # mskds-SecretAgreementAlgorithmID
    secret_parameters=b"...",           # msKds-SecretAgreementParam
    private_key_length=512,             # msKds-PrivateKeyLength
    public_key_length=2048,             # msKds-PublicKeyLength
)

dpapi_ng.ncrypt_unprotect_secret(b"...", cache=cache)

目前,已测试以下 KDF 算法可以工作:SP800_108_CTR_HMAC 和秘密协商算法 DHECDH_P256ECDH_P384。秘密协商算法 ECDH_P521 也应该可以工作,但尚未测试,因为无法创建包含它的测试环境。

特别感谢

我想感谢以下人员(括号中为 GitHub 或 Twitter 处理)在本项目中的帮助:

  • Georg Sieber (@schorschii) 为实现加密支持
  • Grzegorz Tworek (@0gtweet) 和 Michał Grzegorzewski 为提供有关 DPAPI-NG 中使用的内部 BCrypt* API 工作流程的更多信息
  • Marc-André Moreau (@awakecoding) 为其帮助逆向工程一些 Windows API 以及讨论一些理论
  • SkelSec (@SkelSec) 为 RPC 调用的帮助,并作为我理论的通用试金石
  • Steve Syfuhs (@SteveSyfuhs) 为将其与我联系的一些微软工程师联系起来,以帮助理解一些未记录的逻辑

没有他们的耐心和知识,这可能是无法实现的。

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装软件包 的信息。

源分布

dpapi-ng-0.2.0.tar.gz (59.3 kB 查看哈希值)

上传时间

构建分布

dpapi_ng-0.2.0-py3-none-any.whl (52.9 kB 查看哈希值)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面