Skip to content

Reject object ACE whose header exceeds its declared size - #47

Open
chiliec wants to merge 1 commit into
mandiant:mainfrom
chiliec:fix-ace-object-header-overflow
Open

Reject object ACE whose header exceeds its declared size#47
chiliec wants to merge 1 commit into
mandiant:mainfrom
chiliec:fix-ace-object-header-overflow

Conversation

@chiliec

@chiliec chiliec commented Sep 2, 2026

Copy link
Copy Markdown

Problem

ParseACE validates the ACE's declared AceSize against the input length, then for an object ACE advances offset past the ObjectType and InheritedObjectType GUIDs. Those advances are bounded only against len(data), never against aceSize itself:

aceSize := int(binary.LittleEndian.Uint16(data[2:4]))
// ... aceSize >= 8 and len(data) >= aceSize validated ...
offset := 8
if ace.IsObjectACE() {
    // offset can grow to 8 + 4 + 16 + 16 = 44, checked only vs len(data)
}
sid, _, err := ParseSIDBytes(data[offset:aceSize])   // panics if offset > aceSize

A crafted object ACE with a small AceSize (e.g. 12) but ObjectFlags declaring the type GUIDs present pushes offset to 28, so data[offset:aceSize] becomes data[28:12] — an inverted slice range — and Go panics:

panic: runtime error: slice bounds out of range [28:12]

Security descriptors reach ParseACE via ParseSecurityDescriptorParseACL on attacker-controlled data: pkg/relay/ldap_attacks.go parses security descriptors returned by an LDAP server, so a malicious/compromised server can crash the tool.

Reproduction

Added TestParseACE_ObjectAceSizeBelowHeaderNoPanic, which builds an object ACE with AceSize = 12 and OBJECT_TYPE_PRESENT. It panics on the current code and passes with the fix.

Fix

Reject an object header that runs past the ACE's own declared size before slicing:

if offset > aceSize {
    return nil, 0, fmt.Errorf("ACE object header of %d bytes exceeds ACE size %d", offset, aceSize)
}

Validation

go test -race ./pkg/security/   # ok
go vet ./pkg/security/          # clean
gofmt -l pkg/security/          # clean

An object ACE advances the parse offset past the ObjectType and
InheritedObjectType GUIDs (up to 28 bytes), bounded only against the
input length, not the ACE's own declared AceSize. When AceSize is smaller
than that header, data[offset:aceSize] has an inverted slice range and
panics. Security descriptors reach ParseACE from attacker-controlled LDAP
responses (see pkg/relay), so a crafted ACE crashes the process.

Reject offset > aceSize before slicing the SID.
@google-cla

google-cla Bot commented Sep 2, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant