
Python DPAPI NG Decryptor for non-Windows Platforms
مكتبة بايثون لفك وتشفير DPAPI NG، والمعروف أيضًا باسم CNG DPAPI. صُممت لمحاكاة سلوك NCryptUnprotectSecret وNCryptProtectSecret. يمكن استخدامها على المضيفات غير العاملة بنظام ويندوز لفك/تشفير الأسرار المحمية بـ DPAPI NG، مثل كلمة مرور PFX المحمية للمستخدم، أو كلمة مرور LAPS المشفرة. يمكنها إما فك تشفير أي كائنات DPAPI NG باستخدام نسخة محلية غير متصلة من المفتاح الجذر للنطاق، أو فك/تشفير باستخدام بيانات اعتماد المستخدم المقدم لاسترداد المعلومات المطلوبة عبر RPC.
حاليًا، لا تُدعم إلا واصفات الحماية التالية:
| النوع | الغرض |
|---|---|
| SID | يمكن للمستخدم SID أو أعضاء مجموعة SID فقط فك تشفير السر |
يطبق هذا بروتوكول MS-GKDI Group Key Distribution Protocol.
لتثبيت dpapi-ng بجميع الميزات الأساسية، شغّل
python -m pip install dpapi-ng
لن يتم تثبيت دعم مصادقة 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 -m pip install dpapi-ng[kerberos]
يجب أيضًا تكوين Kerberos للتواصل مع النطاق، لكن هذا خارج نطاق هذه الصفحة.
git clone https://github.com/jborean93/dpapi-ng.git
cd dpapi-ng
pip install -e .
تتوفر واجهة برمجة تطبيقات متزامنة (sync) وغير متزامنة (asyncio) لفك/تشفير كائن ثنائي (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)
لفك تشفير الكائن، يجب استرداد المفتاح المحدد في الكائن من وحدة تحكم النطاق التي أنشأت الكائن.
لتشفير كائن، يجب استرداد مفتاح المجموعة لـ SID الهدف المحدد.
لفك التشفير، يتم استرداد اسم مضيف وحدة تحكم النطاق تلقائيًا عبر بحث DNS SRV عن _ldap._tcp.dc._msdcs.{domain_name} باستخدام اسم النطاق الموجود في كائن DPAPI-NG أو بالقيمة المحددة في وسيط server.
للتشفير، يتم تحديد اسم مضيف وحدة تحكم النطاق إما باستخدام وسيط domain_name لإجراء بحث DNS SRV، أو وسيط server مباشرة، أو باستخدام نطاق بحث النظام (إن وجد).
سيحاول المصادقة باستخدام معرف المستخدم الحالي، والذي يوجد على لينكس فقط إذا تم استدعاء kinit مسبقًا لاسترداد تذكرة المستخدم.
خلاف ذلك، إذا لم تتوفر هوية، يمكن استخدام الوسيطين username وpassword لتحديد مستخدم مخصص.
يمكن استخدام الوسائط التالية مع ncrypt_unprotect_secret وasync_ncrypt_unprotect_secret وncrypt_protect_secret وasync_ncrypt_protect_secret.
server: استخدم هذا الخادم كهدف RPC إذا احتاج مفتاح إلى الاستردادusername: اسم المستخدم للمصادقة عبر اتصال RPCpassword: كلمة المرور للمصادقة عبر اتصال RPCauth_protocol: بروتوكول المصادقة (negotiate، kerberos، ntlm) لاستخدامه في اتصال RPCcache: ذاكرة تخزين مؤقت لتخزين المفاتيح المستردة للعمليات المستقبليةبالإضافة إلى ذلك، تأخذ ncrypt_protect_secret وasync_ncrypt_protect_secret الوسيط الإضافي التالي.
domain_name: اسم النطاق/الغابة لاستخدامه عند البحث عن هدف RPC لاسترداد معلومات المفتاحroot_key_identifier: معرّف المفتاح الجذر UUID، وهو ضروري لجعل ذاكرة التخزين المؤقت تعمل مع هذه الوظائفمن الممكن أيضًا تشفير وفك تشفير كائن DPAPI-NG من خلال توفير المفتاح الجذر المخزن في النطاق. يمكن استرداده إما باستخدام هجوم دون اتصال أو عبر استعلام 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 التالي خارج ويندوز:
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 وربط المستخدم (user bind) ليعمل بنجاح.
يمكن تخزين المعلومات المستردة هناك في ذاكرة تخزين مؤقت واستخدامها في استدعاءات ncrypt_protect_secret وncrypt_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 وخوارزميات الاتفاق السري DH وECDH_P256 وECDH_P384 للتأكد من أنها تعمل.
يجب أن تعمل خوارزمية الاتفاق السري ECDH_P521 أيضًا، لكنها غير مختبرة لأنه لا يمكن إنشاء بيئة اختبار بها حاليًا.
أود أن أشكر الأشخاص التاليين (معرفات GitHub أو Twitter بين أقواس) لمساعدتهم في هذا المشروع:
بدون صبرهم ومعرفتهم، ربما لم يكن هذا ممكنًا.