Bug #8577
opendcerpc: bind PDUs with 0 pfc_flags don't match without any_frag
Description
Reported by @alexey -
-PCAP to be provided.
The issue was misrepresented. Conversation on this issue provides clarification.
SB Updated by Shivani Bhardwaj 4 months ago
- Related to Bug #8457: dcerpc.iface keyword matches any interface if PFC_FIRST_FRAG is missing in the BIND request added
PA Updated by Philippe Antoine 4 months ago
Pcap is already merged in SV with previous ticket
PA Updated by Philippe Antoine 4 months ago
If we agree this is the desired behavior, we need mostly to update the doc
AM Updated by Alexey Monastyrskiy 4 months ago
any_frag does not match on PDU with pfc_flags set to 0
I think the issue being discussed is that a lack of `any_frag` makes the signature not match on single-fragment BIND PDUs with pfc_flags set to 0. The PCAP is the same as in #8457. The test is the same as provided in #8457 too. The one that got merged in SV was changed to only match on the session with "normal" BIND pfc_flags, but originally I made it to also match on zeroed-out pfc_flags. (The PCAP contains two sessions.)
SB Updated by Shivani Bhardwaj 4 months ago · Edited
- Subject changed from dcerpc: any_frag does not match on PDU with pfc_flags set to 0 to dcerpc: bind PDUs with 0 pfc_flags don't match without any_frag
- Status changed from New to Rejected
Thank you, alexey ! won't show me packets with flags set to 0 but I had to use an explicit
I apologize. I was using an incorrect Wireshark filter on the PCAP you provided and misunderstood you based on that.
I thought @dcerpc.cn_flags.first_fragdcerpc.cn_flags.first_frag > 0
Based on Philippe's suggestion, I am rejecting this ticket and just keeping the doc update one. Thanks a lot for patiently and actively responding!
SB Updated by Shivani Bhardwaj 4 months ago
- Description updated (diff)
- Assignee deleted (
OISF Dev) - Target version deleted (
9.0.0-beta1)
SB Updated by Shivani Bhardwaj 4 months ago
- Description updated (diff)
PA Updated by Philippe Antoine 4 months ago
- Status changed from Rejected to New
Based on Philippe's suggestion, I am rejecting this ticket
That is not what I meant
I meant the code change is less than one line, but the doc change should be much bigger...
JF Updated by Juliana Fajardini Reichow 4 months ago
- Status changed from New to Triaged
- Assignee set to OISF Dev
- Target version set to 9.0.0-beta1
Re-triaging based on Philippe's comment.
So this needs:
- a (small) fix
- a doc update
Correct?
JI Updated by Jason Ish about 1 month ago
- Related to Documentation #8578: doc: dcerpc any_frag option should mention which PDU is checked added
JI Updated by Jason Ish 29 days ago
- Status changed from Triaged to In Review
Pull request: https://github.com/OISF/suricata/pull/16073
JI Updated by Jason Ish 22 days ago · Edited
As any_frag comes from Snort, it is our intention to be compatible with it. I had Claude Fable run some tests and review the code and came up with this comparison chart:
| # | Scenario | Suricata main | Snort | v1 | v2 |
|----|------------------------------------------------------------------------|---------------|--------------|--------------|--------------|
| 1 | BIND `pfc_flags=0`, request 0x03 (ticket pcap) | no match | match | match | match |
| 2 | BIND with only `PFC_LAST_FRAG`, request 0x03 | no match | match | no match | match |
| 3 | BIND `pfc_flags=0` with `rpc_vers_minor=1` | no match | no match[^1] | no match[^5] | match |
| 4 | Request `pfc_flags=0`, BIND normal | match | no match | match | no match |
| 5 | Request with only `PFC_LAST_FRAG` (first fragment missed) | match | no match | match | no match |
| 6 | Fragmented request 0x01 + 0x02 | match | match | match | match |
| 7 | Request with only `PFC_LAST_FRAG`, rule **with** `any_frag` | match | match | match | match |
| 8 | Request `pfc_flags=0`, rule **with** `any_frag` | match | match | match | match |
| 9 | `flow:to_client` rule, response lacks `PFC_FIRST_FRAG`, request normal | match | no match | match | match[^2] |
| 10 | Request seen before BIND_ACK (context pending) | no match | match[^3] | no match | no match[^2] |
| 11 | Context rejected in BIND_ACK (`result != 0`) | no match | no match | no match | no match |
| 12 | Over SMB: request 0x03 | match | match | match | match |
| 13 | Over SMB: middle-fragment-only request, rule **with** `any_frag` | no match[^4] | match | no match[^4] | no match[^4] |
[^1]: Snort's `DCE2_CoHdrChecks` drops any connection-oriented PDU with
`rpc_vers_minor != 0` as malformed (alert suppressed for SMB), so no
context is ever established and the request cannot match even with
`any_frag`. v2 matches here because the BIND's flags are simply not
consulted.
[^2]: Known remaining divergence from Snort in v2. Response PDU flags are
not tracked (the request's `PFC_FIRST_FRAG` decides for both
directions), and Suricata still requires the context to have been
accepted in a BIND_ACK. A first draft of v2 tracked the response flag
and applied the same gate to SMB; it was dropped to minimize the review
diff.
[^3]: Snort deliberately looks up pending (not yet acknowledged) contexts
from `pending_ctx_ids` in addition to accepted ones, refusing only
rejected contexts, to defeat a request-before-BIND_ACK evasion
(`DCE2_CoSetIface`, `dce2_co.c:1977-2024`; `dce_co.cc:409-448`).
[^4]: Suricata's SMB DCERPC code only creates a request transaction from a
first fragment (`smb_write_dcerpc_record`), so a middle or last fragment
without a preceding first fragment has no transaction to match against.
Unchanged by v1 and v2.
[^5]: v1 agrees with Snort here only by coincidence: v1's zero-flag
exemption requires `rpc_vers_minor == 0`, whereas Snort never parses a
minor-version-1 BIND at all.
The first version of my PR only addresses one item. v2 is a non-existent pull request, but it's not that large and brings us closer to alignment with Snort.
I know very little about DCE RPC so can't present an opinion on if what we do is correct or Snort is. Should we match Snort either way, or go in our own direction?
SB Updated by Shivani Bhardwaj 21 days ago
Interesting. Thanks, Jason!
[^1]: Snort's `DCE2_CoHdrChecks` drops any connection-oriented PDU with
`rpc_vers_minor != 0` as malformed (alert suppressed for SMB), so no
context is ever established and the request cannot match even with
`any_frag`. v2 matches here because the BIND's flags are simply not
consulted.
is making it look like Snort's docs and implementation may not be in sync either? If the only version where fragmentation is allowed is marked malformed, the any_frag definition on the docs does not seem to imply.