// HackTheBox  ·  writeup

Compromised

HackTheBox Easy tsharkPythonVirusTotal
SOC

Scenario

Our SOC team detected suspicious activity in Network Traffic, the machine has been compromised and company information that should not have been there has now been stolen – it’s up to you to figure out what has happened and what data has been taken.

Executive Summary

A host in the capture fetched a PE DLL over plain HTTP from an external server, which started the compromise. The DLL is Pikabot, a loader that then spoke HTTPS to several hosts on non-standard ports, each presenting a self-signed certificate. Afterwards the host generated thousands of DNS queries for random-looking subdomains of a single domain, which is a DNS tunnel and the likely route for the data theft the scenario describes. The whole chain is readable from one packet capture, with VirusTotal supplying the malware family and first-seen date.

Artifacts

Timestamp note: Task formats ask for UTC, YYYY-MM-DD HH:MM:SS. The certificate notBefore value is already UTC in the cert; for the first-seen date, see Q4.

Initial Access

Q1 — What is the IP address used for initial access?

Start with the TCP conversation table to see who the internal host talks to, then list HTTP requests. A single GET for an odd path stands out among the traffic, and the server answering it is the delivery host. Stream 1 carries the download.

tshark -r evidence/capture.pcap -q -z conv,tcp
tshark -r evidence/capture.pcap -Y http.request -T fields -e ip.dst -e http.request.full_uri
Click flag to reveal 162.252.172.54

Execution

Q2 — What is the SHA256 hash of the malware?

The response body on the Q1 stream is a PE DLL. Carve it out of the capture and hash it. HTTP object export is the obvious route, but it only recovered a fragment here, so reassemble the TCP stream from the raw follow output and hash that file instead.

tshark -r evidence/capture.pcap -q -z follow,tcp,raw,1
sha256sum work/stream.bin

Gotcha: --export-objects http wrote a DLL of only 1160 bytes, so its hash is wrong. Rebuild the body from the full stream (strip the HTTP headers) before hashing.

Click to reveal answer 9b8ffdc8ba2b2caa485cca56a82b2dcbd251f65fb30bc88f0ac3da6704e4d3c6
Q3 — What is the Family label of the malware?

Look the Q2 hash up on VirusTotal. The popular threat label on the file report gives the family. The format mask (P*******) matches it.

Click flag to reveal Pikabot
Q4 — When was the malware first seen in the wild (UTC)?

On the same VirusTotal report, the “first seen in the wild” attribute is a different field from the first submission. Read the in-the-wild value, which is an epoch (1684504881), and convert it to UTC.

date -u -d @1684504881 '+%Y-%m-%d %H:%M:%S'

Gotcha: VirusTotal’s first submission (2023-05-17 19:04:23) is the more commonly used “first seen” and it was rejected here. This task wants the in-the-wild date.

Click to reveal answer 2023-05-19 14:01:21

Command and Control

Q5 — The malware used HTTPS traffic with a self-signed certificate. What are the ports, from smallest to largest?

Pull every certificate sent in a TLS handshake (tls.handshake.type == 11) with its issuer and subject. A self-signed certificate has identical issuer and subject. Three non-standard server ports present such certificates; list them in ascending order.

tshark -r evidence/capture.pcap -Y tls.handshake.type==11 -T fields -e ip.src -e tcp.srcport -e x509sat.printableString
Click flag to reveal 2078, 2222, 32999
Q6 — What is the id-at-localityName of the self-signed certificate associated with the first malicious IP?

The first malicious IP in the TLS list is 45.85.235.39, serving on port 2078 (from Q5). Dump that handshake in full with -V and read the localityName attribute inside the subject.

tshark -r evidence/capture.pcap -Y 'tls.handshake.type==11 && ip.src==45.85.235.39' -V
Click to reveal answer Pyopneumopericardium
Q7 — What is the notBefore time(UTC) for this self-signed certificate?

Same certificate as Q6. The validity block in the -V output holds notBefore, already in UTC.

tshark -r evidence/capture.pcap -Y 'tls.handshake.type==11 && ip.src==45.85.235.39' -V | grep -A3 -i validity
Click flag to reveal 2023-05-14 08:36:52

Exfiltration

Q8 — What was the domain used for tunneling?

Count DNS query names across the capture. One parent domain accounts for over 7,000 queries, all to unique-looking subdomains under dns., which is the signature of data encoded into labels. This was identified from query volume and pattern rather than by decoding the payloads, so it is a reasoned conclusion that HTB accepted.

tshark -r evidence/capture.pcap -Y dns.flags.response==0 -T fields -e dns.qry.name | awk -F. '{print $(NF-1)"."$NF}' | sort | uniq -c | sort -rn | head
Click to reveal answer steasteel.net

Attack Summary

PhaseAction
Initial AccessHost downloads a PE DLL over HTTP from 162.252.172.54
ExecutionThe DLL is identified as Pikabot
Command and ControlHTTPS sessions to hosts on ports 2078, 2222 and 32999 with self-signed certificates
ExfiltrationThousands of DNS queries to subdomains of one domain, used as a tunnel

IOCs

TypeValue
IP (payload delivery)162.252.172[.]54
IP (C2, port 2078)45.85.235[.]39
C2 ports2078, 2222, 32999
SHA256 (Pikabot DLL)9b8ffdc8ba2b2caa485cca56a82b2dcbd251f65fb30bc88f0ac3da6704e4d3c6
Domain (DNS tunnel)steasteel[.]net

MITRE ATT&CK

TechniqueIDDescription
Ingress Tool TransferT1105Pikabot DLL fetched over HTTP
Application Layer Protocol: Web ProtocolsT1071.001HTTPS command and control
Encrypted Channel: Asymmetric CryptographyT1573.002TLS sessions with self-signed certificates
Application Layer Protocol: DNST1071.004Tunnel through subdomains of one domain
Exfiltration Over Alternative Protocol: Unencrypted Non-C2 ProtocolT1048.003Data carried in DNS queries

Defender Takeaways

Plain HTTP delivery of a PE file is detectable on the wire. A client pulling a DLL from an unknown external IP by a bare path is visible in proxy and IDS logs. Block or alert on executable content types and MZ headers served over HTTP from uncategorised hosts.

Self-signed certificates on high ports are a cheap C2 signal. Three servers on 2078, 2222 and 32999 presented self-signed certs with odd subject values. Alert on TLS to non-standard ports where issuer equals subject, and log certificate fields with Zeek or similar.

DNS volume per parent domain exposes tunneling. Over 7,000 queries to unique subdomains of one domain stands out against normal resolver traffic. Rank queries by registered domain, watch label length and entropy, and force clients through a resolver that can block newly seen domains.

Do not trust a single extraction method for payload hashing. Object export truncated the DLL and gave a wrong hash. Reassemble the stream and confirm the file is a valid PE before submitting or pivoting on its hash.

Conclusion

A Pikabot DLL pulled over HTTP became self-signed TLS C2 and then a DNS tunnel out. Each stage used a different protocol, so only network-level visibility across HTTP, TLS and DNS ties the chain together.