-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c9f4638
commit 6a12610
Showing
5 changed files
with
547 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,75 @@ | ||
name: Windows.QEMU.ImgConvert | ||
|
||
description: | | ||
Downloads **QEMU image converter** and its required dynamic libraries compressed inside a `qemu-img.zip` file. Unzips the archive then launches the `qemu-img.exe` executable to convert the source file to the desired format. | ||
This artifact requires you to upload a ZIP archive containing `qemu-img.exe` and its required DLLs on the Velociraptor server, in order to serve it locally to the endpoints. | ||
**HOW TO USE:** | ||
1. Create the `qemu-img.zip` archive | ||
2. In the "*Tools*" section, click on "*QEMUImgZip*" | ||
3. Click on "*Select file*" to browse your file system and select the archive | ||
4. Click on "*Click to upload file*" | ||
5. Ensure the calculated hash is correct | ||
author: Synacktiv, Maxence Fossat - @cybiosity | ||
|
||
reference: | ||
- https://www.qemu.org/download/#windows | ||
- https://qemu.weilnetz.de/w64/ | ||
|
||
type: CLIENT | ||
|
||
tools: | ||
- name: QEMUImgZip | ||
serve_locally: true | ||
|
||
precondition: SELECT OS FROM info() WHERE OS = 'windows' | ||
|
||
parameters: | ||
- name: Source | ||
type: string | ||
description: Absolute path to the source file that should be converted. | ||
- name: Destination | ||
type: string | ||
description: Absolute path to the destination file, including filename. | ||
- name: OutputFormat | ||
type: string | ||
description: Destination format for the conversion. | ||
default: 'raw' | ||
|
||
required_permissions: | ||
- FILESYSTEM_READ | ||
- FILESYSTEM_WRITE | ||
- EXECVE | ||
|
||
sources: | ||
- query: | | ||
// Get the path to the zipfile | ||
LET zipfile <= SELECT * FROM Artifact.Generic.Utils.FetchBinary( | ||
ToolName= 'QEMUImgZip', | ||
IsExecutable=FALSE | ||
) | ||
// Build temporary folder to unzip | ||
LET tempfolder <= tempdir() | ||
// Unzip qemu-img.zip | ||
LET unzipping <= SELECT * FROM unzip( | ||
filename=zipfile.OSPath[0], | ||
accessor='auto', | ||
output_directory=tempfolder, | ||
type='zip' | ||
) | ||
// Call the binary and return its output in rows | ||
SELECT Destination, * FROM execve( | ||
argv=[ | ||
path_join(components=[tempfolder, 'qemu-img.exe']), | ||
'convert', | ||
Source, | ||
'-O', OutputFormat, | ||
Destination | ||
], sep='\n' | ||
) |
This file contains 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,69 @@ | ||
name: Windows.Veeam.Extract | ||
|
||
description: | | ||
Downloads and launches the **Veeam extract utility** on a Veeam full backup file (`.vbk`), incremental backup file (`.vib`) or reverse incremental backup file (`.vrb`). | ||
This artifact requires you to upload the CLI Veeam extract utility binary for Windows on the Velociraptor server, in order to serve it locally to the endpoints. | ||
**HOW TO USE:** | ||
1. Download the CLI Veeam extract utility (`Extract.exe`) using a registered Veeam account | ||
2. In the "*Tools*" section, click on "*VeeamExtract*" | ||
3. Click on "*Select file*" to browse your file system and select the binary | ||
4. Click on "*Click to upload file*" | ||
5. Ensure the calculated hash is correct to make sure you will launch the right binary | ||
author: Synacktiv, Maxence Fossat - @cybiosity | ||
|
||
reference: | ||
- https://helpcenter.veeam.com/docs/backup/vsphere/extract_utility.html | ||
|
||
type: CLIENT | ||
|
||
tools: | ||
- name: VeeamExtract | ||
serve_locally: true | ||
|
||
precondition: SELECT OS FROM info() WHERE OS = 'windows' | ||
|
||
parameters: | ||
- name: BackupFilePath | ||
type: string | ||
description: Absolute path to the backup file that needs to be extracted. | ||
- name: OutputFolderPath | ||
type: string | ||
description: Absolute path to the output folder where the extracted image will be placed. | ||
- name: VMName | ||
type: string | ||
description: Name of the machine to extract from the backup. Can be found in "VMName" field from the "Windows.Veeam.RestorePoints" artifacts. | ||
- name: HostName | ||
type: string | ||
description: Name of the backup host. Can be found in "HostName" field from the "Windows.Veeam.RestorePoints" artifacts. | ||
|
||
required_permissions: | ||
- FILESYSTEM_READ | ||
- FILESYSTEM_WRITE | ||
- EXECVE | ||
|
||
sources: | ||
- query: | | ||
// Get the path to the binary | ||
LET binary <= SELECT * FROM Artifact.Generic.Utils.FetchBinary( | ||
ToolName= 'VeeamExtract') | ||
// Build argv array for execve | ||
LET parameters <= (binary.OSPath[0], '-restore') | ||
LET parameters <= if( | ||
condition=VMName, | ||
then=parameters + ('-vm', VMName), | ||
else=parameters) | ||
LET parameters <= if( | ||
condition=HostName, | ||
then=parameters + ('-host', HostName), | ||
else=parameters) | ||
LET parameters <= parameters + (BackupFilePath, OutputFolderPath) | ||
// Call the binary and return its output in rows | ||
SELECT utf16(string=Stdout[1:]) AS Stdout, utf16(string=Stderr[1:]) AS Stderr | ||
FROM execve(argv=parameters, sep='\n') | ||
This file contains 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,133 @@ | ||
name: Windows.Veeam.ProcessBackups | ||
|
||
description: | | ||
**⚠️ USE WITH CAUTION ⚠️️** This artifact is not production-ready and should be considered as a proof-of-concept. It will write gigabytes of data inside the folder specified in `TemporaryFolderPath` parameter and then proceed to delete the files it has written. This artifact was tested on a very limited set of data and only aims to showcase the possibility of a remote Veeam forensics pipeline. | ||
Selects Veeam backups to extract based on filters provided in the `Filter` parameter. For each selected Veeam backup, extracts the data, converts it to raw disk image format if necessary, remaps paths to the correct partition in the disk image and launches a list of Velociraptor artifacts defined in `Windows.Veeam.ProcessDiskImage`. | ||
author: Synacktiv, Maxence Fossat - @cybiosity | ||
|
||
type: CLIENT | ||
|
||
parameters: | ||
- name: UseMetadataFiles | ||
description: Enable to list Restore Points using Veeam backup chain metadata files. Disable to use backup files directly (slower). | ||
type: bool | ||
default: TRUE | ||
- name: BackupRepositories | ||
description: List of Backup Repositories where ".vbm" or ".vbk", ".vib" and ".vrb" files should be looked for. | ||
type: csv | ||
default: | | ||
BackupRepoPath | ||
C:/BackupRepo1 | ||
D:/BackupRepo2 | ||
- name: Filter | ||
type: string | ||
description: VQL-format content of a "WHERE" clause to filter results from a "Windows.Veeam.RestorePoints" artifact. | ||
default: '' | ||
- name: TemporaryFolderPath | ||
type: string | ||
description: Absolute path to the temporary folder where the backups will be extracted. | ||
default: 'E:/TempOutput' | ||
|
||
precondition: SELECT OS FROM info() WHERE OS = 'windows' | ||
|
||
required_permissions: | ||
- FILESYSTEM_READ | ||
- FILESYSTEM_WRITE | ||
- EXECVE | ||
|
||
sources: | ||
- query: | | ||
// Hacky way to make sure the deaddisk image processing artifact is embedded | ||
LET _ = SELECT * FROM Artifact.Exchange.Windows.Veeam.ProcessDiskImage() | ||
// Change RestorePoints artifact according to UseMetadataFiles parameter | ||
LET restore_points_query <= if( | ||
condition=UseMetadataFiles, | ||
then='SELECT * FROM Artifact.Exchange.Windows.Veeam.RestorePoints.MetadataFiles(BackupRepositories=BackupRepositories)', | ||
else='SELECT * FROM Artifact.Exchange.Windows.Veeam.RestorePoints.BackupFiles(BackupRepositories=BackupRepositories)' | ||
) | ||
// Apply WHERE clause to the query based on the Filter parameter | ||
LET filtered_query <= if( | ||
condition=Filter, | ||
then=restore_points_query + ' WHERE ' + Filter, | ||
else=restore_points_query | ||
) | ||
// Execute constructed query to list selected Restore Points | ||
LET selected_restore_points = SELECT BackupFilePath, VMName, HostName, CreationTimeUTC, ExtractName, ExtractID | ||
FROM query(query=filtered_query, inherit=TRUE) | ||
// Extract data from backup and check for statement of success | ||
LET extract = SELECT BackupFilePath, VMName, HostName, CreationTimeUTC, ExtractName, ExtractID, TemporaryFolderPath, * | ||
FROM Artifact.Exchange.Windows.Veeam.Extract( | ||
BackupFilePath=BackupFilePath, | ||
OutputFolderPath=TemporaryFolderPath, | ||
VMName=VMName, | ||
HostName=HostName | ||
) WHERE Stdout =~ VMName+' is restored' | ||
// List extracted disks in .vhdx, .vmdk and raw format | ||
LET extracted_files = SELECT * FROM glob( | ||
globs='/*', | ||
root=path_join(components=[TemporaryFolderPath, ExtractName+'('+ExtractID+')']), | ||
accessor='auto' | ||
) WHERE Name =~ '^(.*\.vhdx|.*-flat\.vmdk|[0-9A-F]{8})$' | ||
// Convert files to raw disk image format, when applicable, and check for success | ||
LET converted_files = SELECT BackupFilePath, VMName, HostName, CreationTimeUTC, * FROM if( | ||
condition= Name =~ '^(.*\.vhdx|.*-flat\.vmdk)$', | ||
then={ | ||
SELECT * FROM Artifact.Exchange.Windows.QEMU.ImgConvert( | ||
Source=OSPath, | ||
Destination=path_join(components=[TemporaryFolderPath, Name+'.raw']), | ||
OutputFormat='raw' | ||
) WHERE Complete = TRUE AND ReturnCode = 0 | ||
}, | ||
else={ SELECT OSPath as Destination FROM scope() } | ||
) | ||
SELECT * FROM foreach(row=selected_restore_points, | ||
query={ | ||
SELECT * FROM foreach(row=extract, | ||
query={ | ||
SELECT * FROM chain(a={SELECT * FROM foreach(row=extracted_files, | ||
query={ | ||
SELECT * FROM foreach(row=converted_files, | ||
query={ | ||
SELECT * FROM chain(a={SELECT * FROM query( | ||
query={ | ||
SELECT * FROM Artifact.Exchange.Windows.Veeam.ProcessDiskImage( | ||
DiskImagePath=Destination, | ||
VMName=VMName, | ||
HostName=HostName, | ||
CreationTimeUTC=CreationTimeUTC, | ||
BackupFilePath=BackupFilePath | ||
) | ||
}, | ||
env=dict( | ||
Artifact=Artifact, | ||
Destination=Destination, | ||
VMName=VMName, | ||
HostName=HostName, | ||
CreationTimeUTC=CreationTimeUTC, | ||
BackupFilePath=BackupFilePath | ||
))}, | ||
b={ | ||
SELECT 'POST_PROCESSING' AS ArtifactName, | ||
rm(filename=Destination) AS DeletedDiskImage, | ||
HostName, VMName, CreationTimeUTC, BackupFilePath | ||
FROM scope() }) | ||
}) | ||
})}, | ||
b={ | ||
SELECT 'POST_PROCESSING' AS ArtifactName, | ||
HostName, VMName, CreationTimeUTC, BackupFilePath, * | ||
FROM Artifact.Windows.System.PowerShell( | ||
Command='Remove-Item -Recurse -Force "'+str(str=path_join(components=(TemporaryFolderPath, ExtractName+'('+ExtractID+')')))+'"' | ||
)} | ||
) | ||
}) | ||
}) |
Oops, something went wrong.