// HackTheBox  ·  writeup

BOughT

HackTheBox Hard Volatility 3objdumpsha256sumPython
DFIR

Scenario

A non-technical client recently purchased a used computer for personal use from a stranger they encountered online. Since acquiring the computer, the client has been using it without making any changes, specifically not installing or uninstalling any software. However, they have begun experiencing issues related to internet connectivity. This includes receiving error messages such as “Server Not Found” and encountering difficulties with video streaming. Despite these problems, checks with the Windows Network Troubleshooter indicate no issues with the internet connection itself. The client has provided a memory image and disk artifacts for investigation to determine if there are any underlying issues causing these problems.

Executive Summary

A second-hand PC came with a DDoS bot already installed. The bot lived in the all-users StartUp folder, so it launched from explorer.exe at every logon, and it slept before running a debugger check as a cheap sandbox and analyst filter. It generated its C2 address with a small DGA, wrote the active domain to one file under C:\Users\Public, and kept the base64-encoded orders from the C2 in another. Those orders named a target site, an attack type and an expiry date, and the bot either flooded the target with HTTP GETs or pinged it in a loop. The owner’s “Server Not Found” and stuttering video came from the machine spending its time and bandwidth attacking someone else.

Artifacts

Timestamp note: The memory capture time and the config expiry are UTC. The PE compile time is whatever the attacker’s build stamped, and it is not trustworthy (see Q6).

Discovery

Q1 — What is the best volatility profile match for the memory image?

windows.info on the memory image reports a Windows 10 build 19041 x64 kernel. Volatility 3 does not use profiles, so the answer is the Volatility 2 style profile name for that build and architecture.

vol -f memdump.mem windows.info
Click flag to reveal Win10x64_19041
Q2 — When was the image captured in UTC?

The same windows.info output carries the SystemTime field, which is the moment the image was captured. Everything the config files say about “active” or “expired” later is measured against this time.

vol -f memdump.mem windows.info | grep SystemTime
Click to reveal answer 2023-08-07 21:28:13

Persistence

Q3 — Check running processes and confirm the name of the suspicious running process.

windows.pstree shows one odd child of explorer.exe: a process run straight from a StartUp location rather than from Program Files or System32. Its name poses as a Windows security tool. That placement is also why it survives reboots, so it is a persistence mechanism as well as the running payload.

vol -f memdump.mem windows.pstree
Click flag to reveal SecurityCheck.exe
Q4 — What is the full path of malicious process?

The Path column of the same pstree row gives the full image path. It is the all-users StartUp folder under ProgramData, so the bot launches for every account that logs on.

vol -f memdump.mem windows.pstree | grep -i securitycheck
Click to reveal answer C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\SecurityCheck.exe

Execution

Q5 — What is the sha256 value of the malware?

Dump the process with windows.pslist --dump or windows.dumpfiles against its PID to get the image from memory, then take the copy from Files.ad1 instead, because the disk file is the unmodified binary and gives the true file hash. Hash it with sha256sum.

vol -f memdump.mem windows.pslist --pid 2572 --dump
sha256sum work/ad1/SecurityCheck.exe
Click flag to reveal 4062963405cc71c032ca51ffd409e832120fcfd496969f4ef548774323c72413
Q6 — What is the compilation timestamp for the malware?

Read TimeDateStamp from the PE file header. The value is in 2037, which is in the future relative to the 2023 capture time, so the stamp was set by hand and is not a usable build date. Report it as stored.

objdump -x work/ad1/SecurityCheck.exe | grep -i 'time/date'

Gotcha: A compile time after the memory capture is a forged timestamp. It is still the answer to the question; do not “correct” it.

Click to reveal answer 2037-09-03 08:20:55
Q7 — What is the name of the mutex that the malware creates?

Disassemble the binary and look for the import of CreateMutexA near the start of the code. The string pushed as its name argument (at 0x40605e) is the mutex, which the bot uses as a single-instance check.

objdump -d -M intel work/ad1/SecurityCheck.exe | grep -B8 CreateMutexA
Click flag to reveal config_m2

Defense Evasion

Q8 — At the top of main function which anti-debugging function is being used?

At the top of main, a Sleep call is followed by a call to the Win32 debugger check. The check exists to detect an attached debugger, and the sleep in front of it delays it past a short analysis window.

objdump -d -M intel work/ad1/SecurityCheck.exe | grep -A12 '<main>'
Click to reveal answer IsDebuggerPresent
Q9 — How many minutes does the malware sleep before calling above anti- debugging function?

The argument pushed to the Sleep before the debugger check is 0xdbba0, which is 900000 milliseconds. Divide by 60000 for minutes. Sandboxes that cap analysis time never reach the real behaviour.

objdump -d -M intel work/ad1/SecurityCheck.exe | grep -B3 -A3 'Sleep'
Click flag to reveal 15

Command and Control

Q10 — This malware uses DGA, how many unique C2 domains in total is this DGA capable of generating?

The DGA routine at 0x4016f4 builds a http://XXXXXX.xyz host from the nine-character set lcb2a8rn5. Five of the six characters are picked randomly from that set and the third character is fixed as 0. Nine choices at five positions gives 9^5 domains. This count was derived from the disassembly rather than read from a log, so it is reasoned, not observed.

objdump -d -M intel work/ad1/SecurityCheck.exe --start-address=0x4016f4 --stop-address=0x401900
Click to reveal answer 59049
Q11 — How many unique C2 domains start with “rb”?

Take the same DGA structure and pin the first two characters to rb. The third is already fixed, which leaves three random positions: 9^3.

Click flag to reveal 729
Q12 — How many unique C2 domains end with “rla”?

Pin the last three characters to rla instead. With the fixed third character that leaves the first two positions random: 9^2.

Click to reveal answer 81
Q13 — Which file is being used to store active C2 domain?

The bot writes its currently active domain to a text file under the Public profile, which every user can write to. Reading win.ini there shows a single domain, the one the DGA settled on.

cat work/ad1/Users/Public/Documents/win.ini

Gotcha: config.ini sounds like the place for an active C2, and it is the more obvious guess, but it holds the orders. The domain is in the file with the innocent-looking win.ini name.

Click flag to reveal C:\Users\Public\Documents\win.ini
Q14 — Which file is being used to store commands from the C2 server?

The orders file is config.ini in the Public profile root. It holds a base64 blob that decodes to the target, the attack type and an expiry value.

cat work/ad1/Users/Public/config.ini
Click to reveal answer C:\Users\Public\config.ini
Q15 — What was the active C2 FQDN at the time of artifact collection?

Read win.ini from Q13 again. The domain on its single line is the active C2, and it matches the XXXXXX.xyz shape produced by the DGA, with a 0 in the third position.

cat work/ad1/Users/Public/Documents/win.ini
Click flag to reveal http://cl0lr8.xyz

Impact

Q16 — How many kinds of DDoS attacks can this malware perform?

The attack function at 0x40211d switches on an attack type value. Type 1 is the ICMP ping flood and type 2 is the HTTP GET flood, so the bot has two attack kinds.

objdump -d -M intel work/ad1/SecurityCheck.exe --start-address=0x40211d --stop-address=0x402400
Click to reveal answer 2
Q17 — What is the FQDN of the target website.

Decode the base64 content of config.ini from Q14. The URL inside it is the site the bot is told to hit.

base64 -d work/ad1/Users/Public/config.ini
Click flag to reveal http://nbscl231sdn.mnj
Q18 — What was the expiration date for the active attack at the time of artifact collection in UTC?

The decoded config.ini ends in an epoch value, 1693482358. Convert it to UTC. It falls after the capture time from Q2, so the attack order was still active when the memory was taken.

date -u -d @1693482358 '+%Y-%m-%d %H:%M:%S'
Click to reveal answer 2023-08-31 11:45:58
Q19 — How many GET requests does the malware perform against target domain before sleeping for a while?

In the type-2 branch the loop runs its counter from 0 to 0x13, which is 20 GET requests, each followed by Sleep(1000). After the loop it sleeps for 300000 ms before the next round.

objdump -d -M intel work/ad1/SecurityCheck.exe --start-address=0x40211d --stop-address=0x402400 | grep -B4 -A10 'cmp.*0x13'
Click flag to reveal 20
Q20 — There seems to be another attack method with ICMP requests. How many of these requests can the malware send before sleeping for a while?

The type-1 branch builds its command from a format string, ping -n 16 %s, and then sleeps 60000 ms. The -n count is the number of ICMP echo requests per round.

objdump -s -j .rdata work/ad1/SecurityCheck.exe | grep -i 'ping'
Click to reveal answer 16
Q21 — Is this malware prone to Botnet hijacking?

The orders in config.ini are only base64-encoded, and the C2 address is a DGA name drawn from a space of 59049 possibilities. Nothing in the file or in the code paths read for this case authenticates the C2 server, so whoever registers the active DGA domain can hand the bot new orders. This answer is reasoned from that evidence, not from a full review of the network code.

Click flag to reveal Yes

Attack Summary

PhaseAction
PersistenceSecurityCheck.exe placed in the all-users StartUp folder, launched by explorer.exe at logon
Defense Evasion15 minute Sleep before an IsDebuggerPresent check
ExecutionMutex created as a single-instance guard
Command and ControlDGA picks a .xyz domain; active domain written to win.ini in the Public profile
Command and ControlBase64 orders from the C2 stored in config.ini
ImpactHTTP GET flood (20 requests per round) or ICMP flood (16 pings per round) against the target named in the orders

IOCs

TypeValue
FileC:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\SecurityCheck.exe
SHA-2564062963405cc71c032ca51ffd409e832120fcfd496969f4ef548774323c72413
Mutexconfig_m2
FileC:\Users\Public\Documents\win.ini
FileC:\Users\Public\config.ini
C2 domainhxxp[://]cl0lr8[.]xyz
Attack targethxxp[://]nbscl231sdn[.]mnj

MITRE ATT&CK

TechniqueIDDescription
Boot or Logon Autostart: Startup FolderT1547.001Malware dropped in the all-users StartUp folder
Virtualization/Sandbox Evasion: Time Based EvasionT1497.00315 minute sleep before the main logic
Debugger EvasionT1622IsDebuggerPresent check at the top of main
Dynamic Resolution: Domain Generation AlgorithmsT1568.002DGA builds the C2 host name
Application Layer Protocol: Web ProtocolsT1071.001C2 contact and orders over HTTP
Data Encoding: Standard EncodingT1132.001Orders in config.ini are base64
Endpoint Denial of Service: Service Exhaustion FloodT1499.002Repeated HTTP GETs against the target
Network Denial of ServiceT1498ICMP ping flood against the target

Defender Takeaways

A second-hand machine should be rebuilt, not inherited. The bot had been sitting in a StartUp folder since before the owner took the machine, and nothing about it was hidden. A clean reinstall removes it, and a quick check of the StartUp folders and Run keys would have found it.

A process that starts from a StartUp folder and poses as a security tool is worth a look. SecurityCheck.exe was a child of explorer.exe from ProgramData. Alert on new executables in the all-users StartUp path and compare names against what is actually signed software.

Slow network and failing lookups are a symptom, not a fault. The Windows troubleshooter saw no connectivity issue because the connection worked; it was just busy. Outbound request rates and DNS volume per host show a flood bot immediately, including lookups of random-looking .xyz names that fail.

Write-for-everyone folders make good malware state stores, and good detections. The bot kept its C2 and orders in C:\Users\Public. A file-creation rule for .ini files in that folder from an unsigned binary would flag this, and the base64 blob in config.ini can be decoded straight to the target and expiry.

Conclusion

The owner bought a working DDoS bot with their PC; it ran from the StartUp folder, picked its C2 with a DGA and attacked whichever site its base64 orders named. Persistence and C2 state sat in plain files, so the picture was recoverable from memory plus the disk image without running the sample.