Hello there! It has been a while since I wrote a blog, but I have been busy with other projects 🙂
NTFS has a file called $Secure that contains security descriptors for all files on the system. $Secure contains three streams with each stream containing different data to help retrieve the security descriptor for specific file. The following are the data streams for $Secure with there description:
- $SDH: Contains security descriptor hash and offset lookup in $SDS stream
- $SII: Contains security ID and offset lookup in $SDS stream. Security ID can be retrieved from the security ID field in $STANDARD_INFORMATION attribute present in every MFT record
- $SDS: Contains all security descriptors for all files and directories on the volume
$SDS Stream
The $SDS contains the most important data for digital forensics. This attribute contains a list of security descriptor with each security descriptor containing the following data:
- Object owner SID
- Object group SID
- Object Discretionary Access Control List (DACL), identify the users and groups that are assigned or denied access permissions on an object
- Object System Access Control List (SACL), SACLs makes it possible to monitor access to secured objects
$SDS Structure
Offset | Size | Type | Description |
---|---|---|---|
0 | 4 | u32 | Security descriptor hash |
4 | 4 | u32 | Security descriptor identifier, can be retrieve from MFT record in the $STANDARD_ INFORMATION attribute |
8 | 8 | u64 | Security descriptor data offset (in $SDS) |
16 | 4 | u32 | Security descriptor data size (in $SDS) |
20 | - | Security Descriptor Struct | Security descriptor struct data |
- | - | - | 16 bit alignment padding |
How to Find Security Descriptor for MFT Record?
Retrieve the security ID from $STANDARD_INFORMATION attribute in MFT record then parser the $SDS and lookup the security ID from the MFT record in the ID field in the $SDS record. The following is an example MFT record along with the corresponding security descriptor from $SDS:
{
"header": {
"signature": [
70,
73,
76,
69
],
"usa_offset": 48,
"usa_size": 3,
"metadata_transaction_journal": 580089845936,
"sequence": 306,
"hard_link_count": 1,
"first_attribute_record_offset": 56,
"flags": "ALLOCATED",
"used_entry_size": 384,
"total_entry_size": 1024,
"base_reference": {
"entry": 0,
"sequence": 0
},
"first_attribute_id": 5,
"record_number": 170557
},
"attributes": [
{
"header": {
"type_code": "StandardInformation",
"record_length": 96,
"form_code": 0,
"residential_header": {
"index_flag": 0
},
"name_size": 0,
"name_offset": null,
"data_flags": "(empty)",
"instance": 0,
"name": ""
},
"data": {
"created": "2021-01-23T14:40:32.114948Z",
"modified": "2021-01-23T14:42:17.245694Z",
"mft_modified": "2021-01-23T14:42:17.245694Z",
"accessed": "2022-07-16T00:04:01.549904Z",
"file_flags": "FILE_ATTRIBUTE_ARCHIVE",
"max_version": 0,
"version": 0,
"class_id": 0,
"owner_id": 0,
"security_id": 4538,
"quota": 0,
"usn": 38532584952
}
},
{
"header": {
"type_code": "FileName",
"record_length": 112,
"form_code": 0,
"residential_header": {
"index_flag": 1
},
"name_size": 0,
"name_offset": null,
"data_flags": "(empty)",
"instance": 2,
"name": ""
},
"data": {
"parent": {
"entry": 5,
"sequence": 5
},
"created": "2021-01-23T14:40:32.114948Z",
"modified": "2021-01-23T14:40:32.114948Z",
"mft_modified": "2021-01-23T14:40:32.114948Z",
"accessed": "2021-01-23T14:40:32.114948Z",
"logical_size": 0,
"physical_size": 0,
"flags": "FILE_ATTRIBUTE_ARCHIVE",
"reparse_value": 0,
"name_length": 8,
"namespace": "Win32AndDos",
"name": "test.txt"
}
},
{
"header": {
"type_code": "ObjectId",
"record_length": 40,
"form_code": 0,
"residential_header": {
"index_flag": 0
},
"name_size": 0,
"name_offset": null,
"data_flags": "(empty)",
"instance": 3,
"name": ""
},
"data": {
"object_id": "3C783C19-5D7C-11EB-BE9B-5076AFA95947",
"birth_volume_id": null,
"birth_object_id": null,
"domain_id": null
}
},
{
"header": {
"type_code": "DATA",
"record_length": 32,
"form_code": 0,
"residential_header": {
"index_flag": 0
},
"name_size": 0,
"name_offset": null,
"data_flags": "(empty)",
"instance": 1,
"name": ""
},
"data": "5445535431"
}
],
"valid_fixup": true
}
$SDS Record:
{
"hash": 3193908388,
"id": 4538,
"security_descriptor": {
"owner_sid": "S-1-5-32-544",
"group_sid": "S-1-5-21-412210041-3083678082-150370041-513",
"dacl": {
"revision": 2,
"count": 4,
"entries": [
{
"ace_type": "ACCESS_ALLOWED",
"ace_flags": "(empty)",
"data": {
"access_rights": 2032127,
"sid": "S-1-5-32-544"
}
},
{
"ace_type": "ACCESS_ALLOWED",
"ace_flags": "(empty)",
"data": {
"access_rights": 2032127,
"sid": "S-1-5-18"
}
},
{
"ace_type": "ACCESS_ALLOWED",
"ace_flags": "(empty)",
"data": {
"access_rights": 1179817,
"sid": "S-1-5-32-545"
}
},
{
"ace_type": "ACCESS_ALLOWED",
"ace_flags": "(empty)",
"data": {
"access_rights": 1245631,
"sid": "S-1-5-11"
}
}
]
},
"sacl": {
"revision": 2,
"count": 1,
"entries": [
{
"ace_type": "SYSTEM_MANDATORY_LABEL",
"ace_flags": "(empty)",
"data": {
"access_rights": 1,
"sid": "S-1-16-12288"
}
}
]
}
}
}
From the records above we can see that the file named test.txt is owned by the user with the SID S-1-5-32-544 (Administrators) and the group with SID S-1-5-21-412210041-3083678082-150370041-513 (Users)
What is the significance of this artifact?
Here are some examples of how $SDS artifact will help during Digital Forensics analysis:
- You have a malicious file deleted by the adversary, but the $MFT record of the file is still present? You can use the $SDS artifact to find the user that created this malicious file and mark that user as compromised to detect other artifacts generated by this user
- You found a webshell on a web server and wondered how it was dropped? You can check the $SDS artifact for the file owner to see if it is the web server process or another user. If it is the web server user, that likely means the adversary exploited a vulnerability in the web server and dropped the webshell. Otherwise, the webshell might have been dropped on the server by other means as a persistence
- Some crypto miners manipulate their files’ permissions to prevent other processes from accessing them. The $SDS artifact will help you to check the file permissions in an offline analysis
From the above examples, you can see how the $SDS artifact could be helpful during analysis.
SDSParser
I developed a parser in Rust 🦀 to parser the $SDS stream, You can download sds_parser from Github
Build
To build from source make sure you have Rust installed then run the following commands:
git clone https://github.com/AbdulRhmanAlfaifi/SDSParser-rs
cd SDSParser-rs
cargo build --release
USE Pre-Compiled Binaries
You can also use the pre-compiled binaries in the release section