Skip to content

Commit

Permalink
Real initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
cybiosity-syn authored Aug 26, 2024
1 parent c9f4638 commit 6a12610
Show file tree
Hide file tree
Showing 5 changed files with 547 additions and 0 deletions.
75 changes: 75 additions & 0 deletions artifacts/Windows.QEMU.ImgConvert.yaml
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'
)
69 changes: 69 additions & 0 deletions artifacts/Windows.Veeam.Extract.yaml
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')
133 changes: 133 additions & 0 deletions artifacts/Windows.Veeam.ProcessBackups.yaml
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+')')))+'"'
)}
)
})
})
Loading

0 comments on commit 6a12610

Please sign in to comment.