// HackTheBox  ·  writeup

Holmes 2025 2: The Watchman's Residue

HackTheBox Medium tsharkMFTECmdLECmdRECmdJohn the Ripperkeepass2johnpykeepass
SOCDFIR

Scenario

Players will analyze and corelate multiple artifacts to create an incident timeline.Evidence includes a Windows triage image, RMM Logs, Packet capture, etc.

Executive Summary

An attacker on a decommissioned internal machine chatted with the MSP helpdesk AI over unencrypted HTTP and used a prompt injection to make it disclose the remote management credentials for the Cogwork Central workstation. They used those credentials to open a TeamViewer remote-control session, pushed a folder of offensive tools through TeamViewer’s file transfer, and ran a browser credential harvester and Mimikatz. Sensitive files, including a KeePass database, were staged in a second folder and sent back out over the same channel. The attacker then hooked the Winlogon Userinit value for persistence and ended the session; the stolen database cracked against a common wordlist and gave credentials for a further workstation.

Artifacts

Timestamp note: TeamViewer15_Logfile.log is in local time (UTC+1). Connections_incoming.txt, the registry and $J are UTC. The capture’s frame times are +10:00, while the chatbot JSON carries UTC. Normalise everything to UTC before answering.

Initial Access

Q1 — What was the IP address of the decommissioned machine used by the attacker to start a chat session with MSP-HELPDESK-AI?

Start with the conversation summary of the capture. One internal host posts to the helpdesk chatbot’s /api/messages/send endpoint over plain HTTP, and it is the only client sending the odd opening lines (“Hello Old Friend”, “I AM WATSON”). Its source address is the answer.

tshark -r pcap.pcapng -q -z conv,tcp
tshark -r pcap.pcapng -Y 'http.request.method==POST' -T fields -e frame.number -e ip.src -e http.request.uri
Click flag to reveal 10.0.69.45
Q2 — What was the hostname of the decommissioned machine?

From Q1 we know the host. Decommissioned machines still announce themselves on the LAN, so filter NBNS and browser-protocol traffic from that source. The Host Announcement frame carries the NetBIOS name.

tshark -r pcap.pcapng -Y 'ip.src==10.0.69.45 && (nbns || browser)' -T fields -e nbns.name -e browser.server
Click to reveal answer WATSON-ALPHA-2
Q3 — What was the first message the attacker sent to the AI chatbot?

List the POST bodies from the Q1 host in frame order. The earliest one is the opening line to the bot, sent at 21:53:40 in the capture’s +10:00 offset.

tshark -r pcap.pcapng -Y 'http.request.method==POST && ip.src==10.0.69.45' -T fields -e frame.time -e http.file_data
Click flag to reveal Hello Old Friend
Q4 — When did the attacker's prompt injection attack make MSP-HELPDESK-AI leak remote management tool info?

The bot’s JSON replies are what matter here. http.file_data truncates the long responses, so reassemble the TCP streams and read the reply that discloses remote-management details. The JSON timestamp field is UTC, unlike the capture’s local frame time.

tshark -r pcap.pcapng -q -z follow,tcp,raw,56

Gotcha: The frame time in the capture is +10:00. Use the timestamp inside the bot’s JSON, which is UTC, because the answer format is UTC.

Click to reveal answer 2025-08-19 12:02:06
Q5 — What is the Remote management tool Device ID and password?

The same leaking reply from Q4 hands over the remote management tool’s ID and password. The ID is printed with spaces in the chat, and the answer format wants it joined, then a colon, then the password.

tshark -r pcap.pcapng -q -z follow,tcp,raw,60
Click flag to reveal 565963039:CogWork_Central_97&65
Q6 — What was the last message the attacker sent to MSP-HELPDESK-AI?

Take the last POST from the Q1 host (frame 2909) after the chat history is fully decoded. It is the attacker’s closing line before they moved to the workstation.

tshark -r pcap.pcapng -Y 'http.request.method==POST && ip.src==10.0.69.45' -T fields -e frame.number -e http.file_data | tail -1
Click to reveal answer JM WILL BE BACK

Command and Control

Q7 — When did the attacker remotely access Cogwork Central Workstation?

Switch to the triage image. TeamViewer keeps Connections_incoming.txt next to its log. The entry for the attacker’s session lists the start and end in UTC, with the connection type RemoteControl.

cat "evidence/Holmes2025_Chapter2 The Watchman's Residue"/TRIAGE_IMAGE_COGWORK-CENTRAL/C/'Program Files'/TeamViewer/Connections_incoming.txt

Gotcha: Connections_incoming.txt is UTC, but TeamViewer15_Logfile.log is local time (UTC+1 on this host). Convert before comparing the two.

Click flag to reveal 2025-08-20 09:58:25
Q8 — What was the RMM Account name used by the attacker?

The same incoming-connection record names the remote party, and the participant lines in TeamViewer15_Logfile.log confirm it with the TeamViewer ID. The display name is the RMM account.

grep -i participant TeamViewer15_Logfile.log
Click to reveal answer James Moriarty
Q9 — What was the machine's internal IP address from which the attacker connected?

At session start the TeamViewer log records a UDP hole-punch from the peer. The punch received line carries the attacker’s internal address.

grep -i 'punch received' TeamViewer15_Logfile.log
Click flag to reveal 192.168.69.213
Q10 — The attacker brought some tools to the compromised workstation to achieve its objectives. Under which path were these tools staged?

The TeamViewer log records every file the attacker pushed over the session as Write file lines. The tools (including Mimikatz) all land in one directory under the Windows temp folder.

grep 'Write file' TeamViewer15_Logfile.log
Click to reveal answer C:\Windows\temp\safe\
Q18 — When did the malicious RMM session end?

The session closes at the end time in Connections_incoming.txt, and the TeamViewer log agrees with a RemoveParticipant line one hour ahead because of its local-time offset.

grep -i RemoveParticipant TeamViewer15_Logfile.log
Click to reveal answer 2025-08-20 10:14:27

Credential Access

Q11 — The attacker staged a browser credential harvesting tool on the compromised system. How long did this tool run before it was terminated? (Provide your answer in milliseconds, rounded to the nearest thousand)

Pull UserAssist from the Cogwork_Admin NTUSER hive with RECmd’s UserAssist batch file. The browser password recovery tool (WebBrowserPassView) has a focus time of 8 seconds, which is 8000 ms rounded to the nearest thousand. This is the closest proxy for how long it ran, and HTB accepted it.

RECmd.exe -d C:\Users\Cogwork_Admin --bn BatchExampleUserAssist.reb --csv work/reg
Click flag to reveal 8000
Q12 — The attacker executed a OS Credential dumping tool on the system. When was the tool executed?

UserAssist has no entry for Mimikatz because it was launched from a command line. The prefetch files are not in the triage, but the NTFS $J journal is. It shows the creation of MIMIKATZ.EXE-<hash>.pf at the moment of first execution. This answer is reasoned from that journal entry rather than read from an execution artifact, and HTB accepted it.

MFTECmd.exe -f '$J' --csv work/mft
grep -i mimikatz work/mft/*.csv
Click to reveal answer 2025-08-20 10:07:08

Collection

Q15 — When did the attacker access and read a txt file, which was probably the output of one of the tools they brought, due to the naming convention of the file?

Parse the Recent LNK files with LECmd. The text file, named like tool output, has a dump.lnk whose target access time marks when it was opened and read.

LECmd.exe -d C:\Users\Cogwork_Admin\AppData\Roaming\Microsoft\Windows\Recent --csv work/lnk

Gotcha: The Notepad jumplist LastModified is a few seconds later and was not accepted. The LNK’s target access time is the read.

Click flag to reveal 2025-08-20 10:08:06
Q14 — Before exfiltration, several files were moved to the staged folder. When was the Heisen-9 facility backup database moved to the staged folder for exfiltration?

The $J change journal records the file creation inside the staging folder. Filter on the KeePass database name to see when it was moved in.

grep -i kdbx work/mft/*.csv
Click to reveal answer 2025-08-20 10:11:09

Exfiltration

Q13 — The attacker exfiltrated multiple sensitive files. When did the exfiltration start? (UTC)

TeamViewer logs transfers in the other direction as Send file lines. The first one after staging is the start of exfiltration. The log is local time, so subtract one hour to get UTC.

grep 'Send file' TeamViewer15_Logfile.log | head

Gotcha: The format mask shows a double colon, but a normal YYYY-MM-DD hh:mm:ss string is what to give.

Click flag to reveal 2025-08-20 10:12:07

Persistence

Q16 — The attacker created a persistence mechanism on the workstation. When was the persistence setup?

Dump the Winlogon key from the SOFTWARE hive with RECmd, replaying the transaction logs first because the hive is dirty. Userinit has been extended with a second executable (JM.exe), and the key’s last write time is when the change was made.

RECmd.exe --bn Winlogon.reb -d C:\Windows\System32\config --csv work/reg

Tip: regipy fails on dirty hives. RECmd replays .LOG1/.LOG2 and gets the correct last-write time.

Click to reveal answer 2025-08-20 10:13:57
Q17 — What is the MITRE ID of the persistence subtechnique?

Appending a payload to Userinit is the Winlogon Helper DLL sub-technique under Boot or Logon Autostart Execution (MITRE ATT&CK).

Click flag to reveal T1547.004

Lateral Movement

Q19 — The attacker found a password from exfiltrated files, allowing him to move laterally further into CogWork-1 infrastructure. What are the credentials for Heisen-9-WS-6?

The exfiltrated .kdbx is locked. Extract its hash with keepass2john and crack it against rockyou. The password opens the database, and the entry for the target workstation holds the username and password.

keepass2john 'acquired file (critical).kdbx' > work/kdbx.hash
john work/kdbx.hash --wordlist=/usr/share/dict/rockyou.txt
python3 -I -c "from pykeepass import PyKeePass as K;[print(e.title,e.username,e.password) for e in K('acquired file (critical).kdbx',password='<cracked>').entries]"
Click flag to reveal Werni:Quantum1!

Attack Summary

PhaseAction
Initial AccessDecommissioned host chats with the helpdesk AI and uses prompt injection to leak the RMM ID and password
Command and ControlAttacker connects to the Cogwork Central workstation over TeamViewer under an RMM account
Command and ControlOffensive tools are pushed to a staging directory under the Windows temp folder
Credential AccessBrowser credential harvester runs briefly and is closed
Credential AccessMimikatz is executed from the command line
CollectionTool output text file is opened; sensitive files, including a KeePass database, are moved to a second staging folder
ExfiltrationStaged files are sent back through the TeamViewer session
PersistenceWinlogon Userinit is extended with JM.exe
Command and ControlTeamViewer session ends
Lateral MovementCracked KeePass database yields credentials for a second workstation

Forensic Timeline

Timestamp (UTC)Event
2025-08-19 11:53:40First chatbot message from the decommissioned host (21:53:40 at +10:00)
2025-08-19 12:02:06Bot leaks RMM ID and password
2025-08-20 09:58:25Attacker’s TeamViewer remote-control session starts
2025-08-20 10:07:08Mimikatz prefetch file created in $J
2025-08-20 10:08:06Tool output text file opened (dump.lnk target accessed)
2025-08-20 10:11:09KeePass database created in the exfiltration staging folder
2025-08-20 10:12:07First file sent out over TeamViewer
2025-08-20 10:13:57Winlogon key modified (persistence)
2025-08-20 10:14:27TeamViewer session ends

IOCs

TypeValue
IP (attacker source, internal)10.0.69[.]45
IP (TeamViewer peer)192.168.69[.]213
HostnameWATSON-ALPHA-2
RMM accountJames Moriarty
DirectoryC:\Windows\Temp\safe\
DirectoryC:\Windows\Temp\flyover\
FileJM.exe (added to Userinit)
Filemimikatz.exe, WebBrowserPassView.exe
FileHeisen-9 remote snapshot.kdbx, COG-HR-EMPLOYEES.pdf

MITRE ATT&CK

TechniqueIDDescription
Remote Access SoftwareT1219TeamViewer session using credentials leaked by the chatbot
Ingress Tool TransferT1105Tools pushed with TeamViewer file transfer
Credentials from Web BrowsersT1555.003WebBrowserPassView run on the workstation
OS Credential DumpingT1003Mimikatz executed (reasoned from the $J prefetch creation)
Local Data StagingT1074.001Sensitive files collected in a staging folder
Exfiltration Over C2 ChannelT1041Files sent back through the TeamViewer session
Boot or Logon Autostart Execution: Winlogon Helper DLLT1547.004JM.exe appended to Userinit
Brute Force: Password CrackingT1110.002Exfiltrated KeePass master password cracked offline to read the stored credentials
Valid AccountsT1078Credentials from the database for the next workstation

Defender Takeaways

An AI helpdesk bot must never hold or reveal credentials. The prompt injection worked because the bot had the RMM ID and password in its context. Keep secrets out of any model’s reach and enforce the policy outside the model, with output filtering and access controls.

Plain HTTP between internal hosts exposed the whole chat. The capture showed the attacker’s prompts and the bot’s replies in clear text. TLS on internal APIs makes this harder to read in transit, and logging the chat server side gives a record that does not depend on a capture.

An unmanaged remote access tool was the whole intrusion path. TeamViewer on a workstation accepted an inbound session from an unknown account and allowed file transfer in both directions. Restrict RMM tooling to an allowlist, disable file transfer where it isn’t needed, and alert on Connections_incoming.txt entries from unfamiliar accounts.

Winlogon Userinit changes are cheap to detect. A second executable after Userinit.exe is a very specific indicator. Monitor writes to the Winlogon key and baseline its value.

A weak KeePass master password turned one theft into a second compromise. The database cracked against rockyou, and its stored credentials gave the attacker a further workstation. Use long random master passphrases or a key file, and do not keep infrastructure credentials in a database that sits on a workstation.

Conclusion

The attacker needed no exploit: a chatbot gave away the remote access credentials, and a legitimate RMM tool carried every later stage. Controls on what the bot could say and on which remote access tools were allowed would have stopped the chain at the first step.