Skip to content

kerberos: reject encryption types wider than Int32 - #5107

Open
KernelClint wants to merge 1 commit into
secdev:masterfrom
KernelClint:perf/kerberos-etype-int32
Open

kerberos: reject encryption types wider than Int32#5107
KernelClint wants to merge 1 commit into
secdev:masterfrom
KernelClint:perf/kerberos-etype-int32

Conversation

@KernelClint

Copy link
Copy Markdown
Contributor

Kerberos TCP reassembly parses EncryptedData.etype, a protocol Int32, as a generic BER integer.
The field accepts an attacker-declared width at
scapy/layers/kerberos.py:377-383,
then shifts a growing Python integer once per byte at
scapy/asn1/ber.py:464-471.

From 4,000 to 64,000 integer bytes, median processing grew from 1.40 ms to 318.41 ms, with an
exponent of 2.08 and a 3.9% noise floor. The patched parser rejected the same inputs in 0.02 ms to
0.06 ms. Its 186.6% micro-timing noise floor made a fixed exponent inconclusive, so none is claimed.

This change rejects etype encodings wider than Int32 before arbitrary-precision conversion.
The focused regression failed on the unmodified revision and passed with the patch; ordinary
one-byte etype values continue to use the existing BER decoder.

AI-Assisted: yes (GPT-5.6-Cyber)
@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 25.00000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.48%. Comparing base (ba8641a) to head (6476809).
⚠️ Report is 10 commits behind head on master.

Files with missing lines Patch % Lines
scapy/layers/kerberos.py 25.00% 6 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (ba8641a) and HEAD (6476809). Click for more details.

HEAD has 10 uploads less than BASE
Flag BASE (ba8641a) HEAD (6476809)
12 2
Additional details and impacted files
@@             Coverage Diff             @@
##           master    #5107       +/-   ##
===========================================
- Coverage   80.59%   47.48%   -33.12%     
===========================================
  Files         390      372       -18     
  Lines       96892    96539      -353     
===========================================
- Hits        78094    45844    -32250     
- Misses      18798    50695    +31897     
Files with missing lines Coverage Δ
scapy/layers/kerberos.py 31.80% <25.00%> (-38.71%) ⬇️

... and 340 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gpotter2

gpotter2 commented Aug 27, 2026

Copy link
Copy Markdown
Member

Correct me if I'm wrong, but while a negative value properly doesn't make sense, it's still whats in the spec: https://www.rfc-editor.org/info/rfc4120/#section-5.2.9. I'm not sure I understand the issue otherwise

@KernelClint

Copy link
Copy Markdown
Contributor Author

You're right that negative values are legal, and the patch keeps them — it never looks at the value.
It only bounds how many octets the encoding may use, and it is deliberately looser than the type.

To be precise about what it is: this is a resource bound, not validation of Int32. RFC 4120 §5.2.9
constrains the value to -2147483648..2147483647, which in DER is at most 4 content octets. The
check rejects at more than 5, so it still accepts things that are not legal Int32 — a 5-octet
00 ff ff ff ff decodes to 4294967295 and passes. That looseness is on purpose: the aim was to kill
the pathological arbitrary-width case without tightening Scapy's generally permissive BER decoding
any more than necessary.

The reason for it is cost. BER_num_dec shifts an arbitrary-precision integer once per byte, so work
grows with the square of the declared width, and EncryptedData is reachable from Kerberos TCP
reassembly. Measured on master:

integer bytes before after
4,000 1.32 ms 0.01 ms
16,000 17.91 ms 0.01 ms
64,000 281.95 ms 0.02 ms

If a loose bound in a Kerberos-specific field subclass isn't worth it, the reasonable alternatives are
a generic width cap in the BER integer decoder, or nothing at all. Happy either way — the only thing
at stake is the cost, not correctness.

@gpotter2

Copy link
Copy Markdown
Member

BER_num_dec already caps the integer with a maximum value, maybe it needs to be tweaked to a lower one. I think that what is described here is a generic issue (related to ASN.1 BER), rather than something specific to kerberos.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants