Chapter 4 · Q010 to Q013
Hands on keyboard¶
Once they had a foothold, the attacker checked where they landed: which user, which host, which network. Some of that was automated. Then a remote support tool showed up and someone started typing.
Automated discovery Q010¶
Admins and scripts run discovery tools all the time, almost always through cmd.exe. On WS02, RustDesk alone runs tasklist through cmd /C about 48,000 times. So I look for discovery tools whose parent isn't a shell:
bifract_category="process_creation" | image=~whoami,ipconfig,hostname,systeminfo,"\\net.exe",nltest,tasklist | NOT parent_image=$"\\cmd.exe" | groupBy(computer_name, parent_image, image)Discovery tools started directly by something other than cmd.exe.
There are six rows and only two tools: whoami.exe and ipconfig.exe, both with /all. Their parents are three processes to treat as implants from here on:
...\Temp\QuickConnect\QuickConnect.Service.exeon WS02 (14:10)C:\Program Files\Greenshot\Greenshot.exeon WS02 (15:08)C:\Windows\QuickConnect.Service.exeon WS03 (15:38)
Finding · Q010
The two directly launched discovery tools are whoami.exe and ipconfig.exe.
Out of place
Greenshot is a screenshot tool installed in Program Files. It has no reason to run whoami /all. Chapter 5 shows why it does.
What did the implants use cmd for? Q011¶
The implants also started cmd.exe as a wrapper. To see what each wrapper ran, I collect their GUIDs in a binding and look for their children:
let &wrappers := bifract_category="process_creation" parent_image=~QuickConnect,Greenshot image=$"\\cmd.exe" | table(process_guid);
bifract_category="process_creation" | in(parent_process_guid, &wrappers) | NOT image=$"\\conhost.exe" | groupBy(computer_name, parent_image, parent_commandline, image)What the implants' cmd.exe wrappers ran.
cmd.exe /d /s /c systeminfo.exe ran systeminfo.exe on WS02 (twice) and WS03. The last row is a for loop that runs net.exe eight times: four net use attempts against WS03, each after a net use /delete. Chapter 6 covers it.
Finding · Q011
Operating system inventory came from cmd.exe → systeminfo.exe.
Bindings
let &name := ...; runs a query and keeps its result for the next one. End the binding with table(field), because in() can't use the _count column a groupBy() adds.
The support tool Q012¶
Chapter 1's first seen model already flagged a second QuickConnectSupport.exe. Here are the two side by side:
bifract_category="process_creation" | image=$"\\QuickConnectSupport.exe" | groupBy(image, original_file_name, product, description)One file name, two binaries.
It's the same file name for two programs: the Python loader in Temp, and RustDesk Remote Desktop in AppData\Local\Programs\QuickConnect Support\. RustDesk is open source remote desktop software that can use any relay server, including one the attacker runs.
bifract_category="network_connect" | image=~QuickConnect,rustdesk | groupBy(computer_name, image, dst_ip, dst_port) | sort(_count, order=desc)RustDesk talks to 192.0.2.146 on its rendezvous and relay ports.
Finding · Q012
The remote support product is RustDesk, deployed under the support-themed name QuickConnectSupport.exe.
Someone typing Q013¶
Back to the Run dialog history from chapter 2:
event_id="13" target_object=~"\\RunMRU\\" | target_object!=/MRUList$/ | sort(timestamp) | table(timestamp, computer_name, image, details)The second and third Run entries come after RustDesk connects.
RustDesk started at 14:18. Four minutes later, at 14:22:53, a new command went through the Run dialog:
/k keeps the window open so someone can read the output. This is the attacker typing over RustDesk.
Finding · Q013
The command typed through the remote session was cmd.exe /k whoami.exe & hostname.exe & ipconfig.exe /all.
The third Run entry, "C:\Program Files\Greenshot\Greenshot.exe" at 14:51, relaunches the screenshot tool. Next: why it does that.




