peass-ng/PEASS-ng · error · IOException

unexpected end-of-contents marker

Error message

unexpected end-of-contents marker

What it means

Asn1InputStream.ReadObject throws this IOException when the first byte of an expected ASN.1 object is 0x00, which in BER/DER is the end-of-contents (EOC) marker for indefinite-length constructions, not a valid object tag. It signals the stream's structure does not match what the caller expects — usually an extra or misplaced EOC byte.

Source

Thrown at winPEAS/winPEASexe/winPEAS/3rdParty/BouncyCastle/asn1/Asn1InputStream.cs:169

        internal virtual DerSequence CreateDerSequence(
            DefiniteLengthInputStream dIn)
        {
            return DerSequence.FromVector(ReadVector(dIn));
        }

        internal virtual DerSet CreateDerSet(
            DefiniteLengthInputStream dIn)
        {
            return DerSet.FromVector(ReadVector(dIn), false);
        }

        public Asn1Object ReadObject()
        {
            int tag = ReadByte();
            if (tag <= 0)
            {
                if (tag == 0)
                    throw new IOException("unexpected end-of-contents marker");

                return null;
            }

            //
            // calculate tag number
            //
            int tagNo = ReadTagNumber(this.s, tag);

            bool isConstructed = (tag & Asn1Tags.Constructed) != 0;

            //
            // calculate length
            //
            int length = ReadLength(this.s, limit, false);

            if (length < 0) // indefinite-length method
            {

View on GitHub (pinned to 53fb989abc)

Solutions

  1. Stop looping when ReadObject returns null (it signals end-of-data after an EOC) instead of expecting an exception-free loop to a fixed count.
  2. Check the stream/offset alignment — you are likely positioned at an EOC marker byte (0x00) that belongs to an enclosing indefinite-length structure.
  3. If indefinite-length BER is expected, use Asn1StreamParser instead of Asn1InputStream, which handles EOC markers correctly.
  4. Trim trailing zero padding from the input before parsing.

Example fix

// before
while (true) { Asn1Object o = stream.ReadObject(); Process(o); }
// after
Asn1Object o;
while ((o = stream.ReadObject()) != null) { Process(o); } // null on EOC/end
Defensive patterns

Strategy: validation

Validate before calling

static IEnumerable<Asn1Object> ReadAll(Asn1InputStream s)
{
    Asn1Object o;
    while ((o = s.ReadObject()) != null) // null = EOC/end, never loop past it
        yield return o;
}
// also trim trailing zero padding:
// while (data.Length > 0 && data[data.Length-1] == 0) Array.Resize(ref data, data.Length-1);

Try / catch

try {
    Asn1Object obj = stream.ReadObject();
} catch (IOException ex) when (ex.Message == "unexpected end-of-contents marker") {
    // stream positioned at an EOC byte: adjust offset or stop parsing
    return null;
}

Prevention

When it happens

Trigger: ReadObject is called on a stream positioned at a 0x00 byte — typically after an indefinite-length object's content was fully consumed but the caller calls ReadObject again, or the byte offset into the buffer is wrong by one (parsing trailing padding/EOC bytes as a new object).

Common situations: Calling ReadObject in a loop over a BER stream containing indefinite-length encoded data whose EOC terminator is then read as a top-level object; hand-slicing a byte array with a wrong offset; parsing data with trailing zero padding.

Related errors


AI-assisted analysis of peass-ng/PEASS-ng@53fb989abc (2026-09-02). Data as JSON: /api/errors/9ac2cd90c2520929. Report an issue: GitHub.