// HackTheBox  ·  writeup

SecretPictures

HackTheBox Easy md5sumstringsobjdumpPython
Malware Analysis

Scenario

Players are given a malicious Go binary for reverse engineering. Their objective is to uncover its purpose, analyze its internal logic, and determine how it communicates with its backend server. The challenge tests skills in static and dynamic analysis of Go malware.

Executive Summary

The sample is a Windows executable written in Go, posing as a picture file. On first run it copies itself into a hidden-style folder on the system drive and registers that copy under the current user’s Run key so it survives logoff. It then enumerates drive letters to find attached storage and beacons on a timer to a hard-coded domain, sending a small POST body that identifies the infected host. Server responses are encoded and decoded before use. The whole analysis was static: Go packs its string literals together, so the work was recovering function boundaries from the runtime metadata and following each main.* function to the constants it uses.

Artifacts

Tip: Go binaries carry no useful symbols in objdump, and strings returns one giant blob because literals are not NUL-separated. Parse the pclntab to get function names and addresses, then resolve string pointers from each function’s disassembly.

Execution

Q1 — What is the MD5 hash of the malware?

Extract the zip with the password from the note, then hash the executable. file confirms a PE32+ before anything else is done with it.

md5sum secretPictures.exe
Click flag to reveal fd46d178474f32f596641ff0f7bb337e
Q2 — What programming language is used to write the malware?

The function table in the binary lists main.* functions alongside the Go runtime and standard library packages (encoding/base64, time), which is the signature of a Go build. A custom parser over the pclntab pulls out the names, and the malware’s own logic sits under main..

strings -a secretPictures.exe | grep -E 'main\.|runtime\.|go1\.'

Gotcha: The format mask is six characters, so the short form Go is rejected. The accepted answer is the full language name.

Click to reveal answer Golang

Persistence

Q3 — What is the name of the folder the malware copies itself to after the initial run?

Disassemble the executable and follow the main.hide and copyExe routines. They load a global string pointer (0x90d2f0) that resolves to a path on the system drive. Reading the bytes at that address gives the destination folder name; the mask is ten characters.

objdump -d secretPictures.exe > work/dis.txt
Click flag to reveal Systemlogs
Q4 — What registry key does the malware modify to achieve persistence?

main.lurk is the persistence routine. It references two strings: the key path at 0x6f22ef and the value name at 0x6e22be. Joined, they give the full per-user Run key path and value that launches the copied binary at logon.

python3 -I va.py secretPictures.exe 0x6f22ef 0x6e22be
Click to reveal answer HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\HealthCheck

Discovery

Q6 — Which Windows API function does the malware call to check drive types?

The import table is the quick route: the executable imports the wide-character drive-type call from kernel32. main.outbreak is the caller, looping over drive letters from D: to Z: and checking the type of each, which skips the system drive.

strings -a secretPictures.exe | grep -i GetDrive
Click flag to reveal GetDriveType

Command and Control

Q5 — What FQDN does the malware attempt to connect to?

main.touchBase and main.heist are the network functions, and both take the same hard-coded host from the read-only data section. Searching the string dump around the networking constants for a dotted hostname turns it up.

strings -a secretPictures.exe | grep -E '[a-z0-9-]+\.[a-z]+\.com'
Click flag to reveal malware.invalid.com
Q7 — Which Go standard library function does the malware use to schedule periodic execution?

main.repeat calls into the time package to build a ticker and loops on its channel, which drives the recurring beacon. The symbol shows in the function table and in the call target inside main.repeat.

strings -a secretPictures.exe | grep -E 'time\.(New|After|Tick)'
Click flag to reveal NewTicker
Q8 — What encoding does the malware use to decode server responses?

The binary links encoding/base64, and the response handling in the network functions calls its decoder on the body before use. The linked package plus that call site point to Base64.

strings -a secretPictures.exe | grep -i 'encoding/'
Click to reveal answer base64
Q9 — The malware communicates with a backend server via a POST request. What are the names of the fields in the request body, separated by commas and listed alphabetically?

main.formatData builds the POST body. Its map keys are the string constants it loads before assembling the request, and the format mask (****,*******) matches two fields in alphabetical order.

python3 -I va.py secretPictures.exe main.formatData
Click flag to reveal name,version

Attack Summary

PhaseAction
ExecutionGo implant runs from its original location
Defense EvasionCopies itself to a folder on the system drive under an innocuous name
PersistenceWrites a HealthCheck value under the per-user Run key
DiscoveryLoops drive letters D: to Z: and checks each drive’s type
Command and ControlBeacons on a ticker to a hard-coded FQDN with a POST body, decodes Base64 responses

IOCs

TypeValue
MD5fd46d178474f32f596641ff0f7bb337e
FilesecretPictures.exe
FolderC:\Systemlogs\
RegistryHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run\HealthCheck
Domainmalware[.]invalid[.]com

MITRE ATT&CK

TechniqueIDDescription
Boot or Logon Autostart Execution: Registry Run KeysT1547.001main.lurk writes the HealthCheck Run value
MasqueradingT1036Self-copy into a log-sounding folder, with a picture-themed filename
Peripheral Device DiscoveryT1120GetDriveType loop over D: to Z:
Scheduled TransferT1029time.NewTicker drives the recurring beacon
Application Layer Protocol: Web ProtocolsT1071.001HTTP POST to the backend
Data Encoding: Standard EncodingT1132.001Base64 decoding of server responses

Defender Takeaways

Go implants hide behind packed strings, so triage the function table, not strings. Literals are concatenated without terminators, which makes plain string hunting noisy. Rebuilding function names from the pclntab gives named main.* entry points that make the logic readable without symbols.

Per-user Run keys are still the cheapest persistence. A new value under HKCU\...\CurrentVersion\Run pointing at a binary in a freshly created folder on the system drive is a high-signal event. Alert on Run key writes whose target path sits outside Program Files and Windows.

A self-copy into a log-sounding folder is a naming tell, not a safe name. Folders such as the one used here should not appear at the root of the system drive. Baseline root-level directories and flag new ones created by a process that then sets autostart.

Block or alert on the beacon domain at DNS. The implant resolves one fixed FQDN and repeats on a timer, so regular lookups of an unknown host from a single process are easy to spot in DNS logs.

Conclusion

A single Go binary gave the actor persistence, drive reconnaissance and a timed beacon with no dropped components. Its logic was fully recoverable statically once the runtime’s own function table replaced the missing symbols.