AC1DF0X VAULT

Galactic Shooter: A Run of the Mill Stealer

In general, malware specifically designed to smash and grab don't take a lot of effort to make. They tend to be small executables that will package up passwords, credit card data, cookies, and any other useful on-disk artifacts before sending them off to a C2.

In my case, my sample brought in a live one: the secondary objective of this stealer was to leave the door open for further on-keyboard access.

Let's take a look at GalacticShooter.exe [a2077125de69b773350e3d1875f71d5433d85bcaa4f1fccce75a59a78cfef668]. As of June '23, we're sitting at 5/66 on VT.



Immediately, we already have some suspicious DNS resolutions:



Overall, VT doesn't help us much. At the time of upload, I didn't see any other popular tools with telemetry that would be constructive either. Into the sandbox it goes.

On first execution, what greets the user is this obnoxious galaxy print background and a box to enter a beta tester key, obviously there is no beta tester key.



From the shell commands and process structure, we can assume that this is an Electron process. Note: this is not the first execution that I will be referring to lower down, this screenshot was taken on the fourth or fifth execution of the sample so the PIDs don't line up to what I mention below.


Preemptively, as we know absolutely nothing about the executable going in, we set Process Monitor to record during the entire execution of the sample. At the same time, Wireshark was capturing all traffic to and from my VM network.

Knowing initially it was a stealer, I went ahead and grepped through the procmon log for password. Immediately, we find something interesting.

"4:04:25.7873536 PM","GalacticShooter.exe","1580","CreateFile","C:\Users\USER\AppData\Local\Temp\epsilon-USER\Passwords.txt","SUCCESS","Desired Access: Append Data/Add Subdirectory/Create Pipe Instance, Write EA, Read Attributes, Write Attributes, Read Control, Synchronize, Disposition: OpenIf, Options: Synchronous IO Non-Alert, Attributes: N, ShareMode: Read, Write, Delete, AllocationSize: 0, OpenResult: Created"

Narrowing our search down to only the call WriteFile from GalacticShooter.exe with the string "epsilon" in it returns the unique files:
C:\Users\USER\AppData\Local\Temp\epsilon-USER\Passwords.txt
C:\Users\USER\AppData\Local\Temp\epsilon-USER\Cookies\Chrome_Default.txt
C:\Users\USER\AppData\Local\Temp\epsilon-USER\Cookies\Edge_Default.txt
C:\Users\USER\AppData\Local\Temp\epsilon-USER\Credit Cards.txt
C:\Users\USER\AppData\Local\Temp\epsilon-USER\Autofill Data.txt
C:\Users\USER\AppData\Local\Temp\epsilon-USER.zip

As each event is recorded sequentially, we know that the process will create a file for passwords, browser cookies, saved browser credit card data, browser autofill data, then zip them all into epsilon-USER.zip. From the first write event of Passwords.txt to the deletion of epsilon-USER.zip is about 5 seconds. Given a wide time-frame, we have the opportunity to snag it for ourselves when the files write to disk.
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\Users\USER\AppData\Local\Temp\"
$watcher.Filter = "epsilon-USER.zip"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true 

    $action = { $path = $Event.SourceEventArgs.FullPath
                cp $path "C:\Users\USER\Desktop\yoinked\"
		echo "success"
              }    
    Register-ObjectEvent $watcher "Created" -Action $action
    Register-ObjectEvent $watcher "Changed" -Action $action
    Register-ObjectEvent $watcher "Deleted" -Action $action
    Register-ObjectEvent $watcher "Renamed" -Action $action
    while ($true) {sleep 1}

[I found this on superuser](https://superuser.com/questions/226828/how-to-monitor-a-folder-and-trigger-a-command-line-action-when-a-file-is-created) then just adjusted it to my use-case. The GalacticShooter.exe process does not perform a check to ensure the data is not a duplicate and thus, after minor trial and error, we can snag the files.



Each file should have a list parsed out from Chrome & Edge (the only two browsers installed on this VM) of any autofill data, credit cards, or passwords found. As both browsers are unused, the data is empty but packaged up and sent off to its C2 regardless.



Each file within the Temp directory in the previous screenshot were created by GalacticShooter.exe, further reinforcing its Electron behavior. The folder 2OcB46IRbVtah4ccWieleL6owgA also contains the child process GalacticShooter.exe that we saw above in Process Hacker.

This child process \2OcB46IRbVtah4ccWieleL6owgA\GalacticShooter.exe [38c81e9d17174f56bf3c22e5994d341ad041254ada2743160b69d893b8d51eda] has even less prevalence in VT. It does, however, offer us a bit of insight into the greater campaign.



Checking the VT graph for this hash, we see it has 20 files listed as potential parents, some unique ones are below:

PARENT SHA256
Palowarn_DEMO.exe 3862b39cbaca21c0a4e1c4ee09c83ab8dca7fdafe90486115ca30d74339aa435
TBMSetup.exe 1fb52505b4b5a857d33c65dbc433cb8259312ee91a9fd23f8a6b7820e5426c18
TBM_Setup.exe 09f0a812f6e111d15cb40ab484cb696f3f510247e618c73add4f445f267cef76
Saturne-SpoofX.exe 0c69121b796701d5f1643ca0358f975b551004425b467f8ccd52b0cbcaa7d161
Condo_Generator.exe 04fb70c81a5f3f2c2310e0ff166b2b2956fb035db81091cc02931bc8e54804f3
GalacticShooter.exe 16c05c50696d648176dfc86b0648c1a74fe166d5fe86640800a4a3571c4bd1d5
SearchDB.exe 729fdc841c88f8601f6ba2986404a83c8e4011a4323eb5e8b3e1131809238051
TBMSetup (6).exe 6badc9e07c43dc30a4d7400aa79ba6ddbe77b7fe80f38579466d03fde4e71c03
Damned-setup.exe 6f9f967e210b482c08bf47f9f67cefcb4cd94ce4be64c2b8fc1c0b150863be7f
Damned-Setup.exe 5a27e4815f753c751ff45d1e998084e4c17769694a2a812f2cc88ae4837098d4
TBMSetup.exe 67335f9c7fca83065c6289963e3d059d4691d2eb32e217f2ba4d6b072fc9fb8b
damned.exe 39292b5820555e73fa5d1ed6c39334f021391c2dab4bf8012fa2ad92a4f55228
Interspace.exe 11b58a18b74ae1e0bcf4952f8854020351aaed16df9d467d14e5ef5ebfeca610

Finally caving from my endless grepping to using a GUI, Libre was actually helpful here to sort through the CSV. Firstly, we can re-create our process tree by sorting down to only Process Create operations:
GalacticShooter (PID 8148)
	-> GalaticShooter (PID 1580)
		-> GalacticShooter (PID 1580)
		"[.]\AppData\Local\Temp\2OcB46IRbVtah4ccWieleL6owgA\GalacticShooter.exe" --type=utility --utility-sub-type=network.mojom.NetworkService --lang=en-US --service-sandbox-type=none --user-data-dir="C:\Users\USER\AppData\Roaming\GalacticShooter" --mojo-platform-channel-handle=1948 --field-trial
		-> GalacticShooter (PID 1580)
		"[.]\AppData\Local\Temp\2OcB46IRbVtah4ccWieleL6owgA\GalacticShooter.exe" --type=renderer --user-data-dir="C:\Users\USER\AppData\Roaming\GalacticShooter" --app-path="C:\Users\USER\AppData\Local\Temp\2OcB46IRbVtah4ccWieleL6owgA\resources\app.asar" --enable-sandbox --lang=en-US --device-scale-factor=1 -

Reviewing QueryDirectory calls shows that PID 8148, the parent that we downloaded and executed, creates the directory C:\Users\USER\AppData\Local\Temp\nssC2CF.tmp\, a connection is made to a Cloudflare IP address, the directory is filled with 7z-out files for the secondary executable that will then be unpacked to \Temp\2OcB46IRbVtah4ccWieleL6owgA\ and house our child process (this also houses vulkan drivers, a ton of keyboard language packs, and Electron dependencies which confirms the earlier assumption). After downloading the second-stage, it is executed to handle the data exfiltration from browsers.

Here we see PID 1580, the child, making outbound connections to:



Both Cloudflare IPs have pretty hefty traffic, amounting to 64MB~:



Throughout the Wireshark capture, there is a brief connection made within the first 100 packets for ipinfo.net (34.117.59.81), likely identifying my public VPN node when the process first launched, logging the public IP in the trove of data sent up to the Cloudflare IPs.

All hosts received data from the box based on the identical TCP Send events:



If we compare the TCP Send events against the WriteFile events we found earlier, the timeline starts to make sense: PID 1580 writes the goods to a ZIP file, upload it through the Cloudflare IPs, then removes it from disk once complete.

If we next filter by the operation CreateFIle, we can map out exactly what the process wants to find:
1. Brave, Chrome, Edge, Opera, Vivaldi, Yandex
1. Extension MetaMask, an Eth wallet (nkbihfbeogaeaoehlefnkodbefgpgknn)
2. Extension Phantom, an NFT wallet (bfnaelmomeimhlpmgjnjophhpkkoljpa)
3. Extension Binance Wallet, a generic coin wallet (fhbohimaelbohpjbbldcngcnapndodjp)
4. Extension Coinbase Wallet, a generic coin wallet (hnfanknocfeofbddgcijnmhnfnkdnaad)
5. Coin98 Wallet, a generic coin wallet (aeachknmefphepccionboohckonoeemg)
6. Crypto.com wallet, a generic coin wallet (hifafgmccdpekplomjjkcfgodnhcellj)
7. Login data, web data, cookies
2. Firefox
1. Queries Profiles
3. Exodus Wallet
1. Checks if folder exists in Appdata
4. FileZilla
1. Checks if Filezilla.xml exists in Appdata
5. Discord
1. Discord PTB
2. Discord Canary
3. Discord Development
4. Better Discord
5. Lightcord
6. Telegram
1. tdata folder

After all potential credential locations have been discovered, each are copied over into \Appdata\Local\Temp\ and zipped into a file of the naming convention , then the original files are deleted from disk. In my case, it was Epsilon-USER.zip.

While taking initial triage of the warez, I had left the process running in my sandbox. About 20 minutes into my analysis, my Windows VM snapped to 800 x 600 resolution and my processes began closing by themselves. Admittedly, rather than take a snapshot to preserve any forensic data, my IR 'nam flashbacks kicked in and I unplugged the NIC. I did, however, leave Wireshark running throughout the entire session.

Assumably, whomever touched my box during analysis was spooked off by the amount of PowerShell windows & monitoring processes were open at the time as any subsequent executions with my same hostname/username never baited another incoming connection: truly a poor time to catch me pretending to be an end-user.

Though it is unclear which is my actual user, the below sheet is a quick glance through my Wireshark traffic looking for my culprit. Quite a few IPs were tagged by tools as Shifter Proxy, which allows paid members to use residential proxies to anonymize traffic.

        "Address": "198.251.88.130",
			ponynet AS 53667
			rentry resolve point
        "Address": "142.250.189.138",
	       GOOG IP with no abuse
	       AS 15169 ( GOOGLE ) 
	       box reached out starting at packet 41
	       prob traffic against 81.59.117.34.bc.googleusercontent.com
        "Address": "34.117.59.81",
	        AS 396982 ( GOOGLE-CLOUD-PLATFORM ) 
	        actual GCP IP, C2?
	        resolves to ipinfo.net
        "Address": "162.159.135.232",
	        CF IP
        "Address": "162.159.135.233",
	        CF IP
        "Address": "104.18.21.229",
	        CF IP
        "Address": "104.18.10.128",
	        CF IP
        "Address": "142.250.189.142",
	        AS 15169 ( GOOGLE ) 
	        shifter proxy - SP
	        traffic lasts less than 20 packets towards ends of capture, begins from localhost, all https
	        looks like a cert download?
	        STRING: http://crl.pki.goog/gtsr1/gtsr1.crl
	        STRING: http://ocsp.pki.goog/gts1c301.
	        STRING: *.google.com..*.appengine.google.com. *.bdn.dev..*.origin-test.bdn.dev..*.cloud.google.com..*.crowdsource.google.com.[TRUNCATED]
        "Address": "34.104.35.123",
	        GCP IP
	        4 sequential packets: FIN, ACK -> ACK -> FIN, PSH, ACK -> ACK
	        client -> server
	        resolves to edgedl.me.gvt1.com, 123.35.104.34.bc.googleusercontent.com - sho
        "Address": "162.243.25.33",
	        digitalocean IP
	        only 1 packet here, server -> client: RST, ACK
	        contextually nowhere near any above sessions in wireshark, could be unrelated

In conclusion, stealers today have become quite simple and streamlined in their goals:
1. Trick a user into double-clicking a user process by enticing them with the promise of a game no one else has
2. Pillage their browsers and local apps for any data worth taking
3. Zip them up and ship them off to a C2
4. Erase tracks

This sample did something different: rather than clean up, they purposefully leave the process there to utilize as a RAT later when the user might not be active but the host is online.