
Python-DPAPI-NG-Entschlüsseler für Nicht-Windows-Plattformen
Bibliothek für die Ent- und Verschlüsselung von DPAPI NG, auch bekannt als CNG-DPAPI, in Python. Sie wurde entwickelt, um das Verhalten von NCryptUnprotectSecret und NCryptProtectSecret nachzubilden. Sie kann auf Nicht-Windows-Hosts verwendet werden, um durch DPAPI NG geschützte Geheimnisse zu ent-/verschlüsseln, wie z. B. das benutzergeschützte PFX-Passwort oder das LAPS-verschlüsselte Passwort. Sie kann entweder beliebige DPAPI-NG-Blobs mithilfe einer Offline-Kopie des Root-Keys der Domäne entschlüsseln oder mithilfe der Anmeldeinformationen des angegebenen Benutzers ent-/verschlüsseln, um die erforderlichen Informationen über RPC abzurufen.
Derzeit werden nur diese Schutzdeskriptoren unterstützt:
| Typ | Zweck |
|---|---|
| SID | Nur der SID-Benutzer oder Mitglieder der SID-Gruppe können das Geheimnis entschlüsseln |
Diese Bibliothek implementiert das MS-GKDI Group Key Distribution Protocol.
Um dpapi-ng mit allen grundlegenden Funktionen zu installieren, führen Sie folgenden Befehl aus:
python -m pip install dpapi-ng
Die Unterstützung für die Kerberos-Authentifizierung wird standardmäßig nicht installiert, da sie Systembibliotheken und einen vorhandenen Compiler voraussetzt. Die krb5-Bibliothek und der Compiler können mit den folgenden Paketen installiert werden:
# 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
Nach der Installation können die Kerberos-Python-Zusatzpakete mit folgendem Befehl installiert werden:
python -m pip install dpapi-ng[kerberos]
Kerberos muss außerdem so konfiguriert werden, dass es mit der Domäne kommunizieren kann; dies liegt jedoch außerhalb des Rahmens dieser Seite.
git clone https://github.com/jborean93/dpapi-ng.git
cd dpapi-ng
pip install -e .
Zum Ent-/Verschlüsseln eines Blobs stehen sowohl eine synchrone als auch eine asyncio-API zur Verfügung.
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)
Zum Entschlüsseln des Blobs muss der im Blob angegebene Schlüssel von dem Domänencontroller abgerufen werden, von dem der Blob erzeugt wurde.
Zum Verschlüsseln eines Blobs muss der Gruppenschlüssel der angegebenen Ziel-SID abgerufen werden.
Für die Entschlüsselung wird der Hostname des Domänencontrollers automatisch über eine DNS-SRV-Abfrage von _ldap._tcp.dc._msdcs.{domain_name} mit dem im DPAPI-NG-Blob gefundenen Domänennamen oder mit dem im server-Kwarg angegebenen Wert ermittelt.
Für die Verschlüsselung wird der Hostname des Domänencontrollers entweder über das domain_name-Kwarg für eine DNS-SRV-Abfrage, direkt über das server-Kwarg oder mithilfe der Suchdomäne des Systems (falls verfügbar) bestimmt.
Es wird versucht, sich mit der aktuellen Benutzeridentität zu authentifizieren, die unter Linux nur vorhanden ist, wenn kinit bereits aufgerufen wurde, um ein Benutzer-Ticket abzurufen.
Ist andernfalls keine Identität verfügbar, können die Kwargs username und password verwendet werden, um einen eigenen Benutzer anzugeben.
Die folgenden Kwargs können für ncrypt_unprotect_secret, async_ncrypt_unprotect_secret, ncrypt_protect_secret und async_ncrypt_protect_secret verwendet werden.
server: Diesen Server als RPC-Ziel verwenden, wenn ein Schlüssel abgerufen werden mussusername: Der Benutzername, mit dem die Authentifizierung für die RPC-Verbindung erfolgen sollpassword: Das Passwort, mit dem die Authentifizierung für die RPC-Verbindung erfolgen sollauth_protocol: Das Authentifizierungsprotokoll (negotiate, kerberos, ntlm), das für die RPC-Verbindung verwendet werden sollcache: Ein Cache zum Speichern abgerufener Schlüssel für zukünftige VorgängeDarüber hinaus akzeptieren ncrypt_protect_secret und async_ncrypt_protect_secret das folgende zusätzliche Kwarg.
domain_name: Der Name der Domäne/Gesamtstruktur, die bei der Suche nach dem RPC-Ziel für den Abruf der Schlüsselinformationen verwendet werden sollroot_key_identifier: Die UUID des Root-Key-Bezeichners, die erforderlich ist, damit der Cache für diese Funktionen funktioniertEs ist auch möglich, den DPAPI-NG-Blob zu ver- und entschlüsseln, indem der in der Domäne gespeicherte Root-Key bereitgestellt wird. Dieser kann entweder über einen Offline-Angriff oder über eine LDAP-Abfrage abgerufen werden, wenn man als Domänenadministrator angemeldet ist. Zum Abrufen der Domänen-Root-Keys mit PowerShell kann Folgendes ausgeführt werden:
$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')
}
}
Der folgende ldapsearch-Befehl kann außerhalb von Windows verwendet werden:
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