diff --git a/content/exchange/artifacts/Windows.Vhdx.RemapConfigBuilder.yaml b/content/exchange/artifacts/Windows.Vhdx.RemapConfigBuilder.yaml new file mode 100644 index 00000000000..a3e44741463 --- /dev/null +++ b/content/exchange/artifacts/Windows.Vhdx.RemapConfigBuilder.yaml @@ -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_(?.*).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: "" + 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 - ' + from: + accessor: raw_ntfs + prefix: | + { + "DelegateAccessor": "offset", + "Delegate": { + "DelegateAccessor": "vhdx", + "DelegatePath": "", + "Path":"/" + }, + "Path": "" + } + "on": + accessor: ntfs + prefix: '\\.\C:\Users\' + path_type: ntfs + + - type: mount + description: 'File - ' + from: + accessor: raw_ntfs + prefix: | + { + "DelegateAccessor": "offset", + "Delegate": { + "DelegateAccessor": "vhdx", + "DelegatePath": "", + "Path":"/" + }, + "Path": "" + } + "on": + accessor: file + prefix: 'C:\Users\' + path_type: windows + + - type: mount + description: 'Auto - ' + from: + accessor: raw_ntfs + prefix: | + { + "DelegateAccessor": "offset", + "Delegate": { + "DelegateAccessor": "vhdx", + "DelegatePath": "", + "Path":"/" + }, + "Path": "" + } + "on": + accessor: auto + prefix: 'C:\Users\' + path_type: windows + + - type: mount + description: 'Registry - NTUSER.DAT' + from: + accessor: raw_reg + prefix: |- + { + "Path": "/", + "DelegateAccessor": "raw_ntfs", + "Delegate": { + "DelegateAccessor":"offset", + "Delegate": { + "DelegateAccessor": "vhdx", + "DelegatePath": "", + "Path": "/" + }, + "Path":"/NTUSER.DAT" + } + } + path_type: registry + "on": + accessor: registry + prefix: HKEY_USERS\ + path_type: registry + + - type: mount + description: 'Registry - UsrClass' + from: + accessor: raw_reg + prefix: |- + { + "Path": "/", + "DelegateAccessor": "raw_ntfs", + "Delegate": { + "DelegateAccessor":"offset", + "Delegate": { + "DelegateAccessor": "vhdx", + "DelegatePath": "", + "Path": "/" + }, + "Path":"/AppData/Local/Microsoft/Windows/UsrClass.dat" + } + } + path_type: registry + "on": + accessor: registry + prefix: HKEY_USERS\_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="", + replace=virtualHostname + "_" + firstBatchUser, + source=RemappingHeader) + + // Create the user sections of the remapping file + LET UserRemapping = SELECT + regex_replace(re="", + replace=userProfile.Username, source= + regex_replace(re="", + replace="/Profile", source= + regex_replace(re="", + replace=vhdxOffset, source= + regex_replace(re="", + 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) \ No newline at end of file diff --git a/content/exchange/artifacts/Windows.Vhdx.Sys.Users.yaml b/content/exchange/artifacts/Windows.Vhdx.Sys.Users.yaml new file mode 100644 index 00000000000..0828cea981c --- /dev/null +++ b/content/exchange/artifacts/Windows.Vhdx.Sys.Users.yaml @@ -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) diff --git a/content/exchange/artifacts/Windows.Vhdx.VirtualClientRemover.yaml b/content/exchange/artifacts/Windows.Vhdx.VirtualClientRemover.yaml new file mode 100644 index 00000000000..2ccc67d429d --- /dev/null +++ b/content/exchange/artifacts/Windows.Vhdx.VirtualClientRemover.yaml @@ -0,0 +1,76 @@ +name: Windows.Vhdx.VirtualClientRemover +description: | + Kill the Velociraptor agent used for the VHDX profiles virtual host. + + This artifact is part of the Vhdx Suite. This suite requires to + have the custom `Windows.Sys.Users` override the server to work properly. + +author: Yann Malherbe - @mirwitch + +reference: + - https://labs.infoguard.ch/posts/automation_of_vhdx_investigations/ + +type: CLIENT + +implied_permissions: + - EXECVE + - FILESYSTEM_WRITE + +parameters: + - name: RemappingFile + type: string + default: "\\\\Vhdx\\\\Remapping\\\\" + description: "Specific remapping file or directory to target." + + - name: RemoveConfiguration + description: "If enabled, deletes Vhdx folder and its subfolders." + type: bool + + - name: ReallyKillProcess + description: "If enabled, terminates running Velociraptor processes." + type: bool + +sources: + - precondition: + SELECT OS From info() where OS = 'windows' + + query: | + + LET targets = SELECT Name as ProcessName, Exe, CommandLine, Pid + FROM Artifact.Windows.System.Pslist(ProcessRegex="Velociraptor", CommandLineRegex=RemappingFile) + + LET kill_targets = SELECT * FROM foreach( + row= targets, + query={ + SELECT ProcessName,Exe,CommandLine,Pid, + dict(ReturnCode=ReturnCode,Complete=Complete,Stdout=Stdout,Stderr=Stderr) as Execve, + if(condition= Stdout=~'^SUCCESS', + then= TRUE, + else= FALSE) as Killed + FROM execve( + argv=["taskkill", "/PID", Pid, "/T", "/F"]) + }) + + + + // Retrieve the directory from the running Velociraptor executable + LET veloInfo = SELECT Exe FROM info() + LET veloExe = SELECT * FROM glob(globs=veloInfo.Exe) + LET vhdxFolder = SELECT * FROM glob(globs=strip(string=veloExe.OSPath.Dirname.String, suffix=" ") + '\\Vhdx{,\\**}') ORDER BY OSPath DESC + + + LET deleteVhdxFolder = SELECT *, rm(filename=OSPath) as Removed + FROM vhdxFolder + WHERE log(message="Removing " + OSPath) + + LET RemoveConfiguration <= SELECT * FROM if(condition=RemoveConfiguration, + then=deleteVhdxFolder, + else= {SELECT *, FALSE as Deleted FROM vhdxFolder}) + + SELECT * + FROM if(condition=ReallyKillProcess, + then= kill_targets, + else= { SELECT *, FALSE as Killed FROM targets } ) + + + diff --git a/content/exchange/artifacts/Windows.Vhdx.VirtualClientRunner.yaml b/content/exchange/artifacts/Windows.Vhdx.VirtualClientRunner.yaml new file mode 100644 index 00000000000..55deada1a5a --- /dev/null +++ b/content/exchange/artifacts/Windows.Vhdx.VirtualClientRunner.yaml @@ -0,0 +1,119 @@ +name: Windows.Vhdx.VirtualClientRunner +description: | + Run the Velociraptor agent using the remapping configuration created. This + agent allow to virtually map the VHDX profiles into virtual Velociraptor agents. + + Two ways to execute agents exist: + - Using native VQL using workers that will be kill once the max execution + time is reached. + - Leveraging PowerShell `Start-Process` cmdlet allowing to run the agents + in the background and independant from the running artifact. + + There is no persistence mechanism to keep the process running after reboot. + The artifact need to be re-run to have the virtual Velociraptor agents back. + + This artifact is part of the Vhdx Suite. This suite requires to have + the `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: + - EXECVE + - FILESYSTEM_WRITE + +parameters: + - name: customLabel + type: string + default: "remapped_profile" + description: "Label to assign to virtual clients (must match label used in Windows.Sys.Users)" + + - name: remappingFile + type: regex + default: "." + description: "One or more remapping YAML files to launch." + + - name: workers + type: int + default: 100 + description: "Number of workers for the native VQL runner." + + - name: PowerShellRunner + type: bool + default: FALSE + description: "Choose to run the agent using PowerShell Start-Process cmdlet." + +sources: + - precondition: + SELECT OS From info() where OS = 'windows' + + query: | + // Retrieve the directory from the running Velociraptor executable + LET veloInfo = SELECT Exe FROM info() + LET veloFolderPath = pathspec(parse=veloInfo[0].Exe).Dirname + + // Create Writeback directory + LET copyFile <= SELECT copy( + filename="", + accessor="data", + dest=veloFolderPath + "\\Vhdx\\Writeback\\empty", + create_directories=TRUE) + FROM scope() + + // Extract username from filename + LET GetUsername(Filename) = regex_replace(source=Filename, re="\\.yaml", replace="") + + // Get the config file paths + LET configFiles = SELECT OSPath.String AS RemappingFile, + "C:\\Windows\\Temp\\velociraptor_Vhdx_Buffer_" + GetUsername(Filename=Name) + ".bin" AS LocalBufferPath, + veloFolderPath.Path + "\\Vhdx\\Writeback\\Vhdx_" + GetUsername(Filename=Name) + ".yaml" AS WritebackFilename + FROM glob(globs=veloFolderPath + "\\Vhdx\\Remapping\\*") + WHERE Name =~ remappingFile + + + // Run the agent using PowerShell Start-Process cmdlet + LET powerShellAgentRunner = SELECT RemappingFile, Complete, ReturnCode, Stdout, Stderr FROM execve(argv=[ + "powershell", + "-ExecutionPolicy", "Bypass", + "-NoProfile", + "-Command", + "Start-Process -FilePath '"+ veloInfo[0].Exe +"' -ArgumentList '--config client.config.yaml --config.client-writeback-windows=\"" + WritebackFilename + "\" --config.client-local-buffer-filename-windows=\"" + LocalBufferPath + "\" --remap \"" + RemappingFile + "\" --config.client-labels=" + customLabel + " client' -WorkingDirectory '" + veloFolderPath.Path + "' -WindowStyle Hidden" + ]) + + // Run the agent using the native VQL + LET agentRunner = SELECT * + FROM execve(argv=[veloInfo[0].Exe, + "--remap", RemappingFile, + "--config", "client.config.yaml", + "--config.client-writeback-linux", WritebackFilename, + "--config.client-writeback-windows", WritebackFilename, + "--config.client-writeback-darwin", WritebackFilename, + "--config.client-local-buffer-filename-windows", LocalBufferPath, + "--config.client-labels", customLabel, + "-v", "client"], + cwd=veloFolderPath, + sep="\n") + + + // Run the agent for each remapping file using PowerShell Start-Process cmdlet + LET powerShellAgentRunners = SELECT * FROM foreach( + row=configFiles, + query=powerShellAgentRunner + ) WHERE log(message="Running agent using PowerShell Start-Process cmdlet for " + RemappingFile) + + // Run the agent using the native Velociraptor binary + LET agentRunners = SELECT * FROM foreach( + row=configFiles, + query=agentRunner, + async=TRUE, + workers=workers + ) + + // Run the virtual Velociraptor agent via PowerShell or native VQL + SELECT * FROM if(condition=PowerShellRunner, then=powerShellAgentRunners, else=agentRunners)