SIGS: PackClient stream-aware signatures and Core startup correlation

Hi y’all,

I REd PackClient and identified a TCP stream robustness issue in the existing ET PackClient Launcher signatures.

The current PLH1 / PLC1 / PLA1 / PLK1 detections (ET SIDs 2069878–2069882) rely on packet-boundary assumptions that hold for the observed capture layout, but equivalent PackClient traffic can be segmented or coalesced differently during normal TCP transport.

I reproduced this under Suricata 7.0.3 and prepared stream-aware equivalents that retain the existing PackClient protocol anchors while matching against the reassembled TCP stream.

I also included an optional PackClient Core startup correlation based on traffic recovered during my reverse engineering. It correlates:

SYS|Q|EXT|STARTUP|PROBE|

with:

SYS|R|EXT|STARTUP|OK|tags=

on the same established TCP flow before alerting.

I originally submitted this to support@emergingthreats.net on September 11, but I’m posting it here as well for visibility and community review.

Proposed rules

The SIDs in the rules below are temporary submission/validation identifiers only. For ET SIDs 2069878–2069882, the existing upstream SID/message/reference/metadata can be retained while replacing the packet-boundary-dependent predicates with the corresponding stream-aware logic.

# PackClient — ET Open stream robustness submission
#
# Mapping:
#   9900101 -> ET 2069878 (PLH1 length prefix)
#   9900102 -> ET 2069879 (PLH1 check-in body)
#   9900103 -> ET 2069880 (PLC1 C2 response)
#   9900104 -> ET 2069881 (PLA1 payload request)
#   9900105 -> ET 2069882 (PLK1 C2 response)
#   9900110/9900111/9900112 -> optional Core startup correlation

alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"PackClient PLH1 length prefix stream"; flow:established,to_server,only_stream; content:"|24 00 40 5a|"; fast_pattern; reference:url,www.proofpoint.com/us/blog/threat-insight/carry-compromise-ta4922-packs-packclient; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900101; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"PackClient PLH1 stream"; flow:established,to_server,only_stream; content:"|24 00 40 5a 15 00 00 00|PLH1"; fast_pattern; reference:url,www.proofpoint.com/us/blog/threat-insight/carry-compromise-ta4922-packs-packclient; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900102; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PackClient PLC1 stream"; flow:established,to_client,only_stream; content:"|1c 00 40 5a 15 00 00 00|PLC1"; fast_pattern; reference:url,www.proofpoint.com/us/blog/threat-insight/carry-compromise-ta4922-packs-packclient; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900103; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"PackClient PLA1 stream"; flow:established,to_server,only_stream; content:"|2c 00 40 5a 15 00 00 00|PLA1"; fast_pattern; reference:url,www.proofpoint.com/us/blog/threat-insight/carry-compromise-ta4922-packs-packclient; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900104; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PackClient PLK1 stream"; flow:established,to_client,only_stream; content:"|3c 00 40 5a 15 00 00 00|PLK1"; fast_pattern; reference:url,www.proofpoint.com/us/blog/threat-insight/carry-compromise-ta4922-packs-packclient; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900105; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

# Optional Core startup correlation. Match each semantic message on reassembled
# stream data, then alert once both states are present on the same TCP flow.
alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"PackClient Core startup probe state"; flow:established,to_client,only_stream; content:"SYS|7c|Q|7c|EXT|7c|STARTUP|7c|PROBE|7c|"; fast_pattern; flowbits:set,ET.packclient.core_startup_probe; flowbits:noalert; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900110; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"PackClient Core startup response state"; flow:established,to_server,only_stream; content:"SYS|7c|R|7c|EXT|7c|STARTUP|7c|OK|7c|tags="; fast_pattern; flowbits:set,ET.packclient.core_startup_response; flowbits:noalert; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900111; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

alert tcp $HOME_NET any <> $EXTERNAL_NET any (msg:"PackClient Core startup probe and response"; flow:established; flowbits:isset,ET.packclient.core_startup_probe; flowbits:isset,ET.packclient.core_startup_response; flowbits:unset,ET.packclient.core_startup_probe; flowbits:unset,ET.packclient.core_startup_response; reference:url,ivanimmanuel-dev.github.io/PackClient/; classtype:trojan-activity; sid:9900112; rev:1; metadata:attack_target Client_Endpoint, created_at 2026_09_11, deployment Perimeter, malware_family PackClient, confidence High, signature_severity Major, updated_at 2026_09_11;)

Validation

The submitted rules parse successfully under Suricata 7.0.3.

Engine-level testing confirmed that:

  • the observed four-byte split layout satisfies the existing packet-oriented predicates;
  • equivalent PackClient frames delivered as coalesced TCP payloads can bypass those predicates;
  • segmentation within the PackClient framing can also prevent packet-oriented matching;
  • the stream-aware Launcher signatures continue to match after TCP reassembly;
  • the Core startup alert requires both the probe and response on the same TCP flow;
  • a response without the corresponding probe does not produce the correlated alert;
  • the Core startup correlation survives segmentation in both directions.

References

PackClient reverse-engineering research:

Original Proofpoint PackClient research:

Happy to adjust the signatures or provide additional captures/validation if useful.

Thanks,

Ivan Immanuel Shaji