In this Sherlock, players analyze a PCAP to find malicious downloads and use tools like VirusTotal to gather information on the malware’s origin, function and type.
A Windows host on the internal network browsed a remote WebDAV share, listed its contents, and then downloaded a Windows Installer package from it. The package was an MSI wrapping a cabinet that carried a DLL, and VirusTotal tied it to a known loader family. After execution the host began beaconing to a separate C2 server over plain HTTP, first checking its external address through a public IP lookup service. The beacon leaked the hostname, OS version, owner name and the RC4 key in clear JSON, so the tasking the server sent back could be decrypted straight from the capture. The only job observed was an instruction to download and run a further module from the C2.
tshark (or Wireshark). Start with the protocol hierarchy, then the HTTP request listCarving note:
tshark --export-objects httpwrites the WebDAVPROPFINDXML reply under the same name as the real file. Hash the export before trusting it, and follow the TCP stream of the actualGETto get the binary.
Protocol hierarchy shows the capture is almost entirely HTTP, so list every request with source address and URI. All of the requests originate from one RFC1918 host, and that is the machine the whole case is about. The external addresses in the capture are servers it talks to, not sources.
tshark -r interceptor.pcap -q -z io,phs
tshark -r interceptor.pcap -Y http.request -T fields -e frame.number -e ip.src -e ip.dst -e http.request.method -e http.request.uri
Gotcha: The format hint (an IPv4 address) fits the public addresses in the capture too. The WebDAV server and the public address that shows up inside the beacon are both destinations or payload data. The traffic’s source is the internal victim.
In the request listing from Q1, frames 10945 to 10986 are a run of non-standard verbs against /share/ on the external WebDAV server. WebDAV uses a dedicated method to ask for resource properties (name, size, timestamps) without fetching the body. That is the enumeration step before the download.
tshark -r interceptor.pcap -Y http.request -T fields -e frame.number -e http.request.method -e http.request.uri | sed -n '/^10945/,/^10999/p'
Right after the property listing, frame 10999 is a plain GET for a single file under /share/. It is the only file the host actually retrieves from the share, and the extension is an installer package.
tshark -r interceptor.pcap -Y 'http.request.method == "GET" && frame.number == 10999' -T fields -e http.request.uri
The file has to be carved first. --export-objects gave the PROPFIND XML under the MSI’s name, so follow the TCP stream of the GET instead (stream 39) and dump the raw response, then strip the HTTP headers. The result is a real MSI. Hash it and look it up; VirusTotal reports the ssdeep in the file details.
tshark -r interceptor.pcap -q -z follow,tcp,raw,39 > avp_body.hex
sha256sum avp_body.bin
vt "$(sha256sum avp_body.bin | cut -d' ' -f1)"
Gotcha: If the hash you look up belongs to a few kilobytes of XML, VirusTotal will not know it. Check the size of the carved file before submitting it.
The VirusTotal threat label for the package names an Emotet-linked loader family. The NeikiAnalytics comment itself was not read, because the comments tab could not be retrieved and the vt helper does not return comments. This answer is reasoned from the threat label rather than read from the comment. HTB accepted it, which fits the format mask of a six-letter name.
vt --json "$(sha256sum avp_body.bin | cut -d' ' -f1)"
Tip: Open the file’s Community tab in a browser if you want the comment text. The label in the detection details gets you the same family name.
The creation_time attribute comes from the same VirusTotal report as Q4. It is the compile or build stamp stored in the file’s metadata, not when the sample was first submitted, so use the history field named creation time and keep the seconds.
vt --json "$(sha256sum avp_body.bin | cut -d' ' -f1)"
An MSI is a compound file that can be opened as an archive. Listing the carved package with 7-Zip shows an embedded cabinet, and the cabinet holds the payload file that the installer drops and uses. It is a DLL.
7z l avp_body.bin
The malware arrived as a Windows Installer package, and Windows runs .msi files through its built-in installer engine. No other launcher appears in the capture, so this is reasoned from the file type, not read from a process record. HTB accepted it. The packet capture cannot show the process tree.
Note: The capture has no endpoint telemetry. A host log with process creation events would confirm the parent of the DLL load.
Two sources agree. VirusTotal’s Relations tab lists the contacted domains for the package, and the capture contains a DNS query for the same name from the victim just before the C2 beacons start. The domain belongs to a public service that reports a caller’s external IP, which is host discovery before check-in.
vt --rel contacted_domains "$(sha256sum avp_body.bin | cut -d' ' -f1)"
tshark -r interceptor.pcap -Y dns.flags.response==0 -T fields -e frame.number -e dns.qry.name
The check-in to the C2 is unencrypted HTTP carrying JSON. Frame 12608 is the beacon, and it reports the machine’s identity fields in the body. Dump the payload of the POSTs to the C2 and read the hostname field.
tshark -r interceptor.pcap -Y 'frame.number >= 12607 && frame.number <= 12610 && http' -T fields -e frame.number -e http.file_data
Same beacon as Q11. The os_version field holds the Windows version string in major.minor.build form, prefixed with the OS name, matching the format mask.
tshark -r interceptor.pcap -Y 'frame.number == 12608' -T fields -e http.file_data
The beacon from Q11 also carries an owner field. It is a single word, not a username in DOMAIN\user form.
tshark -r interceptor.pcap -Y 'frame.number == 12608' -T fields -e http.file_data
After the download from the WebDAV host, the victim talks to a different external address. Repeated requests to /api/gateway and /tasks on that address, with the same paths on every cycle, mark it as the C2. Count destinations to confirm it dominates the later traffic.
tshark -r interceptor.pcap -Y http.request -T fields -e ip.dst -e http.request.uri | sort | uniq -c | sort -rn
The registration JSON in frame 12607, sent just before the beacon in Q11, includes a key field. This is the RC4 key the implant uses for the tasking channel, handed to the server in the clear.
tshark -r interceptor.pcap -Y 'frame.number == 12607' -T fields -e http.file_data
From Q12 we have the key. The job the server returns in frame 12610 is a base64 blob. Decode it and run RC4 with the Q12 key over the bytes. The plaintext is a JSON task: a command name and an argument list pointing at a download URL on the C2 itself, with the machine’s owner name as the id.
import base64
def rc4(key, data):
s = list(range(256)); j = 0
for i in range(256):
j = (j + s[i] + key[i % len(key)]) % 256
s[i], s[j] = s[j], s[i]
i = j = 0; out = bytearray()
for b in data:
i = (i + 1) % 256; j = (j + s[i]) % 256
s[i], s[j] = s[j], s[i]
out.append(b ^ s[(s[i] + s[j]) % 256])
return bytes(out)
key = open("key.txt", "rb").read().strip()
print(rc4(key, base64.b64decode(open("job.b64").read())).decode())
Tip: Copy the answer exactly, including the space after each colon and the quotes. The format mask is the literal JSON.
| Phase | Action |
|---|---|
| Initial Access | Victim host enumerates a remote WebDAV share with PROPFIND |
| Initial Access | Victim downloads an MSI from the share with a GET |
| Execution | MSI runs through the Windows Installer engine and unpacks a DLL from its cabinet |
| Discovery | Malware queries a public IP lookup service |
| Command and Control | Beacon registers with the C2 over plain HTTP, sending hostname, OS version, owner and RC4 key |
| Command and Control | C2 returns an RC4-encrypted job telling the host to download and run a further module |
| Type | Value |
|---|---|
| IP (victim) | 10.4.17[.]101 |
| IP (WebDAV server) | 87.249.49[.]206 |
| IP (C2) | 85.239.53[.]219 |
| Domain | api[.]ipify[.]org |
| File | avp.msi |
| File (inside MSI) | forcedelctl.dll |
| RC4 key | WkZPxBoH6CA3Ok4iI |
| URL | hxxp[://]85[.]239[.]53[.]219/download?id=Nevada&module=2&filename=None |
| Technique | ID | Description |
|---|---|---|
| Ingress Tool Transfer | T1105 | MSI pulled from a remote WebDAV share |
| User Execution: Malicious File | T1204.002 | Installer package run on the victim |
| System Binary Proxy Execution: Msiexec | T1218.007 | Payload delivered and launched through the Windows Installer engine |
| System Network Configuration Discovery | T1016 | External IP lookup through a public service |
| System Information Discovery | T1082 | Hostname and OS version reported in the beacon |
| Application Layer Protocol: Web Protocols | T1071.001 | C2 over plain HTTP to /api/gateway and /tasks |
| Encrypted Channel: Symmetric Cryptography | T1573.001 | RC4-encrypted tasking, key sent in the registration |
Outbound WebDAV to the internet should be blocked. The victim walked a remote share with PROPFIND and fetched an installer from it over HTTP. WebDAV from workstations to external hosts has little legitimate use, so block it at the proxy or firewall, and alert on PROPFIND toward non-corporate addresses.
Treat MSI files from untrusted sources as executables. The package carried a DLL in an embedded cabinet and ran through msiexec. Restrict msiexec from running packages fetched from the network, and detect .msi downloads that do not come from software distribution infrastructure.
Look for lookups to IP-echo services. The malware resolved a public IP lookup service before check-in. A workstation resolving that domain right after an installer download is a cheap, high-signal detection.
Plain HTTP C2 gives the network the whole story. The beacon leaked host identity and the RC4 key, so the tasking decrypted offline. Full-packet capture or proxy body logging retained for a few days is enough to recover the key, the job and the next-stage URL. Without that retention, this would have been a connection record and nothing more.
A single WebDAV download turned a workstation into a beacon that fetched its next module on command. Everything needed to unravel it, including the key that protected the tasking, crossed the wire in the clear, so the network telemetry alone told the full story.