Skip to content

Instantly share code, notes, and snippets.

@khr0x40sh
Created January 13, 2021 16:47
Show Gist options
  • Save khr0x40sh/a941c5d280a3eed594184352a1366c68 to your computer and use it in GitHub Desktop.
Save khr0x40sh/a941c5d280a3eed594184352a1366c68 to your computer and use it in GitHub Desktop.
Generates the SUNBURST GUID and an example DGA prefix as would be seen on a compromised SolarWinds system
function Invoke-Sunburst-GUID-creator
{
<#
.Synopsis
SUNBURST GUID CREATOR
.Description
The script will generate the SUNBURST GUID and an example DGA prefix as would be seen on a compromised SolarWinds server.
The SUNBURST GUID is made up of the machine's primary non local loopback network adapter's MAC address,
the domain name of the system, and the (optional) GUID of the system in the registry.
These values are concatenated together and then an MD5 hash of the string is created.
Finally this MD5 hash is is condensed into 8 bytes with two rounds of XOR on the 16 bytes (upon themselves) of the MD5.
The SUNBURST GUID can then be used to track other packets the system may have sent out over the DGA DNS stage 1 C2 if those packets were decoded.
For more information on decoding the DGA, please visit:
https://www.netresec.com/?page=Blog&month=2020-12&post=Reassembling-Victim-Domain-Fragments-from-SUNBURST-DNS
After the malware GUID is created, an example DGA prefix will also be created to show what the first 15 bytes of DGA subdomain could look like.
It is important to note that the DGA prefix may not match any DNS logs as the prefix is based off a random number 1-127 and then XOR'd across the bytes.
As for the "Why did you do this?":
We (my team and I) were aiding a tiger team to hunt down hosts that had beaconed out Stage 1 C&C via DNS records.
After utilizing the amazing SUNBURST decoder assembly linked above, we were able to correlate hosts to their callouts.
Due to the nature of log ingestion, we could see the DNS requests and responses, but we sometimes did not see the originating system(s).
With the ability to take key information from the systems, or run this script on the systems in a sandbox, we were able to marry up the decoded DNS requests
and the GUIDs to the systems, so we could track what information left over DGA (don't worry, this wasn't the only thing that was examined).
Additionally, as far as emulating this attack, for educational purposes, we know have a quick way to show the first 15 bytes of a DGA may look like.
Eventually, I plan to include the ability to create the full sample DGAs from powershell, if others haven't already done so. And before someone says,
"well, couldn't you just do it from C# or do an Add-Type? ..." I have had some limited success doing this, but really want to have a nice clean port in psh!
If you have any issues or questions using this script, please direct them to @khr0x40sh on Twitter.
.Parameter machinename
External system's machinename. If this value is not provided, the script will assume you are running against the local system.
.Parameter mac
External system's MAC Address. If this value is not provided, the script will assume you are running against the local system.
.Parameter domain
External system's domain name.
.Parameter guid
External system's guid from the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\MachineGuid.
This is an "optional" parameter in the original malware
.Example
Import-Module SUNBURST-GUID-creator.ps1
# Run on local system to generate SUNBURST GUID and DGA prefix from current system
Invoke-Sunburst-GUID-creator
# Run with parameters to calculate SUNBURST GUID and DGA prefix
Invoke-Sunburst-GUID-creator -machinename TESTDEV -domain dev.local -mac 11-22-33-44-55-66 -guid 12345678-1234-1234-1234-123456789ABC
# Run with parameters to calculate SUNBURST GUID and DGA prefix, output to CSV
Invoke-Sunburst-GUID-creator -machinename TESTDEV -domain dev.local -mac 11-22-33-44-55-66 -guid 12345678-1234-1234-1234-123456789ABC | Export-Csv -notypeinformation -path "C:\Users\Public\exported.csv"
# Run with parameters to calculate SUNBURST GUID and DGA prefix, append to CSV
Invoke-Sunburst-GUID-creator -machinename TESTDEV -domain dev.local -mac 11-22-33-44-55-66 -guid 12345678-1234-1234-1234-123456789ABC | Export-Csv -notypeinformation -path "C:\Users\Public\exported.csv" -Append
#>
Param($machinename = "",
$mac = "",
$domain = "",
$guid = "");
function XOR{
Param($byteA, $key);
$arr = @()
$arr += $key
for ($i=1; $i -lt $byteA.Length; $i++)
{
$c = $byteA[$i] -bxor $key
$arr += $c
}
$arr
}
function MACaddr
{
foreach( $nic in [System.Net.NetworkInformation.NetworkInterface]::GetAllNetworkInterfaces())
{
if ($nic.OperationalStatus -eq [System.Net.NetworkInformation.OperationalStatus]::Up -and $nic.NetworkInterfaceType -ne [System.Net.NetworkInformation.NetworkInterfaceType]::Loopback)
{
return $nic.GetPhysicalAddress().ToString()
}
}
}
function CreateUserID
{
Param($mac,$domain, $guid)
$text = $mac
$hash64 = @(0)*8 # new byte[8];
#[Array]::Clear($hash64, 0, $hash64.Length);
if ($text -eq $null)
{
return false;
}
$text += $domain
try
{
if([System.String]::IsNullOrEmpty($guid))
{
# HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography
#MachineGuid
$text += (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Cryptography\MachineGuid).ToString()
}
else
{
$text += $guid
}
}
catch
{
Write-Warning "[!] Could not retrieve Registry GUID. This is an optional piece of the malware GUID, but the results may differ from actual malware GUID."
}
$md = [System.Security.Cryptography.MD5]::Create()
[byte[]] $bytes = [System.Text.Encoding]::ASCII.GetBytes($text);
[byte[]] $array = $md.ComputeHash($bytes);
for ($i = 0; $i -lt $array.Length; $i++)
{
$num = $i % $hash64.Length;
$hash64[$num] = $hash64[$num] -bxor $array[$i]
}
@($hash64, $array)
}
function CustomBase32{
Param($bytes)
# This is based of the leaked C# source, hopefully I didn't mess up porting it over to psh lol :-)
[string] $text = "ph2eifo3n5utg1j8d94qrvbmk0sal76c"
$r = [Random]::new()
$xor = $r.Next(1,127)
$bytes = XOR $bytes $xor
$text2 = "";
$num = 0
$rt = $true
$i = 0
foreach ($b in $bytes)
{
$num = $num -bor $b -shr $i
for ($i += 8; $i -ge 5; $i -= 5)
{
$text2 += $text[[int]($num -band 31)].ToString();
$num = $num -shr 5
}
}
if ($i -gt 0)
{
if ($rt)
{
$num = $num -bor ($r.Next() -shl $i)
}
$text2 += $text[[int]($num -band 31)].ToString();
}
$text2
}
function ConvertTo-Object($hashtable)
{
$object = New-Object PSObject
$hashtable.GetEnumerator() |
ForEach-Object { Add-Member -inputObject $object `
-memberType NoteProperty -name $_.Name -value $_.Value }
$object
}
<# MAIN #>
if ([System.String]::IsNullOrEmpty($mac) -and [System.String]::IsNullOrEmpty($machinename))
{
Write-Output "[-] Parameters are null, grabbing data from system..."
#Grab the primary NIC
$mac = MACAddr
#Grab the machinename
$machinename = [System.Environment]::MachineName;
#Grab the domain name
$domain = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties().DomainName;
}
else
{
if ([System.String]::IsNullOrEmpty($domain))
{
Write-Error "[!] Domain not specified. Malware will not execute on non-domain joined system. Exiting..."
return
}
if ([System.String]::IsNullOrEmpty($guid))
{
Write-Warning "[!] No registry GUID specified. This is an optional parameter the malware may use, but if it is present the GUID output may be different!"
}
$mac = $mac.ToUpper().Replace("-","")
$mac = $mac.Replace(":", "")
$domain = $domain.ToLower() #Not 100% on this yet, but it appears that domain is always lowercase
}
$IDX = (CreateUserID $mac $domain $guid)
$prefix = CustomBase32 $IDX[0]
$machine = @{MachineName = $machinename; Mac= $mac; Domain=$domain; RegGUID = $guid; GUID = (($IDX[0]|ForEach-Object ToString X2) -join ''); MD5 = (($IDX[1]|ForEach-Object ToString X2) -join ''); Prefix = $prefix }
# I left the above hashtable in if you prefer hashtable output over the object output, you can just uncomment below
$machine = ConvertTo-Object $machine
$machine
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment