CASE 0x03 tryhackme
Carnage Writeup
Summary
Category: Network Forensics
Traffic Analysis first, Malware Analysis second. It fits the first because the entire engagement is reading a single packet capture; HTTP objects, TLS certificate metadata, DNS queries, and connection timing; to reconstruct what happened on this host. It fits the second because the traffic you're reconstructing is a malicious Word macro pulling a ZIP dropper and then beaconing to Cobalt Strike C2 infrastructure, so several steps are really about recognizing malware behavior patterns rather than about packets.
Task 1 Scenario
No commands. Deploy the attached machine (split-screen view; click Show Split View if it does not load).
Do not directly interact with any domain or IP address in this room.
Task 2 Traffic Analysis
Setup — load the capture and fix the time format
Open Wireshark → File → Open → <PCAP_PATH>
View → Time Display Format → UTC Date and Time of Day
View → Time Display Format → SecondsThe last two lines are separate toggles in the same menu — the first sets the format, the second the precision. Set precision to whole seconds or your timestamps will carry microseconds the answer format rejects.
Q1 First HTTP connection to the malicious IP (date/time)
Display filter:
httpRead the Time column of the first request frame.
Q2 Name of the downloaded zip file
Same http filter — read the request URI of that first GET.
Q3 Domain hosting the malicious zip
Expand Hypertext Transfer Protocol on that frame and read the Host: header (also visible in the ASCII byte pane).
Q4 Name of the file inside the zip (without downloading it)
Right-click the GET frame → Follow → HTTP StreamAuto-applied filter:
tcp.stream eq <STREAM_ZIP>Scroll past the response headers to the body. It begins with PK; the stored filename follows the local file header as plain uncompressed text.
Everything after the filename is compressed binary and renders as noise in the ASCII pane — expected, not an error.
Q5 Webserver name of the malicious IP
In the same Follow HTTP Stream window, read the server response header:
server:Q6 Version from the previous question
Same response block:
x-powered-by:The
server:line carries no version — the room's expected value comes fromx-powered-by, which identifies the scripting engine, not the server.
Q7 Three domains involved in malicious downloads
tls.handshake.type == 1Add the SNI column:
Click any Client Hello frame → detail pane → expand:
Transport Layer Security
→ TLSv1.2 Record Layer: Handshake Protocol: Client Hello
→ Handshake Protocol: Client Hello
→ Extension: server_name
→ Server Name Indication extension
→ Server Name
Right-click "Server Name" → Apply as ColumnScroll the 16:45:11–16:45:30 window and read the three hostnames.
Q8 Certificate authority for the first domain
tls.handshake.type == 11Find the row whose Source is that domain's IP, then expand the Certificates subtree.
Single-frame alternative:
ip.addr == <TLS_DOMAIN_IP> && tls.handshake.type == 11Q9 The two Cobalt Strike server IPs
Identify the candidate external addresses, then confirm each on VirusTotal → Community tab. Answer format: sequential order.
Statistics → Conversations → IPv4 tab → sort by Bytes/PacketsQ10 Host header for the first Cobalt Strike IP
ip.addr == <CS_IP_1> && httpClick the first returned frame → expand Hypertext Transfer Protocol → read Host:.
&& httpis what strips the TLS sessions on 443/8888 and leaves the readable plaintext request.
Q11 Domain name for the first Cobalt Strike IP
VirusTotal lookup on <CS_IP_1> (Community tab / Relations).
Q12 Domain name for the second Cobalt Strike IP
VirusTotal lookup on <CS_IP_2> (Community tab / Relations).
Q13 Domain of the post-infection traffic
ip.addr == <POSTINFECT_IP> && httpor
http.request.method == POSTClick any POST frame → expand Hypertext Transfer Protocol → read Host:.
Q14 First eleven characters the victim sends to that domain
Right-click the first frame in that conversation → Follow → TCP StreamAuto-applied filter:
tcp.stream eq <STREAM_C2>Read the opening bytes of the client half — the eleven characters immediately after POST /.
Q15 Length of the first packet sent to the C2 server
ip.addr == <POSTINFECT_IP> && httpSelect the earliest frame in the conversation and read the Length column (or the Frame branch in the detail pane).
Q16 Server header for that malicious domain
In the same Follow TCP Stream window (tcp.stream eq <STREAM_C2>), read the server response header:
Server:Q17 Date/time of the DNS query for the IP-check domain
frame contains "api"Then confirm no earlier query exists by targeting the field directly:
dns.qry.name contains "ipify"Read the earliest timestamp in the Time column. Answer format: yyyy-mm-dd hh:mm:ss UTC.
The broad
frame containssearch truncates in the window. Always re-run against the specific field when the answer depends on a value being earliest or unique.
Q18 Domain in that DNS query
Read the query name from the Info column, or expand Domain Name System (query) → Queries in the detail pane.
Q19 First MAIL FROM address observed
smtp.req.command == "MAIL"Sort by the No. column to restore capture order, then read the earliest frame.
Filter on the verb only — the
FROM:portion is a parameter held insmtp.req.parameter, not part of the command value. Sorting by any other column interleaves the phases and hides which command came first.
Q20 How many packets were observed for the SMTP traffic
smtpRead Displayed in the status bar at the bottom of the window.
Host map
| Host | Role |
|---|---|
Victim workstation (10.9.23.x) |
Source of all outbound activity in the capture |
Domain controller / DNS / DHCP (10.9.23.5) |
Expected internal infrastructure — baseline, not a finding |
| Compromised web hosts (external) | Serve the ZIP dropper and follow-on files |
| Cobalt Strike servers (external) | Beacon C2 |
| Post-infection C2 (external) | Plaintext HTTP POST channel on port 80 |
| External mail servers (external, port 25) | Malspam relay targets |
Everything in this room is read out of one offline capture — no traffic is generated toward any of the hosts above.