dissect.database 1.2.dev6__tar.gz → 1.2.dev8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/PKG-INFO +1 -1
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/database.py +68 -52
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/ntds.py +7 -7
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/__init__.py +2 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/computer.py +7 -0
- dissect_database-1.2.dev8/dissect/database/ese/ntds/objects/msfve_recoveryinformation.py +45 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ntdsdsa.py +13 -1
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/object.py +5 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/server.py +7 -1
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/query.py +4 -1
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/schema.py +2 -2
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/util.py +24 -7
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect.database.egg-info/PKG-INFO +1 -1
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect.database.egg-info/SOURCES.txt +1 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/conftest.py +7 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/test_ntds.py +48 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/test_pek.py +4 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/.git-blame-ignore-revs +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/COPYRIGHT +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/LICENSE +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/MANIFEST.in +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/README.md +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/c_db.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/c_db.pyi +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/db.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/tools/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/tools/c_rpm.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/tools/c_rpm.pyi +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/tools/rpm.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/c_ese.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/c_ese.pyi +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/compression.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/cursor.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ese.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/exception.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/index.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/lcmapstring.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/c_ds.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/c_ds.pyi +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/c_pek.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/c_pek.pyi +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/c_sd.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/c_sd.pyi +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/applicationsettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/attributeschema.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/builtindomain.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/certificationauthority.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/classschema.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/classstore.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/configuration.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/container.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/controlaccessright.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/crldistributionpoint.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/crossref.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/crossrefcontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/dfsconfiguration.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/displayspecifier.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/dmd.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/dnsnode.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/dnszone.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/domain.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/domaindns.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/domainpolicy.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/dsuisettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/filelinktracking.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/foreignsecurityprincipal.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/group.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/grouppolicycontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/infrastructureupdate.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/intersitetransport.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/intersitetransportcontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ipsecbase.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ipsecfilter.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ipsecisakmppolicy.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ipsecnegotiationpolicy.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ipsecnfa.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ipsecpolicy.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/leaf.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/linktrackobjectmovetable.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/linktrackvolumetable.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/locality.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/lostandfound.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msauthz_centralaccesspolicies.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msauthz_centralaccessrules.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_content.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_contentset.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_globalsettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_localsettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_member.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_replicationgroup.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_subscriber.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_subscription.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdfsr_topology.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msdns_serversettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_authnpolicies.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_authnpolicysilos.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_claimstransformationpolicies.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_claimtype.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_claimtypepropertybase.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_claimtypes.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_optionalfeature.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_passwordsettingscontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_quotacontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_resourceproperties.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_resourceproperty.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_resourcepropertylist.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_shadowprincipalcontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msds_valuetype.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msimaging_psps.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/mskds_provserverconfiguration.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msmqenterprisesettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/mspki_enterpriseoid.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/mspki_privatekeyrecoveryagent.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/msspp_activationobjectscontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/mstpm_informationobjectscontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ntdsconnection.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ntdsservice.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ntdssitesettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ntfrssettings.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/organizationalperson.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/organizationalunit.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/person.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/physicallocation.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/pkicertificatetemplate.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/pkienrollmentservice.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/querypolicy.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ridmanager.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ridset.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/rpccontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/rrasadministrationdictionary.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/samserver.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/secret.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/securityobject.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/serverscontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/site.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/sitelink.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/sitescontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/subnetcontainer.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/subschema.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/top.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/trusteddomain.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/user.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/pek.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/sd.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/tools/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/tools/ntds.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/page.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/record.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/sorting_table.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/table.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/tools/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/tools/certlog.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/tools/impacket.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/tools/sru.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/tools/ual.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/util.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/exception.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/c_sqlite3.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/c_sqlite3.pyi +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/encryption/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/encryption/sqlcipher/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/encryption/sqlcipher/exception.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/encryption/sqlcipher/sqlcipher.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/exception.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/sqlite3.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/util.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/sqlite3/wal.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect.database.egg-info/dependency_links.txt +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect.database.egg-info/entry_points.txt +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect.database.egg-info/requires.txt +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect.database.egg-info/top_level.txt +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/pyproject.toml +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/setup.cfg +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/_docs/Makefile +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/_docs/conf.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/_docs/index.rst +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/_tools/sqlite3/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/_tools/sqlite3/generate_sqlite.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/_util.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/bsd/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/bsd/conftest.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/bsd/test_db.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/bsd/test_rpm.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/conftest.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/conftest.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/test_benchmark.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/test_query.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/test_schema.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/test_sd.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/ntds/test_util.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/test_cursor.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/test_ese.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/test_index.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/test_page.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/test_record.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/test_table.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/tools/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/tools/test_certlog.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/tools/test_sru.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/ese/tools/test_ual.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/__init__.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/conftest.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/test_default_values.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/test_row.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/test_sqlcipher.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/test_sqlite3.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/test_util.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tests/sqlite3/test_wal.py +0 -0
- {dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.database
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.dev8
|
|
4
4
|
Summary: A Dissect module implementing parsers for various database formats, including Berkeley DB, Microsofts Extensible Storage Engine (ESE) and SQLite3
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/database.py
RENAMED
|
@@ -6,18 +6,18 @@ from typing import TYPE_CHECKING, BinaryIO
|
|
|
6
6
|
|
|
7
7
|
from dissect.database.ese.ese import ESE
|
|
8
8
|
from dissect.database.ese.exception import KeyNotFoundError
|
|
9
|
-
from dissect.database.ese.ntds.objects import
|
|
9
|
+
from dissect.database.ese.ntds.objects import Object
|
|
10
10
|
from dissect.database.ese.ntds.pek import PEK
|
|
11
11
|
from dissect.database.ese.ntds.query import Query
|
|
12
12
|
from dissect.database.ese.ntds.schema import Schema
|
|
13
13
|
from dissect.database.ese.ntds.sd import SecurityDescriptor
|
|
14
|
-
from dissect.database.ese.ntds.util import DN, SearchFlags, encode_value
|
|
14
|
+
from dissect.database.ese.ntds.util import DN, DatabaseFlags, SearchFlags, encode_value
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
17
|
from collections.abc import Iterator
|
|
18
18
|
|
|
19
19
|
from dissect.database.ese.index import Index
|
|
20
|
-
from dissect.database.ese.ntds.objects import DMD, NTDSDSA, Top
|
|
20
|
+
from dissect.database.ese.ntds.objects import DMD, NTDSDSA, DomainDNS, Server, Top
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class Database:
|
|
@@ -34,78 +34,91 @@ class Database:
|
|
|
34
34
|
self.link = LinkTable(self)
|
|
35
35
|
self.sd = SecurityDescriptorTable(self)
|
|
36
36
|
|
|
37
|
-
self.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class DataTable:
|
|
41
|
-
"""Represents the ``datatable`` in the NTDS database."""
|
|
42
|
-
|
|
43
|
-
def __init__(self, db: Database):
|
|
44
|
-
self.db = db
|
|
45
|
-
self.table = self.db.ese.table("datatable")
|
|
46
|
-
self.hiddentable = self.db.ese.table("hiddentable")
|
|
37
|
+
self.hiddentable = self.ese.table("hiddentable")
|
|
47
38
|
self.hiddeninfo = next(self.hiddentable.records(), None)
|
|
48
39
|
|
|
49
|
-
self.schema
|
|
50
|
-
|
|
51
|
-
# Cache frequently used and "expensive" methods
|
|
52
|
-
self.get = lru_cache(4096)(self.get)
|
|
53
|
-
self._make_dn = lru_cache(4096)(self._make_dn)
|
|
54
|
-
|
|
55
|
-
def dsa(self) -> NTDSDSA:
|
|
56
|
-
"""Return the Directory System Agent (DSA) object."""
|
|
57
|
-
if not self.hiddeninfo:
|
|
58
|
-
raise ValueError("No hiddentable information available")
|
|
59
|
-
return self.get(self.hiddeninfo.get("dsa_col"))
|
|
60
|
-
|
|
61
|
-
def dmd(self) -> DMD:
|
|
62
|
-
"""Return the Directory Management Domain (DMD) object, a.k.a. the schema container."""
|
|
63
|
-
if not self.hiddeninfo:
|
|
64
|
-
raise ValueError("No hiddentable information available")
|
|
65
|
-
return self.get(self.dsa().get("dMDLocation", raw=True))
|
|
66
|
-
|
|
67
|
-
def root(self) -> Top:
|
|
68
|
-
"""Return the top-level object in the NTDS database."""
|
|
69
|
-
if (root := next(self.children_of(0), None)) is None:
|
|
70
|
-
raise ValueError("No root object found")
|
|
71
|
-
return root
|
|
40
|
+
self.data.schema.load(self)
|
|
72
41
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
while stack:
|
|
77
|
-
if (obj := stack.pop()).is_deleted:
|
|
78
|
-
continue
|
|
42
|
+
# Clear the cache of the data table to avoid caching results before the schema is loaded
|
|
43
|
+
self.data.get.cache_clear()
|
|
44
|
+
self.data._make_dn.cache_clear()
|
|
79
45
|
|
|
80
|
-
|
|
81
|
-
|
|
46
|
+
@cached_property
|
|
47
|
+
def flags(self) -> DatabaseFlags | None:
|
|
48
|
+
"""Return the database flags."""
|
|
49
|
+
if self.hiddeninfo is None:
|
|
50
|
+
return None
|
|
82
51
|
|
|
83
|
-
|
|
52
|
+
result = DatabaseFlags(0)
|
|
53
|
+
flags = self.hiddeninfo.get("flags_col")
|
|
54
|
+
for idx, member in enumerate(DatabaseFlags.__members__.values()):
|
|
55
|
+
if flags[idx] == ord(b"1"):
|
|
56
|
+
result = member if result is None else result | member
|
|
84
57
|
|
|
85
|
-
return
|
|
58
|
+
return result
|
|
86
59
|
|
|
87
60
|
@cached_property
|
|
88
61
|
def pek(self) -> PEK | None:
|
|
89
62
|
"""Return the PEK."""
|
|
90
|
-
if (
|
|
63
|
+
if (domain := self.domain()) is None:
|
|
91
64
|
# Maybe this is an AD LDS database
|
|
92
|
-
if (root_pek := self.root().get("pekList")) is None:
|
|
65
|
+
if (root_pek := self.data.root().get("pekList")) is None:
|
|
93
66
|
# It's not
|
|
94
67
|
return None
|
|
95
68
|
|
|
96
69
|
# Lookup the schema pek and permutate the boot key
|
|
97
70
|
# https://www.synacktiv.com/publications/using-ntdissector-to-extract-secrets-from-adam-ntds-files
|
|
98
|
-
schema_pek = self.
|
|
71
|
+
schema_pek = self.dmd().get("pekList")
|
|
99
72
|
boot_key = bytes(
|
|
100
73
|
[root_pek[i] for i in [2, 4, 25, 9, 7, 27, 5, 11]]
|
|
101
74
|
+ [schema_pek[i] for i in [37, 2, 17, 36, 20, 11, 22, 7]]
|
|
102
75
|
)
|
|
103
76
|
|
|
104
77
|
# Lookup the actual PEK and unlock it
|
|
105
|
-
pek = PEK(self.
|
|
78
|
+
pek = PEK(self.dmd().parent().get("pekList"))
|
|
106
79
|
pek.unlock(boot_key)
|
|
107
80
|
return pek
|
|
108
|
-
|
|
81
|
+
|
|
82
|
+
return domain.pek
|
|
83
|
+
|
|
84
|
+
def dsa(self) -> NTDSDSA:
|
|
85
|
+
"""Return the Directory System Agent (DSA) object, a.k.a. the NTDS Settings object."""
|
|
86
|
+
if not self.hiddeninfo:
|
|
87
|
+
raise ValueError("No hiddentable information available")
|
|
88
|
+
return self.data.get(self.hiddeninfo.get("dsa_col"))
|
|
89
|
+
|
|
90
|
+
def dmd(self) -> DMD:
|
|
91
|
+
"""Return the Directory Management Domain (DMD) object, a.k.a. the schema container."""
|
|
92
|
+
if not self.hiddeninfo:
|
|
93
|
+
raise ValueError("No hiddentable information available")
|
|
94
|
+
return self.data.get(self.dsa().get("dMDLocation", raw=True))
|
|
95
|
+
|
|
96
|
+
def dc(self) -> Server:
|
|
97
|
+
"""Return the Domain Controller (DC) server object that corresponds to this NTDS database."""
|
|
98
|
+
return self.dsa().parent()
|
|
99
|
+
|
|
100
|
+
def domain(self) -> DomainDNS | None:
|
|
101
|
+
"""Return the root domain object in the NTDS database. For AD LDS (ADAM), this will return ``None``."""
|
|
102
|
+
return self.dsa().domain()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class DataTable:
|
|
106
|
+
"""Represents the ``datatable`` in the NTDS database."""
|
|
107
|
+
|
|
108
|
+
def __init__(self, db: Database):
|
|
109
|
+
self.db = db
|
|
110
|
+
self.table = self.db.ese.table("datatable")
|
|
111
|
+
self.schema = Schema()
|
|
112
|
+
|
|
113
|
+
# Cache frequently used and "expensive" methods
|
|
114
|
+
self.get = lru_cache(4096)(self.get)
|
|
115
|
+
self._make_dn = lru_cache(4096)(self._make_dn)
|
|
116
|
+
|
|
117
|
+
def root(self) -> Top:
|
|
118
|
+
"""Return the top-level object in the NTDS database."""
|
|
119
|
+
if (root := next(self.children_of(0), None)) is None:
|
|
120
|
+
raise ValueError("No root object found")
|
|
121
|
+
return root
|
|
109
122
|
|
|
110
123
|
def walk(self) -> Iterator[Object]:
|
|
111
124
|
"""Walk through all objects in the NTDS database."""
|
|
@@ -201,8 +214,11 @@ class DataTable:
|
|
|
201
214
|
cursor.seek([dnt])
|
|
202
215
|
|
|
203
216
|
record = cursor.record()
|
|
204
|
-
while record is not None
|
|
217
|
+
while record is not None:
|
|
205
218
|
yield Object.from_record(self.db, record)
|
|
219
|
+
if record == end:
|
|
220
|
+
break
|
|
221
|
+
|
|
206
222
|
record = cursor.next()
|
|
207
223
|
|
|
208
224
|
def _make_dn(self, dnt: int) -> DN:
|
|
@@ -41,18 +41,18 @@ class NTDS:
|
|
|
41
41
|
def __init__(self, fh: BinaryIO):
|
|
42
42
|
self.db = Database(fh)
|
|
43
43
|
|
|
44
|
+
@property
|
|
45
|
+
def pek(self) -> PEK | None:
|
|
46
|
+
"""Return the PEK associated with the root domain."""
|
|
47
|
+
return self.db.pek
|
|
48
|
+
|
|
44
49
|
def root(self) -> Object:
|
|
45
50
|
"""Return the root object of the Active Directory."""
|
|
46
51
|
return self.db.data.root()
|
|
47
52
|
|
|
48
|
-
def
|
|
53
|
+
def domain(self) -> DomainDNS | None:
|
|
49
54
|
"""Return the root domain object of the Active Directory."""
|
|
50
|
-
return self.db.
|
|
51
|
-
|
|
52
|
-
@property
|
|
53
|
-
def pek(self) -> PEK | None:
|
|
54
|
-
"""Return the PEK associated with the root domain."""
|
|
55
|
-
return self.db.data.pek
|
|
55
|
+
return self.db.domain()
|
|
56
56
|
|
|
57
57
|
def walk(self) -> Iterator[Object]:
|
|
58
58
|
"""Walk through all objects in the NTDS database."""
|
|
@@ -68,6 +68,7 @@ from dissect.database.ese.ntds.objects.msds_resourceproperty import MSDSResource
|
|
|
68
68
|
from dissect.database.ese.ntds.objects.msds_resourcepropertylist import MSDSResourcePropertyList
|
|
69
69
|
from dissect.database.ese.ntds.objects.msds_shadowprincipalcontainer import MSDSShadowPrincipalContainer
|
|
70
70
|
from dissect.database.ese.ntds.objects.msds_valuetype import MSDSValueType
|
|
71
|
+
from dissect.database.ese.ntds.objects.msfve_recoveryinformation import MSFVERecoveryInformation
|
|
71
72
|
from dissect.database.ese.ntds.objects.msimaging_psps import MSImagingPSPs
|
|
72
73
|
from dissect.database.ese.ntds.objects.mskds_provserverconfiguration import MSKDSProvServerConfiguration
|
|
73
74
|
from dissect.database.ese.ntds.objects.msmqenterprisesettings import MSMQEnterpriseSettings
|
|
@@ -174,6 +175,7 @@ __all__ = [
|
|
|
174
175
|
"MSDSResourcePropertyList",
|
|
175
176
|
"MSDSShadowPrincipalContainer",
|
|
176
177
|
"MSDSValueType",
|
|
178
|
+
"MSFVERecoveryInformation",
|
|
177
179
|
"MSImagingPSPs",
|
|
178
180
|
"MSKDSProvServerConfiguration",
|
|
179
181
|
"MSMQEnterpriseSettings",
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from dissect.database.ese.ntds.objects.msfve_recoveryinformation import MSFVERecoveryInformation
|
|
5
6
|
from dissect.database.ese.ntds.objects.user import User
|
|
6
7
|
|
|
7
8
|
if TYPE_CHECKING:
|
|
@@ -22,6 +23,12 @@ class Computer(User):
|
|
|
22
23
|
def __repr_body__(self) -> str:
|
|
23
24
|
return f"name={self.name!r}"
|
|
24
25
|
|
|
26
|
+
def fve_recovery_information(self) -> Iterator[MSFVERecoveryInformation]:
|
|
27
|
+
"""Return the BitLocker recovery information objects associated with this computer."""
|
|
28
|
+
for child in self.children():
|
|
29
|
+
if isinstance(child, MSFVERecoveryInformation):
|
|
30
|
+
yield child
|
|
31
|
+
|
|
25
32
|
def managed_by(self) -> Iterator[Object]:
|
|
26
33
|
"""Return the objects that manage this computer."""
|
|
27
34
|
self._assert_local()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
from uuid import UUID
|
|
5
|
+
|
|
6
|
+
from dissect.database.ese.ntds.objects.top import Top
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from dissect.database.ese.ntds.objects import Computer
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MSFVERecoveryInformation(Top):
|
|
13
|
+
"""Represents a msFVE-RecoveryInformation object in the Active Directory.
|
|
14
|
+
|
|
15
|
+
References:
|
|
16
|
+
- https://learn.microsoft.com/en-us/windows/win32/adschema/c-msfve-recoveryinformation
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
__object_class__ = "msFVE-RecoveryInformation"
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def volume_guid(self) -> UUID:
|
|
23
|
+
"""Return the volume GUID associated with this recovery information."""
|
|
24
|
+
return UUID(bytes_le=self.get("msFVE-VolumeGuid"))
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def recovery_guid(self) -> UUID:
|
|
28
|
+
"""Return the recovery GUID associated with this recovery information."""
|
|
29
|
+
return UUID(bytes_le=self.get("msFVE-RecoveryGuid"))
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def recovery_password(self) -> str | None:
|
|
33
|
+
"""Return the recovery password associated with this recovery information."""
|
|
34
|
+
return self.get("msFVE-RecoveryPassword")
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def key_package(self) -> bytes | None:
|
|
38
|
+
"""Return the key package associated with this recovery information, if any."""
|
|
39
|
+
return self.get("msFVE-KeyPackage")
|
|
40
|
+
|
|
41
|
+
def computer(self) -> Computer:
|
|
42
|
+
"""Return the computer object associated with this recovery information."""
|
|
43
|
+
if (parent := self.parent()) is None:
|
|
44
|
+
raise ValueError("msFVE-RecoveryInformation object has no parent computer")
|
|
45
|
+
return parent
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/ntdsdsa.py
RENAMED
|
@@ -7,7 +7,7 @@ from dissect.database.ese.ntds.objects.applicationsettings import ApplicationSet
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from collections.abc import Iterator
|
|
9
9
|
|
|
10
|
-
from dissect.database.ese.ntds.objects import Object
|
|
10
|
+
from dissect.database.ese.ntds.objects import DomainDNS, MSDSOptionalFeature, Object
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class NTDSDSA(ApplicationSettings):
|
|
@@ -19,6 +19,18 @@ class NTDSDSA(ApplicationSettings):
|
|
|
19
19
|
|
|
20
20
|
__object_class__ = "nTDSDSA"
|
|
21
21
|
|
|
22
|
+
def domain(self) -> DomainDNS | None:
|
|
23
|
+
"""Return the domain object associated with this NTDS DSA object, if any."""
|
|
24
|
+
self._assert_local()
|
|
25
|
+
|
|
26
|
+
return next(self.db.link.links(self.dnt, "msDS-HasDomainNCs"), None)
|
|
27
|
+
|
|
28
|
+
def features(self) -> Iterator[MSDSOptionalFeature]:
|
|
29
|
+
"""Return the optional features that are enabled on this NTDS DSA object."""
|
|
30
|
+
self._assert_local()
|
|
31
|
+
|
|
32
|
+
yield from self.db.link.links(self.dnt, "msDS-EnabledFeature")
|
|
33
|
+
|
|
22
34
|
def managed_by(self) -> Iterator[Object]:
|
|
23
35
|
"""Return the objects that manage this NTDS DSA object."""
|
|
24
36
|
self._assert_local()
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/object.py
RENAMED
|
@@ -57,6 +57,11 @@ class Object:
|
|
|
57
57
|
def __getattr__(self, name: str) -> Any:
|
|
58
58
|
return self.get(name)
|
|
59
59
|
|
|
60
|
+
def __eq__(self, other: object) -> bool:
|
|
61
|
+
if not isinstance(other, Object):
|
|
62
|
+
return NotImplemented
|
|
63
|
+
return self.record == other.record
|
|
64
|
+
|
|
60
65
|
@classmethod
|
|
61
66
|
def from_record(cls, db: Database, record: Record) -> Object:
|
|
62
67
|
"""Create an Object instance from a database record.
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/objects/server.py
RENAMED
|
@@ -7,7 +7,7 @@ from dissect.database.ese.ntds.objects.top import Top
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from collections.abc import Iterator
|
|
9
9
|
|
|
10
|
-
from dissect.database.ese.ntds.objects import Object
|
|
10
|
+
from dissect.database.ese.ntds.objects import Computer, Object
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class Server(Top):
|
|
@@ -19,6 +19,12 @@ class Server(Top):
|
|
|
19
19
|
|
|
20
20
|
__object_class__ = "server"
|
|
21
21
|
|
|
22
|
+
def computer(self) -> Computer | None:
|
|
23
|
+
"""Return the computer object associated with this server, if any."""
|
|
24
|
+
self._assert_local()
|
|
25
|
+
|
|
26
|
+
return next(self.db.link.links(self.dnt, "serverReference"), None)
|
|
27
|
+
|
|
22
28
|
def managed_by(self) -> Iterator[Object]:
|
|
23
29
|
"""Return the objects that manage this server."""
|
|
24
30
|
self._assert_local()
|
|
@@ -124,6 +124,7 @@ class Query:
|
|
|
124
124
|
Yields:
|
|
125
125
|
Records matching any condition in the OR operation.
|
|
126
126
|
"""
|
|
127
|
+
records = list(records) if records is not None else None
|
|
127
128
|
for child in filter.children:
|
|
128
129
|
yield from self._process_query(child, records=records)
|
|
129
130
|
|
|
@@ -186,8 +187,10 @@ def _process_wildcard_tail(index: Index, filter_value: str) -> Iterator[Record]:
|
|
|
186
187
|
|
|
187
188
|
# Yield all records in range
|
|
188
189
|
record = cursor.record()
|
|
189
|
-
while record is not None
|
|
190
|
+
while record is not None:
|
|
190
191
|
yield record
|
|
192
|
+
if record == end:
|
|
193
|
+
break
|
|
191
194
|
record = cursor.next()
|
|
192
195
|
|
|
193
196
|
|
|
@@ -202,7 +202,7 @@ class Schema:
|
|
|
202
202
|
# This _should_ have all the attribute and class schema entries
|
|
203
203
|
# We used to perform an index search on objectClass (ATTc0, INDEX_00000000), but apparently
|
|
204
204
|
# not all databases have this index
|
|
205
|
-
dmd = db.
|
|
205
|
+
dmd = db.dmd()
|
|
206
206
|
|
|
207
207
|
# We bootstrapped these earlier
|
|
208
208
|
attribute_schema = self.lookup_class(name="attributeSchema")
|
|
@@ -232,7 +232,7 @@ class Schema:
|
|
|
232
232
|
)
|
|
233
233
|
|
|
234
234
|
# Load user-defined OID prefixes
|
|
235
|
-
if (prefix_map :=
|
|
235
|
+
if (prefix_map := dmd.get("prefixMap")) is not None:
|
|
236
236
|
self._oid_idx_to_prefix_index.update(parse_prefix_map(prefix_map))
|
|
237
237
|
# Rebuild the reverse index
|
|
238
238
|
self._oid_prefix_to_idx_index = {prefix: idx for idx, prefix in self._oid_idx_to_prefix_index.items()}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import struct
|
|
4
|
-
from enum import IntEnum, IntFlag
|
|
4
|
+
from enum import Flag, IntEnum, IntFlag, auto
|
|
5
5
|
from typing import TYPE_CHECKING, Any
|
|
6
6
|
from uuid import UUID
|
|
7
7
|
|
|
@@ -18,6 +18,23 @@ if TYPE_CHECKING:
|
|
|
18
18
|
from dissect.database.ese.ntds.schema import AttributeEntry
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
class DatabaseFlags(Flag):
|
|
22
|
+
"""Database flags that are stored in the hiddentable.
|
|
23
|
+
|
|
24
|
+
The flags are weirdly stored as ``1``, ``0`` or ``\x00`` in a byte array.
|
|
25
|
+
To make parsing a bit easier, we use the index of each flag in this class as the character offset in the byte array.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
AUXCLASS = auto()
|
|
29
|
+
SD_CONVERSION_REQUIRED = auto()
|
|
30
|
+
ROOT_GUID_UPDATED = auto()
|
|
31
|
+
ADAM = auto()
|
|
32
|
+
ASCII_INDICES_REBUILT = auto()
|
|
33
|
+
SHOW_IN_AB_ARRAY_REBUILD = auto()
|
|
34
|
+
UPDATE_NC_TYPE_REQUIRED = auto()
|
|
35
|
+
LINK_QUOTA_USN = auto()
|
|
36
|
+
|
|
37
|
+
|
|
21
38
|
# https://learn.microsoft.com/en-us/windows/win32/adschema/a-instancetype
|
|
22
39
|
class InstanceType(IntFlag):
|
|
23
40
|
HeadOfNamingContext = 0x00000001
|
|
@@ -102,10 +119,10 @@ def _pek_decrypt(db: Database, value: bytes) -> bytes:
|
|
|
102
119
|
Returns:
|
|
103
120
|
The decrypted data blob, or the original value if the PEK is locked.
|
|
104
121
|
"""
|
|
105
|
-
if db.
|
|
122
|
+
if db.pek is None or not db.pek.unlocked:
|
|
106
123
|
return value
|
|
107
124
|
|
|
108
|
-
return db.
|
|
125
|
+
return db.pek.decrypt(value)
|
|
109
126
|
|
|
110
127
|
|
|
111
128
|
def _decode_supplemental_credentials(db: Database, value: bytes) -> dict[str, bytes] | bytes:
|
|
@@ -118,10 +135,10 @@ def _decode_supplemental_credentials(db: Database, value: bytes) -> dict[str, by
|
|
|
118
135
|
Returns:
|
|
119
136
|
A dictionary mapping credential types to their data blobs, or the original value if the PEK is locked.
|
|
120
137
|
"""
|
|
121
|
-
if db.
|
|
138
|
+
if db.pek is None or not db.pek.unlocked:
|
|
122
139
|
return value
|
|
123
140
|
|
|
124
|
-
value = db.
|
|
141
|
+
value = db.pek.decrypt(value)
|
|
125
142
|
header = c_ds.USER_PROPERTIES_HEADER(value)
|
|
126
143
|
|
|
127
144
|
result = {}
|
|
@@ -222,12 +239,12 @@ def _decode_pwd_history(db: Database, value: list[bytes]) -> list[bytes]:
|
|
|
222
239
|
Returns:
|
|
223
240
|
A list of decrypted password hashes, or the original value if the PEK is locked.
|
|
224
241
|
"""
|
|
225
|
-
if db.
|
|
242
|
+
if db.pek is None or not db.pek.unlocked:
|
|
226
243
|
return value
|
|
227
244
|
|
|
228
245
|
result = []
|
|
229
246
|
for buf in value:
|
|
230
|
-
buf = db.
|
|
247
|
+
buf = db.pek.decrypt(buf)
|
|
231
248
|
# The history attributes can contain multiple hashes concatenated together, so we need to split them up
|
|
232
249
|
# NT and LM hashes are both 16 bytes long
|
|
233
250
|
result.extend(buf[i : i + 16] for i in range(0, len(buf), 16))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dissect.database
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.dev8
|
|
4
4
|
Summary: A Dissect module implementing parsers for various database formats, including Berkeley DB, Microsofts Extensible Storage Engine (ESE) and SQLite3
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect.database.egg-info/SOURCES.txt
RENAMED
|
@@ -116,6 +116,7 @@ dissect/database/ese/ntds/objects/msds_resourceproperty.py
|
|
|
116
116
|
dissect/database/ese/ntds/objects/msds_resourcepropertylist.py
|
|
117
117
|
dissect/database/ese/ntds/objects/msds_shadowprincipalcontainer.py
|
|
118
118
|
dissect/database/ese/ntds/objects/msds_valuetype.py
|
|
119
|
+
dissect/database/ese/ntds/objects/msfve_recoveryinformation.py
|
|
119
120
|
dissect/database/ese/ntds/objects/msimaging_psps.py
|
|
120
121
|
dissect/database/ese/ntds/objects/mskds_provserverconfiguration.py
|
|
121
122
|
dissect/database/ese/ntds/objects/msmqenterprisesettings.py
|
|
@@ -34,6 +34,13 @@ def adam() -> Iterator[NTDS]:
|
|
|
34
34
|
yield NTDS(fh)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
@pytest.fixture(scope="module")
|
|
38
|
+
def fve() -> Iterator[NTDS]:
|
|
39
|
+
"""NTDS file with BitLocker recovery information."""
|
|
40
|
+
for fh in open_file_gz("_data/ese/ntds/fve/ntds.dit.gz"):
|
|
41
|
+
yield NTDS(fh)
|
|
42
|
+
|
|
43
|
+
|
|
37
44
|
@pytest.fixture(scope="module")
|
|
38
45
|
def large() -> Iterator[NTDS]:
|
|
39
46
|
"""Large NTDS file for performance testing.
|
|
@@ -13,6 +13,23 @@ if TYPE_CHECKING:
|
|
|
13
13
|
from dissect.database.ese.ntds import NTDS
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
def test_dsa(goad: NTDS) -> None:
|
|
17
|
+
"""Test retrieval of the NTDS DSA object and its associated domain and features."""
|
|
18
|
+
dsa = goad.db.dsa()
|
|
19
|
+
assert dsa is not None
|
|
20
|
+
assert dsa.domain() is not None
|
|
21
|
+
assert dsa.domain().name == "sevenkingdoms"
|
|
22
|
+
assert [f.name for f in dsa.features()] == ["Recycle Bin Feature"]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_dc(goad: NTDS) -> None:
|
|
26
|
+
"""Test retrieval of the domain controller objects and their associated computer and managedBy links."""
|
|
27
|
+
dc = goad.db.dc()
|
|
28
|
+
assert dc.name == "KINGSLANDING"
|
|
29
|
+
assert dc.computer() is not None
|
|
30
|
+
assert dc.computer().name == "KINGSLANDING"
|
|
31
|
+
|
|
32
|
+
|
|
16
33
|
def test_groups(goad: NTDS) -> None:
|
|
17
34
|
groups = sorted(goad.groups(), key=lambda x: x.distinguished_name)
|
|
18
35
|
|
|
@@ -303,3 +320,34 @@ def test_backup_keys(goad: NTDS) -> None:
|
|
|
303
320
|
hashlib.sha256(keys[1].public_key).hexdigest()
|
|
304
321
|
== "398fef9281677096b18785d0ad000251d41f76b82e28687718d6a9812ddaca8a"
|
|
305
322
|
)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def test_fve_recovery_information(fve: NTDS) -> None:
|
|
326
|
+
"""Test retrieval of BitLocker recovery information."""
|
|
327
|
+
computer = next(c for c in fve.computers() if c.name == "WIN11")
|
|
328
|
+
assert isinstance(computer, Computer)
|
|
329
|
+
|
|
330
|
+
recovery_info = list(computer.fve_recovery_information())
|
|
331
|
+
assert len(recovery_info) == 1
|
|
332
|
+
assert recovery_info[0].volume_guid == UUID("616127c1-403a-4bdf-9213-42c285cf9ee7")
|
|
333
|
+
assert recovery_info[0].recovery_guid == UUID("1d3184e4-ff3f-44f8-9255-32d1728f6172")
|
|
334
|
+
assert recovery_info[0].recovery_password == "197307-494857-485111-648725-619432-662057-360844-079310"
|
|
335
|
+
assert recovery_info[0].key_package == bytes.fromhex(
|
|
336
|
+
"d40100000100000030000000d4010000c12761613a40df4b921342c285cf9ee7"
|
|
337
|
+
"0100000000000000a0bad003caa5dc015000030005000100a039ebd4c8a5dc01"
|
|
338
|
+
"090000003a621f05e8ca419a50af679b12eef8b0dba5cef0249ab9a509164767"
|
|
339
|
+
"2ff5d3ea058671c43643fbc6f503f5fb966f6e61acda9b5d44ad4730ca200fe9"
|
|
340
|
+
"3c01020008000100e484311d3ffff844925532d1728f61721040cdd6c8a5dc01"
|
|
341
|
+
"00000008ac0000000300010000100000b351f88395b15fc67a7bcbf9132ba131"
|
|
342
|
+
"4000120005000100a039ebd4c8a5dc0105000000373c16060ab99c0619679931"
|
|
343
|
+
"1b2f3cfccb4ca31f6ae9dbd41c5c67a605674db0b96512e4184c815bc4d38ad1"
|
|
344
|
+
"5000130005000100a039ebd4c8a5dc01060000002ee39c79df7a782cead1fb91"
|
|
345
|
+
"73b073b5d512e054c9700c69076cf7a374e066b13b56fec03e12fa623acaaab0"
|
|
346
|
+
"702141d694cb726163f5b4da002a5cc85000000005000100a039ebd4c8a5dc01"
|
|
347
|
+
"07000000df655b5d65e9a8d969c990083a846ca8c34708334d4710b5fb532887"
|
|
348
|
+
"a9689ff9e1191521f5abe368cf5476e82cd2ecad01ba90b6065cd7e87447a8ad"
|
|
349
|
+
"1c00000015000100f06475dec8a5dc01f06475dec8a5dc011000020018000f00"
|
|
350
|
+
"0f00010000400e04000000000020000000000000"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
assert recovery_info[0].computer() == computer
|
|
@@ -2,6 +2,8 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
|
+
from dissect.database.ese.ntds.util import DatabaseFlags
|
|
6
|
+
|
|
5
7
|
if TYPE_CHECKING:
|
|
6
8
|
from dissect.database.ese.ntds import NTDS
|
|
7
9
|
|
|
@@ -44,6 +46,8 @@ def test_pek(goad: NTDS) -> None:
|
|
|
44
46
|
|
|
45
47
|
def test_pek_adam(adam: NTDS) -> None:
|
|
46
48
|
"""Test PEK unlocking and decryption for AD LDS NTDS.dit."""
|
|
49
|
+
assert DatabaseFlags.ADAM in adam.db.flags
|
|
50
|
+
|
|
47
51
|
# The PEK in AD LDS is derived within the database itself
|
|
48
52
|
assert adam.pek.unlocked
|
|
49
53
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/tools/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/bsd/tools/c_rpm.pyi
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_database-1.2.dev6 → dissect_database-1.2.dev8}/dissect/database/ese/ntds/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|