// HackTheBox  ·  writeup

GateKeeper

HackTheBox Hard sw_verssqlite3unifiedlog_iteratorPythonstringsgrep
DFIR

Scenario

A targeted attack on Wika’s macOS device has left traces hidden deep within system logs and artifacts. As a DFIR analyst, your mission is to reconstruct the attack timeline and uncover key evidence using macOS forensic tools.

Executive Summary

A fake photo application was dropped into the user’s Downloads folder and moved to /Applications, then launched with the user’s help, sidestepping Gatekeeper’s quarantine check. It opened a reverse shell back to an attacker host on the local network, where the attacker first confirmed their identity and then pulled a zip archive over HTTP. The archive held exploit source that was compiled on the Mac and used against a vulnerable diagnostics binary, which mounted a crafted disk image and produced a root shell. The attacker then deleted their working directory with sudo and removed two of the user’s files. The user noticed something was off and searched Safari for how to tell whether they had been hacked. The unified logs carried nearly every step; they had to be parsed offline because the live-response set holds them only as a raw logarchive.

Artifacts

Timestamp note: The host is on GMT+2 and the logs carry a Pacific label, so read the unified-log times as UTC from the parsed CSV. The UTC values are what the answers use.

Discovery

Q1 — What is the macOS version?

BasicInfo/ in the collection holds the output of sw_vers. The product version line gives the answer directly.

cat BasicInfo/sw_vers.txt
Click flag to reveal 10.13.6

Execution

Q2 — What is the full path of the malicious application?

Search the full file listing for the app bundle and cross-check system.log: launchd logs a one-shot job for funphotos when it runs. The bundle sits in /Applications, while a copy also exists under the user’s Downloads.

grep -i funphotos Full_file_listing.txt

Gotcha: The Downloads copy and the Trash entry are the same download in earlier states. The question wants the path the app executed from.

Click to reveal answer /Applications/funphotos.app
Q3 — What is the inode number of the above malicious application?

The listing has no inode column, so the number comes from other artifacts. RecentApplications.sfl2 stores a bookmark for Users/wika/Downloads/funphotos.app, and the bookmark carries the catalog node ID (CNID), which on HFS+ is the inode number. A short Python script decodes the plist and bookmark and extracts it. The same node ID can be cross-checked in the fsevents records.

python3 -I decode_sfl2.py RecentApplications.sfl2
Click flag to reveal 2156084
Q4 — In the Execution phase, the user executed the application without any restrictions, what is the CVE the attacker tried to abuse to bypass the gatekeeper?

This one was reasoned rather than read from an artifact. The app arrived as funphotos.gz, and the gzip archive was left in the Trash. A quarantine-flag bypass tied to extracting a gzip-delivered app on macOS of this era points to CVE-2022-22616 (Gatekeeper bypass through a crafted gzip). Nothing in the collection names the CVE, so the match rests on the delivery format, and HTB accepted it.

sqlite3 QuarantineEventsV2 'select * from LSQuarantineEvent'

Gotcha: Other well-known Gatekeeper bypass CVEs (for example CVE-2021-30657 and CVE-2021-1810) fit a “Gatekeeper bypass” label but not a gzip-delivered app.

Click to reveal answer CVE-2022-22616
Q5 — At what timestamp did the reverse shell activity begin?

The unified logs only exist as a logarchive, so parse it offline into a CSV first. Around the launch of the app the log shows AppTranslocation activity and a bash process spawned from the app, which is the first sign of the shell. Pivot on process name bash after the app launch and take the first entry.

unifiedlog_iterator --mode log-archive --format csv --input system_logs.logarchive --output work/ul/logs.csv
python3 -I filter_ul.py work/ul/logs.csv --from "2025-02-03 21:09" --to "2025-02-03 21:20"
Click flag to reveal 2025-02-03 21:09:51
Q6 — After the user assists in executing the application, what is the first command the attacker runs upon gaining a reverse shell?

The shell history under .bash_sessions records the attacker’s commands in order, and the unified log shows whoami running at 21:10:32, about 40 seconds after the shell appeared. The two sources agree on the first command.

cat .bash_sessions/*
Click to reveal answer whoami

Command and Control

Q7 — What is the name of the malicious archive file the attacker downloads on the system?

The same shell history holds a curl -O against an HTTP server on 192.168.1.2:8000, the attacker’s staging host. The saved file is the archive.

grep -h curl .bash_sessions/*
Click flag to reveal priv.zip

Privilege Escalation

Q8 — At what time did the attacker compile the exploit?

Unzipping priv.zip yields source that has to be built. In the parsed unified log, filter to the window after the download and look for the make process; its first appearance is the compile.

python3 -I filter_ul.py work/ul/logs.csv --process make --from "2025-02-03 21:09" --to "2025-02-03 21:20"
Click to reveal answer 2025-02-03 21:13:50
Q9 — When did the attacker get the root shell on the system?

After the compile, the exploit runs and the log shows the privileged activity (hdiutil, kernel mount messages and the test binary) in the minute that follows. The root shell is the last step of that chain. The exact second was reasoned from that sequence rather than read from a single “root” event, and HTB accepted it.

python3 -I filter_ul.py work/ul/logs.csv --process "test,hdiutil,kernel,sudo" --from "2025-02-03 21:14" --to "2025-02-03 21:16"

Gotcha: The activity spans several seconds. Seconds just before the accepted one belong to the exploit still running, not to the shell, and one second off is not accepted.

Click flag to reveal 2025-02-03 21:15:07
Q10 — What volume name was created during the privilege escalation attack?

The kernel log records the HFS mount of the volume the exploit created. The exploit binary confirms it: running strings on its uuidtext entry shows the same volume name passed to hdiutil.

python3 -I filter_ul.py work/ul/logs.csv --process kernel --grep hfs
strings -a uuidtext/10/12D53A...

Tip: The name contains a backtick, so copy it exactly as shown in the kernel mount line.

Click to reveal answer disk`t*:1`
Q11 — An error file was generated during exploitation, indicating a vulnerability in a macOS binary. What is the CVE identifier associated with this privilege escalation vulnerability?

The strings from the same exploit binary reference tmdiagnose, Apple’s diagnostics tool, whose log-collection command is open to command injection through the mounted volume name. That is the “rootpipe reborn” bug published at codecolor.ist and Exploit-DB 47070, assigned CVE-2019-8513. The fit with the 10.13.6 host from Q1 holds, since the bug is fixed in later releases.

strings -a uuidtext/10/12D53A...
Click flag to reveal CVE-2019-8513

Defense Evasion

Q12 — According to the MITRE ATT&CK framework, what is the attack technique classification for the injection ?

The exploit injects commands into tmdiagnose so that a trusted binary runs the attacker’s payload. That is the shape of Indirect Command Execution, T1202. This was reasoned from the mechanism and not read from an artifact.

Gotcha: “Injection” invites process-injection or command-interpreter IDs. The abuse here is a trusted utility executing attacker input, which maps to Indirect Command Execution.

Click to reveal answer T1202
Q13 — What command was used by the attacker to erase their traces?

sudo logs every elevated command line to the unified log. After the root shell, the only cleanup command is a recursive delete of the working directory the exploit lived in.

python3 -I filter_ul.py work/ul/logs.csv --process sudo --from "2025-02-03 21:15" --to "2025-02-03 21:20"
Click flag to reveal sudo rm -r priv
Q14 — At what time did the attacker start erasing their traces?

The timestamp of the sudo entry from Q13 is the start of the cleanup.

Click to reveal answer 2025-02-03 21:15:49

Impact

Q15 — What are the names of the 2 files the attacker deleted to prevent the user from achieving his target (in alphabetical order)?

The shell history also holds rm commands against the user’s documents. Two files are removed, and the answer lists them in alphabetical order, case-insensitive.

grep -h 'rm ' .bash_sessions/*
Click flag to reveal mytarget.txt, Targets.rtf
Q16 — Meanwhile, he discovered that he might be compromised. What is the search query he conducted to confirm or investigate this suspicion?

Safari’s History.db stores search-engine visits. A Google results URL in the history_visits window after the compromise carries the user’s query in its q= parameter.

sqlite3 History.db "select url, title from history_items where url like '%google.com/search%'"
Click to reveal answer how to know that am not hacked

Attack Summary

PhaseAction
ExecutionUser runs funphotos.app from /Applications, bypassing Gatekeeper
Command and ControlApp spawns a reverse shell back to the attacker
DiscoveryAttacker runs whoami as the first command
Command and Controlpriv.zip pulled from 192.168.1.2:8000 with curl
Privilege EscalationExploit source compiled with make
Privilege Escalationtmdiagnose command injection mounts a crafted volume and yields a root shell
Defense Evasionsudo rm -r priv removes the working directory
ImpactTwo user files deleted

Forensic Timeline

Timestamp (UTC)Event
2025-02-03 21:09:51Reverse shell activity begins
2025-02-03 21:10:32First attacker command, whoami
2025-02-03 21:13:50Exploit compiled
2025-02-03 21:15:07Root shell obtained
2025-02-03 21:15:49sudo rm -r priv starts the cleanup

IOCs

TypeValue
Application/Applications/funphotos.app
Archivepriv.zip
Staging hosthxxp[://]192[.]168[.]1[.]2:8000/priv.zip
Volume namedisk`t*:1`
Deleted filesmytarget.txt, Targets.rtf

MITRE ATT&CK

TechniqueIDDescription
User Execution: Malicious FileT1204.002User opens the trojanised photo app
Subvert Trust Controls: Gatekeeper BypassT1553.001App delivered as a gzip to dodge quarantine checks
Command and Scripting Interpreter: Unix ShellT1059.004Reverse shell and interactive commands
Ingress Tool TransferT1105priv.zip fetched with curl
Exploitation for Privilege EscalationT1068tmdiagnose flaw used to reach root
Indirect Command ExecutionT1202Injection into a trusted diagnostics binary
Indicator Removal: File DeletionT1070.004sudo rm -r priv
Data DestructionT1485The user’s target files removed

Defender Takeaways

Gatekeeper decisions need to be watched, not trusted. A gzip-delivered app launched from /Applications with a reverse shell as its only payload went unchallenged. Alert on a freshly downloaded app spawning bash and on AppTranslocation followed by shell activity.

Unpatched 10.13.6 handed over root. The host ran an old release where the tmdiagnose flaw was still open. Keeping macOS current closes this class of local escalation outright.

Compiling on a workstation is a signal. make running on a user’s Mac minutes after a curl download is rare outside of developers. Flag compiler activity that follows an HTTP download from a LAN address.

Unified logs hold the story, but only if collected in a parseable form. Command lines from sudo and process starts were enough to rebuild the whole timeline, while a raw logarchive needed offline parsing. Ship them to a central store so they survive cleanup.

Conclusion

The attacker went from a single user-assisted app launch to root and then to destroying the user’s files, using one known local flaw and an HTTP file server. Nothing was hidden from the unified logs, which is why the timeline could be rebuilt to the second.