Jamal Darbo// Security PortfolioPortfolio v1
Portfolio Blog
Back to blog

Security notes

Investigating Koi Stealer malware using Wireshark

An end-to-end Wireshark investigation of a Koi Stealer packet capture, examining beaconing, HTTP payloads, internal network activity and indicators of compromise.

Originally published on Medium on 15 April 2025. Select a screenshot to open the full-size image.

In this write-up, I will analyze a pcap file from www.malware-traffic-analysis.net. I will use the pcap from the exercise: BIG FISH IN A LITTLE POND. The goal is to identify malicious behavior, and extract indicators of compromise (IOCs), but I mainly wanted to practice my Wireshark skills.

This article walks through an end-to-end analysis using Wireshark, starting with a high-level overview and progressively drilling into anomalies and patterns.

The scenario has the following LAN segment details:

  • LAN segment range: 172.17.0[.]0/24 (172.17.0[.]0 through 172.17.0[.]255)
  • Domain: bepositive[.]com
  • Active Directory (AD) domain controller: 172.17.0[.]17 — WIN-CTL9XBQ9Y19
  • AD environment name: BEPOSITIVE
  • LAN segment gateway: 172.17.0[.]1
  • LAN segment broadcast address: 172.17.0[.]255

Taking a look at the bigger picture

Before diving into individual packets, it’s useful to take a look at the traffic at a macro level. This high-level perspective allows us to establish context: What protocols are in use? Which endpoints are most active? Are there external connections? Which IP addresses are talking the most? By reviewing these different types of statistics, we can identify potential anomalies, prioritize areas for deeper inspection, and avoid drowning in packets.

First, I like to take a look at the Protocol Hierarchy to get a general impression of the protocols being used. One protocol that stands out to me is SMB — specifically, because it’s an older version of SMB. This doesn’t necessarily mean anything by itself but it could be easier be abused than SMBv2 or SMBv3. Also, the Active Directory Replication traffic could be interesting, depending on the context. Another protocol that jumps out is HTTP, due to it being an unecrypted protocol which can be used for exfiltration or command-and-control (C2) communication.

Wireshark Protocol Hierarchy showing protocols in the packet capture

The next thing I like to do take a look at the Conversations and sort on Duration, which is the total time a network conversation lasted. In this case, you can see four “winners”, but one of them is especially suspect to me: 79.124.78[.]197.

Wireshark conversations sorted by duration

Why aren’t the other IP addresses not immediately suspect to me? Because the 172.17.x.x addresses are part of the LAN segment range, and the other address (20.10.31[.]115) is a Microsoft IP address. It also noteworthy to remember the Stream ID (IP stream, not the TCP or UDP stream) for later use, which is 22 in our case. The IP stream tracks all packets between two IP addresses, regardless of the protocols.

Looking at the Endpoints tab we can see a suspicious packets-to-bytes ratio. There are many packets being sent, but with few bytes. This could suggest beaconing (C2-traffic):

Wireshark endpoints and their packet and byte counts

The final item I like to inspect from the Statistics tab, is the list of HTTP requests. In this case, we can clearly observe some suspicious POST requests from the same IP address:

HTTP request statistics showing suspicious POST requests

Our first general impression from looking at the bigger picture is that a significant portion of the traffic seems to originate from a suspicious IP: 79.124.78[.]197. This IP address is issuing strange POST requests and warrants further investigation.

Dissecting the IP stream

Looking at the IP stream by using the filter “ip.stream eq 22”, we can clearly see malicious traffic originating from our infected host: 172.17.0[.]99. We can see multiple POST requests, but also a GET request over HTTP:

Packets in IP stream 22 between the infected host and external server

By opening Statistics > Flow Graph from here, we can change the Y axis to display bytes in order to show the amount of data transferred over time. This is useful for identifying C2 beaconing behaviour. I use an interval of 1-second in the image below. In this case we can see periodic bursts, possibly indicating beaconing behavior associated with C2 communication:

Traffic graph showing periodic bursts of network activity

Furthermore, we can add a Time Delta column by adding a column with the “frame.time_delta_displayed” field (credits to Active Countermeasures for this):

Wireshark column configuration for frame.time_delta_displayed

Looking at the Time and Time Delta columns we can see a pattern. We can see a Time Delta of around 60 seconds every 12 packets or so, showing the time difference between the current packet and the previous packet in the packet list. We can also notice a consistent pattern between the source and destination ip-addresses after the 60 seconds intervals (see column in the middle). This means that 172.17.0[.]99 is periodically reaching out to the external server (79.124.78[.]197). Malware often “checks in” to receive instructions from its C2-server, so this is important to keep in mind.

Packet list with Time and Time Delta columns showing repeated intervals

Investigating HTTP traffic

Looking at the HTTP traffic with the filter “ip.addr == 79.124.78[.]197 && http”, we can observe binary data being transferred, which is a red flag in this case. This is likely due to some form of malware evasion:

HTTP traffic with binary request data

Taking a closer look at the data, we can observe the following string “3130327c33303136383231332d336265302d613735312d383161302d636633623232386338363534” (edit: to clarify, the following screenshot is data from one of the other frames in the image above, hence you see 40 bytes instead of 94):

Hexadecimal data from a captured packet

This string can be decoded with Cyberchef by using a “from Hex” recipe, which gives us the following result “102|30168213–3be0-a751–81a0-cf3b228c8654”:

CyberChef From Hex recipe and decoded identifier

This looks like some sort of UUID that the C2 server is using. We can search for this string in the packet bytes to confirm this, because the string is identifiable in every POST request:

Searching packet bytes for the recurring identifier

Other identifiers we can extract from the POST request from the same IP stream (by using (ip.stream eq 22 ) && (http.request.method == “POST” ))) are:

101|30168213–3be0-a751–81a0-cf3b228c8654|5LHtVruc|f3f3oMg2lz4XGyHy0LidzFiNvSftke//k+COyrO9aBI=

111|30168213–3be0-a751–81a0-cf3b228c8654|XHfhyxOtsArXQLiP|=¬ª|U7÷#±/ónåH -øî1
Rm¹UÂO‰ÖyBÓÌ\vK¹sâl­4ð]7ø´1
Z (I am not sure what this last part is. If someone can help me, that would be great.)

102|30168213–3be0-a751–81a0-cf3b228c8654

The general structure seems to start with the following: <Code>|<UUID>|<Session ID>. Only frame 1668 seems to be using 101 as a code in the whole packet capture, and only frame 1672 uses code 111. This is probably due to something that the malware is doing at the start:

Initial HTTP requests containing payload codes 101 and 111

All the following POST foot requests are using code 102, with a consistent length of 443:

POST request
POST request

Opening a TCP stream from here shows this to us as well:

TCP Stream 48
TCP Stream 48

The user-agent is also highly suspicious because it is from an older version of Internet Explorer. Which is in this context also a clear indicator of malware:

Mozilla 4 0 Compatible Msie 7 Windows Nt 10 Wow64 Trident Net4 0C 0E Net Clr 2 50727 3 30729 5 — List of User Agent Strings
Mozilla 4 0 Compatible Msie 7 Windows Nt 10 Wow64 Trident Net4 0C 0E Net Clr 2 50727 3 30729 5 — List of User Agent Strings

Infiltration in progress

Given the fact that there is SMB traffic observed, it could be wise to look for possible lateral movement or enumeration in the pcap. Using the following display filter: “kerberos || smb2 || smb || dcerpc”, we can filter for interesting traffic:

bindRequest
bindRequest

As you can see, this is a conversation between our infected host and 172.17.0[.]17, which is the Domain Controller (DC). The bindRequest(7) “<ROOT>” sasl from our infected host to the DC is possibly interesting, because this shows a succesful LDAP bind. So I’ve marked it in Wireshark so we can inspect the whole pcap without a filter. Interestingly enough, we can see a dynamic DNS update before the bindRequest happens coming from the host:

Possible DNS server dynamic update record injection
Possible DNS server dynamic update record injection

This seems to me like a dynamic DNS server dynamic update record injection (see: DNS Server Dynamic Update Record Injection — Virtue Security), but I am not 100% sure about it. It deletes records and afterwards updates the A record to 172.17.0[.]99. Although this behavior can occur in legitimate domain environments, it can also be leveraged by malware to masquerade as a trusted host or prepare for internal lateral movement:

Dynamic DNS update
Dynamic DNS update

We can also observe LANMAN traffic when filtering for SMB which is another red flag. LANMAN is a legacy protocol and is often abused by bad actors for enumeration. The only reason to enable it is for compatability reasons with legacy systems. When filtering with “lanman” as display filter, it shows short-lived communication from 2 minutes, which is possibly due to enumeration:

LANMAN enumeration
LANMAN enumeration

Let’s get back to the host again. Filtering data traffic for 172.17.0[.]99 by using “(ip.addr == 172.17.0[.]99) && (data)”, shows us another important IP address: 46.254.34[.]201. This one we haven’t seen before yet:

Data traffic involving the infected host and an additional external IP address

Looking it up in VirusTotal shows us that it is related to the KOI malware. It also shows the same URL we can observe when opening the TCP stream from the same packet from above. This is obviously a red flag:

URL in TCP stream 41
URL in TCP stream 41
VirusTotal results
VirusTotal results

The first connection to this IP address happens at 17:35:04. This is short-lived communications which ends at 17:36:46. Which probably indicates that another layer of infection happened at that time:

Traffic to 46.x.x.x
Traffic to 46.x.x.x

So to recap, we now have three IP addresses involved with malicious traffic:

172.17.0[.]99 — compromised host
79.124.78[.]197 — C2 server
46.254.34[.]201 — suspicious traffic to a compromised domain

Suspicious TLS traffic

When further investigating the 46.x.x.x IP-address, we can filter for the TLS Client Hello and the TLS Server Hello with “ip.addr == 46.254.34[.]201 && (tls.handshake.type == 1 || tls.handshake.type == 2)”. From here we can gather the JA3 fingerprints and look them up. JA3 fingerprints can be useful for identifying TLS traffic:

JA3 fingerprints
JA3 fingerprints

The JA3 fingerprint values are:
3c4eb72b882d4d1442c67ce73f1292a9 — TLS Client Hello
15af977ce25de452b96affa2addb1036 — TLS Server Hello

Both of these are related to malware, although this is not a strong indicator by itself because bad actors can spoof this.

Conclusion

This pcap analysis strongly indicates malicious activity consistent with KOI Stealer infection. The internal host 172.17.0[.]99 communicates periodically with the C2 server 79.124.78[.]197 using obfuscated POST requests over HTTP. The pattern of communication suggests beaconing behavior. In addition, the dynamic DNS update and LDAP bind to the Domain Controller (172.17.0[.]17) may indicate preparatory steps for lateral movement. The connection to 46.254.34[.]201 also increases confirms the presence of KOI Stealer or related malware. I hope you found this article useful — feel free to share your thoughts.

IOCs:

IP Addresses
172.17.0.99 — Infected host inside LAN
79.124.78.197 — C2 server
46.254.34.201 — Malicious external server

User-Agent
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)

HTTP URIs
/foots[.]php
/index[.]php?id=&subid=qIOuKk7U
/index[.]php
bellantonicioccolato[.]it

POST Payload patterns
- 101|30168213–3be0-a751–81a0-cf3b228c8654|5LHtVruc|f3f3oMg2lz4XGyHy0LidzFiNvSftke//k+COyrO9aBI=
- 111|30168213–3be0-a751–81a0 cf3b228c8654|XHfhyxOtsArXQLiP|=¬ª|U7÷#±/ónåH -øî1 Rm¹UÂO‰ÖyBÓÌ\vK¹sâl­4ð]7ø´1 Z
- 102|30168213–3be0-a751–81a0-cf3b228c8654

Dynamic DNS Update
A-record update to 172.17.0.99

JA3 Fingerprints
3c4eb72b882d4d1442c67ce73f1292a9 — TLS Client Hello
15af977ce25de452b96affa2addb1036 — TLS Server Hello

Sources

Malware-Traffic-Analysis.net — 2024–09–04 — Traffic analysis exercise: Big Fish in a Little Pond (this is just a page to the file, not the file itself, don’t worry)

https://blog.nviso.eu/2021/11/15/detecting-dcsync-and-dcshadow-network-traffic/

https://activecm.github.io/threat-hunting-labs/beacons/

DNS Server Dynamic Update Record Injection

Application Layer Protocol: DNS, Sub-technique T1071.004 — Enterprise | MITRE ATT&CK®

CyberChef