-
Notifications
You must be signed in to change notification settings - Fork 240
VHDX artifact suite #1115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
mirwitch
wants to merge
6
commits into
Velocidex:master
Choose a base branch
from
mirwitch:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
VHDX artifact suite #1115
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
e11fe4d
VHDX artifact suite
mirwitch 0d5f170
Rename Windows.Sys.Users to unique name and match Vhdx suite
mirwitch de0f4a3
Add usrclass.dat remapping
mirwitch 9789fa7
Fix "undefined" rows variable coming from batch function
mirwitch d5dbe40
Simplify path manipulation
mirwitch 11ab2c9
Add native VQL runner
mirwitch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
292 changes: 292 additions & 0 deletions
292
content/exchange/artifacts/Windows.Vhdx.RemapConfigBuilder.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
name: Windows.Vhdx.RemapConfigBuilder | ||
description: | | ||
Create remapping configuration YAML file(s) to virtually mount | ||
VHDX profiles into virtual Velociraptor clients. | ||
|
||
This artifact is part of the Vhdx Suite. This suite requires to have | ||
the Velociraptor server artifact `Windows.Sys.Users` override on the | ||
server to work properly. | ||
|
||
Read the dedicated blog post before using this artifact. | ||
|
||
author: Yann Malherbe - @mirwitch | ||
|
||
reference: | ||
- https://labs.infoguard.ch/posts/automation_of_vhdx_investigations/ | ||
|
||
type: CLIENT | ||
|
||
implied_permissions: | ||
- FILESYSTEM_WRITE | ||
|
||
parameters: | ||
- name: vhdxFolderPath | ||
type: string | ||
default: "F:\\vhdx\\" | ||
description: "Directory containing VHDX profile files." | ||
|
||
- name: usernameExtractor | ||
type: regex | ||
default: "profile_(?<Username>.*).vhdx" | ||
description: "Regex used to extract usernames from filenames." | ||
|
||
- name: user | ||
type: regex | ||
default: Administrator | ||
description: "Optional filter to restrict which profiles to process." | ||
|
||
- name: virtualHostname | ||
type: string | ||
default: "VHDX" | ||
description: "Hostname to assign to the virtual clients." | ||
|
||
- name: vhdxOffset | ||
type: hidden | ||
default: 1048576 | ||
description: "NTFS start offset inside VHDX." | ||
|
||
- name: batchSize | ||
type: int | ||
default: 30 | ||
description: "Number of profiles per virtual client." | ||
|
||
sources: | ||
- precondition: | ||
SELECT OS From info() where OS = 'windows' | ||
|
||
query: | | ||
// Static remapping header | ||
LET RemappingHeader =''' | ||
remappings: | ||
- type: permissions | ||
permissions: | ||
- COLLECT_CLIENT | ||
- FILESYSTEM_READ | ||
- FILESYSTEM_WRITE | ||
- READ_RESULTS | ||
- MACHINE_STATE | ||
- SERVER_ADMIN | ||
- type: impersonation | ||
os: windows | ||
hostname: "<VIRTUAL_HOSTNAME>" | ||
env: | ||
- key: SystemRoot | ||
value: C:\Windows | ||
- key: WinDir | ||
value: C:\Windows | ||
disabled_functions: | ||
- amsi | ||
- lookupSID | ||
- token | ||
disabled_plugins: | ||
- users | ||
- certificates | ||
- handles | ||
- pslist | ||
- interfaces | ||
- modules | ||
- netstat | ||
- partitions | ||
- proc_dump | ||
- proc_yara | ||
- vad | ||
- winobj | ||
- wmi | ||
|
||
- type: shadow | ||
from: | ||
accessor: data | ||
"on": | ||
accessor: data | ||
|
||
- type: shadow | ||
from: | ||
accessor: raw_reg | ||
"on": | ||
accessor: raw_reg | ||
|
||
- type: shadow | ||
from: | ||
accessor: zip | ||
"on": | ||
accessor: zip | ||
''' | ||
|
||
// Remapping required per user | ||
LET RemappingUser = ''' | ||
- type: mount | ||
description: 'NTFS - <USERNAME>' | ||
from: | ||
accessor: raw_ntfs | ||
prefix: | | ||
{ | ||
"DelegateAccessor": "offset", | ||
"Delegate": { | ||
"DelegateAccessor": "vhdx", | ||
"DelegatePath": "<VHDX_PATH>", | ||
"Path":"/<VHDX_OFFSET>" | ||
}, | ||
"Path": "<PROFILE_PATH>" | ||
} | ||
"on": | ||
accessor: ntfs | ||
prefix: '\\.\C:\Users\<USERNAME>' | ||
path_type: ntfs | ||
|
||
- type: mount | ||
description: 'File - <USERNAME>' | ||
from: | ||
accessor: raw_ntfs | ||
prefix: | | ||
{ | ||
"DelegateAccessor": "offset", | ||
"Delegate": { | ||
"DelegateAccessor": "vhdx", | ||
"DelegatePath": "<VHDX_PATH>", | ||
"Path":"/<VHDX_OFFSET>" | ||
}, | ||
"Path": "<PROFILE_PATH>" | ||
} | ||
"on": | ||
accessor: file | ||
prefix: 'C:\Users\<USERNAME>' | ||
path_type: windows | ||
|
||
- type: mount | ||
description: 'Auto - <USERNAME>' | ||
from: | ||
accessor: raw_ntfs | ||
prefix: | | ||
{ | ||
"DelegateAccessor": "offset", | ||
"Delegate": { | ||
"DelegateAccessor": "vhdx", | ||
"DelegatePath": "<VHDX_PATH>", | ||
"Path":"/<VHDX_OFFSET>" | ||
}, | ||
"Path": "<PROFILE_PATH>" | ||
} | ||
"on": | ||
accessor: auto | ||
prefix: 'C:\Users\<USERNAME>' | ||
path_type: windows | ||
|
||
- type: mount | ||
description: 'Registry - <USERNAME> NTUSER.DAT' | ||
from: | ||
accessor: raw_reg | ||
prefix: |- | ||
{ | ||
"Path": "/", | ||
"DelegateAccessor": "raw_ntfs", | ||
"Delegate": { | ||
"DelegateAccessor":"offset", | ||
"Delegate": { | ||
"DelegateAccessor": "vhdx", | ||
"DelegatePath": "<VHDX_PATH>", | ||
"Path": "/<VHDX_OFFSET>" | ||
}, | ||
"Path":"<PROFILE_PATH>/NTUSER.DAT" | ||
} | ||
} | ||
path_type: registry | ||
"on": | ||
accessor: registry | ||
prefix: HKEY_USERS\<USERNAME> | ||
path_type: registry | ||
|
||
- type: mount | ||
description: 'Registry - <USERNAME> UsrClass' | ||
from: | ||
accessor: raw_reg | ||
prefix: |- | ||
{ | ||
"Path": "/", | ||
"DelegateAccessor": "raw_ntfs", | ||
"Delegate": { | ||
"DelegateAccessor":"offset", | ||
"Delegate": { | ||
"DelegateAccessor": "vhdx", | ||
"DelegatePath": "<VHDX_PATH>", | ||
"Path": "/<VHDX_OFFSET>" | ||
}, | ||
"Path":"<PROFILE_PATH>/AppData/Local/Microsoft/Windows/UsrClass.dat" | ||
} | ||
} | ||
path_type: registry | ||
"on": | ||
accessor: registry | ||
prefix: HKEY_USERS\<USERNAME>_Classes | ||
path_type: registry | ||
''' | ||
|
||
// Get the list of user profiles of interest | ||
LET userProfilesList = SELECT *, | ||
parse_string_with_regex( | ||
string=Name, | ||
regex=usernameExtractor | ||
) AS userProfile | ||
FROM glob(globs=vhdxFolderPath+"/*.vhdx") | ||
WHERE userProfile.Username AND userProfile.Username =~ user | ||
|
||
|
||
// Split the user list into batches | ||
LET userBatch = SELECT rows AS user_batch | ||
FROM batch(query={ | ||
SELECT * | ||
FROM userProfilesList | ||
}, batch_size=batchSize) | ||
|
||
|
||
// Create the header of the remapping file | ||
LET HeaderRemapping = regex_replace(re="<VIRTUAL_HOSTNAME>", | ||
replace=virtualHostname + "_" + firstBatchUser, | ||
source=RemappingHeader) | ||
|
||
// Create the user sections of the remapping file | ||
LET UserRemapping = SELECT | ||
regex_replace(re="<USERNAME>", | ||
replace=userProfile.Username, source= | ||
regex_replace(re="<PROFILE_PATH>", | ||
replace="/Profile", source= | ||
regex_replace(re="<VHDX_OFFSET>", | ||
replace=vhdxOffset, source= | ||
regex_replace(re="<VHDX_PATH>", | ||
replace=regex_replace( | ||
re="\\\\", replace="/", source=OSPath), | ||
source=RemappingUser) | ||
))) AS Content | ||
FROM scope() | ||
|
||
// Iterate on the users part of the bulk | ||
LET BulkUserRemapping = SELECT * FROM foreach( | ||
row=user_batch, | ||
query=UserRemapping | ||
) | ||
|
||
// Write the remapping content in a temp file | ||
LET tmpFile = tempfile( | ||
data=HeaderRemapping + BulkUserRemapping.Content, | ||
remove_last=TRUE | ||
) | ||
|
||
// Retrieve the directory from the running Velociraptor executable | ||
LET veloInfo = SELECT Exe FROM info() | ||
|
||
// Get the first user of the batch | ||
LET firstBatchUser = user_batch[0].userProfile.Username | ||
|
||
// Get the remapping filename | ||
LET remappingFilename = firstBatchUser + ".yaml" | ||
|
||
// Copy the file to the remapping YAML file | ||
LET copyFile = SELECT copy( | ||
filename=tmpFile, | ||
dest=pathspec(parse=veloInfo[0].Exe).Dirname + "Vhdx" + "Remapping" + remappingFilename, | ||
create_directories=TRUE) AS CreatedConfig | ||
FROM scope() | ||
|
||
|
||
|
||
// Create dedicated YAML file for each batch of users | ||
SELECT * FROM foreach(row=userBatch, query=copyFile) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
name: Windows.Vhdx.Sys.Users | ||
description: | | ||
List User accounts by inspecting registry keys. This method is a | ||
reliable indicator for users who have physically logged into the | ||
system and thereby created local profiles. | ||
|
||
This will not include domain users or the output from `NetUserEnum` | ||
- you should collect the `Windows.Sys.AllUsers` artifact to get all | ||
possible users on the system. | ||
|
||
This artifact should be rename to replace the official | ||
`Windows.Sys.Users` allowing to list the users for potential user | ||
profiles from virtual Velociraptor clients. | ||
|
||
Read the dedicated blog post before using this artifact. | ||
|
||
author: Yann Malherbe - @mirwitch | ||
|
||
reference: | ||
- https://labs.infoguard.ch/posts/automation_of_vhdx_investigations/ | ||
|
||
parameters: | ||
- name: remoteRegKey | ||
default: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\* | ||
description: "Location of the registry key holding the profile list." | ||
|
||
- name: labelName | ||
default: "remapped_profile" | ||
type: string | ||
description: "Client label that signals the use of VHDX-based enumeration." | ||
|
||
imports: | ||
- Windows.Sys.AllUsers | ||
|
||
sources: | ||
- precondition: | ||
SELECT OS From info() where OS = 'windows' | ||
|
||
query: | | ||
|
||
LET GetTimestamp(High, Low) = if(condition=High, | ||
then=timestamp(winfiletime=High * 4294967296 + Low)) | ||
|
||
// lookupSID() may not be available on deaddisk analysis | ||
LET Standard = SELECT split(string=Key.OSPath.Basename, sep="-")[-1] as Uid, | ||
"" AS Gid, | ||
LookupSIDCache(SID=Key.OSPath.Basename || "") AS Name, | ||
Key.OSPath as Description, | ||
ProfileImagePath as Directory, | ||
Key.OSPath.Basename as UUID, | ||
Key.Mtime as Mtime, | ||
{ | ||
SELECT Mtime | ||
FROM stat(filename=expand(path=ProfileImagePath)) | ||
} AS HomedirMtime, | ||
dict(ProfileLoadTime=GetTimestamp( | ||
High=LocalProfileLoadTimeHigh, Low=LocalProfileLoadTimeLow), | ||
ProfileUnloadTime=GetTimestamp( | ||
High=LocalProfileUnloadTimeHigh, Low=LocalProfileUnloadTimeLow) | ||
) AS Data | ||
FROM read_reg_key(globs=remoteRegKey, accessor="registry") | ||
|
||
// User list for VHDX profiles emulating the Standard one | ||
LET UserProfile = SELECT | ||
OSPath.Components[-2] AS Uid, | ||
OSPath.Dirname AS Directory, | ||
OSPath.Components[-2] AS UUID, | ||
OSPath.Components[-2] AS Name, | ||
"" AS Gid, | ||
Mtime, | ||
Mtime AS HomedirMtime, | ||
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\" + OSPath.Components[-2] AS Description | ||
FROM glob(globs="C:/Users/*/NTUSER.DAT") | ||
|
||
// Get the labels of the agent | ||
LET agent_config = SELECT labels FROM config | ||
|
||
// Take the appropriate user list method | ||
SELECT * FROM if(condition=agent_config.labels=~labelName, then=UserProfile, else=Standard) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there are actually alot of registry paths to mount - like user class, sam etc. You are better off to use the supported remapping builder artifact for completeness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For user profiles, only NTUser.dat and UsrClass.dat are available. I added UsrClass with de0f4a3