Skip to content

Add protocol/grpc helper for plaintext gRPC exploits#588

Open
vlobstein-vc wants to merge 8 commits into
mainfrom
feat/grpc-protocol
Open

Add protocol/grpc helper for plaintext gRPC exploits#588
vlobstein-vc wants to merge 8 commits into
mainfrom
feat/grpc-protocol

Conversation

@vlobstein-vc
Copy link
Copy Markdown
Collaborator

@vlobstein-vc vlobstein-vc commented May 6, 2026

Summary

The framework already eliminates HTTP boilerplate for modules via protocol/httphelper: callers say HTTPSendAndRecv(...) and the framework handles the client, transport, TLS, timeouts, redirects. Modules targeting gRPC services have not had the same treatment, so they rewrite the same dial / codec / context / TLS plumbing every time. This PR fills that gap with protocol/grpc/.

Two layers:

  • Invoke(host, port, method, in, timeoutSec, ssl) runs a unary RPC and returns the response body or ok=false on any failure. Modules stay free of fmt, context and google.golang.org/grpc imports.
body := grpc.EncodeBytesField(1, payload)
out, ok := grpc.Invoke(host, port, "/svc/Method", body, 5, conf.SSL)
  • Dial(host, port, ssl) returns a configured *grpc.ClientConn for everything Invoke does not cover: server- / client- / bidi-streaming RPCs, gRPC reflection, or amortising one connection across many calls. The caller drives the standard grpc-go ClientStream API.

EncodeBytesField / EncodeStringField wrap values as proto3 length-delimited fields so modules can skip protoc on simple messages. For complex schemas, callers bring their own protoc-generated marshallers and pass the resulting bytes through the raw codec.

The TLS config mirrors protocol/httphelper.go (InsecureSkipVerify, permissive MinVersion) for the same reason: exploit targets routinely have self-signed or expired certs and unknown TLS versions.

This adds google.golang.org/grpc to the framework go.mod. One earlier exploit module already pulled it transitively, so this hoists what was a pseudo-shared dependency into a real shared package.

Comment thread protocol/grpc/grpc.go Fixed
@vlobstein-vc vlobstein-vc force-pushed the feat/grpc-protocol branch from 98987f2 to 12be363 Compare May 6, 2026 11:01
Comment thread protocol/grpc/grpc.go Dismissed
Comment thread protocol/grpc/grpc.go Dismissed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new protocol/grpc helper package to reduce boilerplate for exploit modules interacting with plaintext (h2c) and TLS gRPC services, mirroring the ergonomics provided by protocol/httphelper.

Changes:

  • Introduces protocol/grpc with Dial and Invoke built around a raw-bytes gRPC codec, plus minimal proto3 wire-format helpers (EncodeBytesField, EncodeStringField).
  • Adds unit tests covering the proto field encoding helpers.
  • Updates go.mod / go.sum to include google.golang.org/grpc and related transitive dependencies.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
protocol/grpc/grpc.go New gRPC helper API (Dial/Invoke), raw codec, and simple proto wire-format encoders.
protocol/grpc/grpc_test.go Tests for EncodeBytesField / EncodeStringField fixtures and varint length encoding.
go.mod Adds google.golang.org/grpc and required indirect protobuf/genproto deps.
go.sum Records checksums for newly introduced direct/transitive modules.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread protocol/grpc/grpc.go Outdated
Comment thread protocol/grpc/grpc.go
Comment thread protocol/grpc/grpc.go
@vlobstein-vc vlobstein-vc requested a review from j-baines May 8, 2026 17:42
Copy link
Copy Markdown
Collaborator

@lobsterjerusalem lobsterjerusalem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of comments.

Comment thread protocol/grpc/grpc.go Outdated
Comment thread protocol/grpc/grpc.go Outdated
Comment thread protocol/grpc/grpc.go
Modules targeting unauth gRPC services (lerobot async-inference, etc.)
need three things: dial an h2c endpoint, ship pre-encoded protobuf
bytes through a unary RPC, and shape the request as a proto3 message
without pulling in protoc. The package wraps grpc-go behind two
high-level functions:

  Invoke(host, port, method, in []byte, timeoutSec int) ([]byte, bool)
  EncodeBytesField(fieldNumber uint32, value []byte) []byte

A package-level rawCodec passes pre-encoded bytes through grpc-go's
codec pipeline untouched so callers do not need proto.Message values.
The codec is registered from package init because grpc-go's codec
registry is process-wide.

Tests cover EncodeBytesField with empty / short / multi-byte-varint /
high-tag inputs plus a thin EncodeStringField wrapper.

The framework now depends on google.golang.org/grpc; one earlier
exploit module (cve-2025-68926) already pulled it transitively, so
this hoists what was effectively a pseudo-shared dependency into a
proper shared package.

Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
Doc strings were stating the obvious on every exported symbol.
Tightened to one-liners where the function name + signature already
say enough. Two parallel sentinel errors (errMarshalType /
errUnmarshalType) collapsed into a single errCodecType with the
direction kept in the format string.

Tests: dropped the per-call /* Field N, wire type 2, length M */
narration, regrouped the basic EncodeBytesField cases into a
table-driven subtest, and replaced a "12017800"[:6] slicing hack
with the literal hex value.

Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
Plaintext h2c was the only transport before; many real gRPC services
run TLS on 443 with ALPN h2 negotiation. Add a ssl boolean at the end
of Invoke's signature, matching the framework's HTTP helper convention
where SSL is wired through conf.SSL. The TLS path uses
InsecureSkipVerify since exploit targets routinely use self-signed or
expired certs.

Caller side:

    grpc.Invoke(conf.Rhost, conf.Rport, method, body, 5, conf.SSL)

Internal transportCreds helper centralises the credential choice so
the Invoke body stays one screen.

Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
Invoke covered the unary fast path; everything else (server- /
client- / bidi-streaming, reflection, multi-RPC on one conn) was off
limits because the conn was internal. Surface Dial as a public entry
point that returns the configured *grpc.ClientConn so callers can
drive grpc.ClientStream directly when they need streaming or to
amortise dial cost across calls. Invoke now uses Dial under the hood
to keep its body short.

Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
CodeQL flagged InsecureSkipVerify on transportCreds. The pattern is
intentional and matches protocol/httphelper.go which has the same
alert dismissed for the same reason: exploit modules have no control
over the cert validity or TLS version on the remote target. Add
MinVersion: tls.VersionSSL30 to match the http helper exactly and
update the comment so the rationale lives next to the code.

Repo maintainers will dismiss the new CodeQL alert as they did for
httphelper's identical instances.

Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
…ork log level

Signed-off-by: Valentin Lobstein <281638514+vlobstein-vc@users.noreply.github.com>
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.

5 participants