Blackbox Protobuf

repository·master·Indexed 20 days ago

https://github.com/nccgroup/blackboxprotobuf

A suite of tools and a Python library (bbpb) for decoding and manipulating Protocol Buffer messages without requiring original .proto definition files. It includes a library for encoding/decoding messages and type definitions, as well as extensions for Burp Suite and mitmproxy to facilitate security testing, reverse engineering, and forensics.

Tokens
16.6K
Snippets
49
Records
80
Agent score
70%

What's inside blackboxprotobuf

  1. Overview of Blackbox Protobuf capabilities

    master
    Blackbox Protobuf is a toolset designed to work with encoded Protocol Buffers (protobuf) when the original .proto message definitions are unavailable. It is useful for analyzing or modifying binary network traffic that lacks human-readable structure, making it a key tool for mobile penetration testing, reverse engineering, and digital forensics.
  2. Understand the Type Definition structure

    master

    The type definition is a Python dictionary where keys are field numbers and values are dictionaries containing field attributes.

    Required Attributes:

    • type: A string identifier for the type (e.g., int, string, uint). Valid identifiers are located in blackboxprotobuf/lib/types/type_maps.py.

    Nested Messages: To define a nested message, use one of the following in the field's value dictionary:

    • message_typedef: A second type definition dictionary for the inner message.
    • message_type_name: A string identifier for a message type previously stored in blackboxprotobuf.known_messages.

    Note: If both are specified, message_type_name is ignored.

  3. Type Definition Format and Structure

    master

    A type definition is a Python dictionary (or JSON object) where each key is the field number (as a string) and the value is a Field Definition dictionary containing metadata.

    Example Structure

    {
        "1": {
            "name": "email",
            "type": "string"
        },
        "2": {
            "name": "uid",
            "type": "int"
        },
        "3": {
            "type": "string"
        }
    }
    {
        "1": {
            "name": "email",
            "type": "string",
          },
        "2": {
            "name": "uid",
            "type": "int",
          },
        "3": {
               "type": "string",
             }
    }
  4. How Type Definitions work in BBPB

    master

    Type Definitions (typedefs) are data structures used by BBPB to store metadata about a protobuf message and its fields, including exact types and field names.

    Decoding

    Typedefs are optional during decoding. If a typedef is not provided or is missing metadata for a field, BBPB performs a best-effort guess of the type based on the field's wire type.

    Important: The decoding function returns a typedef containing the types it actually used to decode each field. You must use this returned typedef to re-encode the message successfully. If you provided an initial typedef, the returned version will be a copy that includes type values for any previously unknown fields.

    Encoding

    Typedefs are required when encoding a message back to protobuf. The encoder uses the typedef to map fields to their correct binary representation. If the message contains a field not present in the typedef, an exception will be raised.

    Best Practice: Always use the exact type definition returned by the decoder for encoding. If you need to change a field's type, decode the message again using the modified typedef rather than manually editing the dictionary before encoding.

  5. Handle polymorphic fields with `alt_typedefs`

    master

    In scenarios where a single field number might contain different message types (e.g., when using google.protobuf.Any or embedding messages as bytes), BBPB uses alt_typedefs.

    If the primary message_typedef (indexed at 0) fails to decode a field, BBPB attempts to use definitions found in the alt_typedefs dictionary.

    Identifying Alternate Types: When a field is decoded using an alternative definition, the decoder indicates this in the output by appending the index of the alternative definition to the field number or name with a hyphen.

    • Example: "1-2" means field number 1 was decoded using alt_typedefs[2].
    • Example: "user_profile-2" means the field named user_profile was decoded using alt_typedefs[2].

    To re-encode such a field, you must use the specific alternative definition identified by that index.

  6. Available Blackbox Protobuf interfaces

    master

    Blackbox Protobuf provides several different interfaces depending on your workflow:

    • Python Library: A core library (bbpb) that can be integrated into other Python applications.
    • Python CLI: A command-line interface embedded within the library for quick interactions.
    • Burp Extension: A Jython-based extension for use within Burp Suite.
    • mitmproxy Addon: An addon for mitmproxy to intercept and handle protobuf traffic.
  7. Persist Protobuf Type Data

    master

    By default, edited types and endpoint mappings are stored in memory and lost when mitmproxy shuts down or the addon is reloaded. To persist this data, use one of the following methods:

    Using a Project File

    Set the bbpb_project_file option in your mitmproxy configuration. The addon will automatically load types from this file on startup and write any changes back to it. Warning: Back up your project file regularly to prevent data loss from overwrites.

    Manual Save/Load

    Use the following commands within the mitmproxy interface to manually manage a JSON project file:

    • :bbpb.project.save
    • :bbpb.project.load
  8. Handle payload encodings like gzip or gRPC

    master

    The CLI automatically detects and handles common wrapper encodings like gzip compression and gRPC headers.

    • Decoding: If a wrapper is detected, it is unpacked, and the encoding type is stored in the payload_encoding field of the output JSON.
    • Encoding: The encoder will re-apply the detected wrapper. If no encoding is provided, it defaults to none.
    • Manual Override: You can manually specify the encoding using the -pe/--payload-encoding flag.
  9. Use the JSON Protobuf format for CLI tools

    master

    The -j/--json-protobuf flag allows passing both the protobuf data and the type definition in a single JSON object. This is ideal for automation where you want to avoid writing temporary files to disk.

    Input format (for decoding): A JSON object with:

    • protobuf_data: The base64 encoded protobuf bytes.
    • typedef (optional): The type definition.

    Output format (for encoding): A JSON object with:

    • protobuf_data: The base64 encoded protobuf bytes.
    • typedef: The type definition.
    # Decode from a single JSON object instead of stdin binary
    echo '{"protobuf_data": "...base64...", "typedef": {...}}' | bbpb -j
    
    # Encode to a single JSON object instead of stdout binary
    echo '{"message": {...}, "typedef": {...}}' | bbpb -e -j
  10. Decode Protobuf messages with the CLI

    master

    The default mode of the CLI is decoding. It takes a binary protobuf payload (provided via stdin) and outputs a JSON object containing the decoded message and the typedef.

    To use a specific type definition for decoding, use the -it/--input-type flag pointing to a file. To output only the decoded message without the type definition, use the -r/--raw-decode flag.

    # Simple raw decode (JSON message only)
    cat test_data | bbpb -r
    
    # Decode using a saved type definition file
    cat test_data | bbpb -it ./saved_type.json
    
    # Save the type definition to a file while decoding
    cat test_data | bbpb -ot ./saved_type.json
  11. Change default types for wire types using Config

    master

    You can override the default type used for a specific wire type by providing a Config object to the decoder and modifying its default_types dictionary. The key must be the wiretype (e.g., from wiretypes.py).

    Note on Length Delimited types: default_types is not used for length-delimited fields due to fallback logic. To change the fallback for length-delimited fields, modify default_binary_type on the Config object. This can change the representation (e.g., to bytes_hex) or default to a packed_* type.

    # Example: Changing the default type for FIXED64 to double
    config.default_types[wiretypes.FIXED64] = 'double'
  12. Manage type definitions via the Protobuf Type Editor Tab

    master

    The Protobuf Type Editor Tab allows you to manage named type definitions globally, independent of active requests.

    Features:

    • CRUD Operations: Create, rename, edit, and remove type definitions.
    • Backup/Sharing: Use Save All Types or Load All Types to export/import definitions as JSON files. While named types persist across Burp reboots, regular backups are recommended.
    • .proto Support:
      • Export: Attempts to save known type definitions into .proto format for use in other tools.
      • Import: Attempts to read a .proto file and create Blackbox protobuf type definitions.
      • Note: Import does not support import statements; you must import referenced files manually first. Both features are experimental.