How to Map, Analyze, and Exploit Non-HTTP Attack Surfaces from Source Code

How to Map, Analyze, and Exploit Non-HTTP Attack Surfaces from Source Code

Ask ten security engineers to audit a piece of software and nine of them will start by looking for a web interface. That instinct is understandable — HTTP is well-documented, tooling is mature, and Burp Suite makes the workflow almost mechanical. But a huge amount of high-value attack surface never touches HTTP at all: custom RPC protocols, message queues, gRPC services, native IPC, database wire protocols, industrial control protocols, and countless proprietary binary formats. I want to lay out a repeatable methodology for finding and exploiting this kind of surface directly from source code, since — unlike black-box HTTP testing — this is fundamentally a code-reading discipline.

Why Non-HTTP Surface Gets Overlooked

There are a few structural reasons this surface is chronically under-tested:

  • Tooling gap. There’s no universal “Burp Suite for arbitrary binary protocols.” Every custom protocol needs at least a little custom tooling.
  • Documentation gap. Non-HTTP protocols are frequently undocumented or under-documented internal RPC mechanisms, so understanding them requires reading code rather than a spec.
  • Discoverability gap. A REST API shows up in browser dev tools. A gRPC service on a non-standard port, a Unix socket, or a custom TCP protocol on an obscure port doesn’t announce itself the same way.
  • Assumption of internal trust. Non-HTTP services are frequently assumed to be “internal only” or “trusted callers only,” which historically leads to weaker input validation — an assumption attackers exploit constantly during lateral movement.

The Methodology: From Source to Exploit

flowchart TD
    A[Identify Candidate Entry Points in Source] --> B[Classify Transport & Protocol Type]
    B --> C[Trace Data Flow: Source to Sink]
    C --> D[Identify Trust Boundaries Crossed]
    D --> E[Build Minimal Interaction Tooling]
    E --> F[Confirm Vulnerability with Proof-of-Concept]
    F --> G[Assess Impact & Exploitability]

Step 1: Identify Candidate Entry Points

Start by grepping for the primitives that indicate a listener exists, regardless of language:

Language/FrameworkGrep Targets
C/C++socket(, bind(, listen(, accept(, recvfrom(
Pythonsocket.socket(, asyncio.start_server(, grpc.server(
JavaServerSocket, Netty ChannelInitializer, @GrpcService
Gonet.Listen(, net.ListenUDP(, grpc.NewServer(
RustTcpListener::bind(, tonic::transport::Server
Node.jsnet.createServer(, dgram.createSocket(

Every hit is a candidate entry point worth cataloging: what address/port/path does it bind to, what’s the protocol, and is it reachable from outside the process’s immediate trust zone?

Step 2: Classify the Transport and Protocol

Once you’ve found a listener, figure out what’s actually running on it. This dictates your entire testing approach:

  • Well-known binary protocol (gRPC, Thrift, MQTT, AMQP, Redis protocol, Memcached protocol) — existing tooling and client libraries exist; leverage them.
  • Custom binary protocol — you’ll need to reverse-engineer the framing and message format directly from the parsing code.
  • Text-based but non-HTTP (SMTP, custom line-based protocols) — often easier to interact with manually via nc/socat, but don’t assume “text” means “safe.”

Step 3: Trace Data Flow — Source to Sink

This is the core of source-code-driven vulnerability research, and it applies identically whether the entry point is HTTP or not. Starting from the point where bytes come off the socket (the source), trace every transformation the data undergoes until it reaches a sink — a database query, a file write, a command execution, a memory allocation, a deserialization call.

# Illustrative example: tracing a custom TCP protocol handler in Python
def handle_connection(sock):
    header = sock.recv(8)                      # SOURCE: untrusted bytes
    msg_type, length = struct.unpack('!II', header)
    payload = sock.recv(length)                 # length attacker-controlled -- Q: bounded?
    if msg_type == MSG_TYPE_QUERY:
        query = payload.decode('utf-8')
        result = db.execute(f"SELECT * FROM items WHERE name='{query}'")  # SINK: SQLi
    elif msg_type == MSG_TYPE_LOAD:
        obj = pickle.loads(payload)              # SINK: insecure deserialization

This tiny example contains two classic sink types that have nothing to do with HTTP at all: a SQL injection reachable only through a custom binary protocol, and an insecure deserialization sink (pickle.loads on attacker-controlled bytes is a well-known remote code execution primitive in Python). Neither would show up in a web-focused scan, because there’s no HTTP request involved anywhere.

Step 4: Identify Trust Boundaries

Ask, for every entry point: who is expected to connect here, and is that expectation actually enforced? A gRPC service listening on an internal Kubernetes ClusterIP is “internal” only until something else in the cluster is compromised, or the service is accidentally exposed via a misconfigured LoadBalancer type, or a debug port gets forwarded during troubleshooting and forgotten.

Step 5: Build Minimal Interaction Tooling

Since there’s rarely a point-and-click tool for a custom protocol, you build the smallest thing that lets you send and receive crafted messages. For most binary protocols, Python’s struct module plus raw sockets gets you 90% of the way:

import socket, struct

def send_msg(host, port, msg_type, payload: bytes):
    s = socket.create_connection((host, port))
    header = struct.pack('!II', msg_type, len(payload))
    s.sendall(header + payload)
    return s.recv(4096)

# Reproduce the SQLi sink identified above
resp = send_msg('target', 9090, 1, b"' OR '1'='1")
print(resp)

For gRPC specifically, since it’s Protocol Buffers over HTTP/2, tools like grpcurl or ghz let you interact with services once you have (or can extract, via reflection or decompiling client code) the .proto definitions.

Common Non-HTTP Protocols and Their Known Risk Patterns

ProtocolTransportCommon Vulnerability Classes
gRPC / ProtobufHTTP/2Deserialization issues, missing auth on reflection service, resource exhaustion
Redis protocol (RESP)TCPUnauthenticated access leading to RCE (module loading, CONFIG SET abuse)
Memcached protocolUDP/TCPAmplification DDoS, unauthenticated data exposure
AMQP/MQTT (message queues)TCPBroker misconfig, missing ACLs, topic/queue injection
Java RMITCPInsecure deserialization leading to RCE
SMB/CIFSTCPAuth relay attacks, protocol downgrade
Custom TLV binary protocolsTCP/UDPBuffer overflows, integer overflow in length fields, missing auth
Database wire protocols (MySQL, PostgreSQL)TCPAuth bypass, injection when application constructs raw protocol messages

Real-World Examples

  • Unauthenticated Redis instances: for years, misconfigured Redis servers exposed to the internet without authentication have been a favorite target — attackers use the CONFIG SET command to write an SSH authorized key or a webshell to disk, turning a “just a cache” service into remote code execution, entirely through Redis’s own native protocol rather than HTTP.
  • Java deserialization RCE via RMI/JMX (the broader “Ysoserial” class of vulnerabilities): Java RMI and JMX endpoints that accept serialized objects over their native protocol have repeatedly been a source of unauthenticated RCE, because deserialization itself can trigger arbitrary code execution through “gadget chains” in commonly-used libraries on the classpath.
  • Memcached DDoS amplification (2018): attackers abused internet-exposed Memcached servers’ UDP protocol, sending small spoofed requests that triggered enormous responses back at a victim, resulting in some of the largest DDoS attacks recorded at the time. A pure protocol/configuration issue with no HTTP involvement whatsoever.

Building an Attack Surface Inventory from Source

A practical workflow for a codebase-wide review:

  1. Grep for listener primitives across every language/framework in the repo (see table above).
  2. For each listener, record: bind address, port/path, protocol type, authentication mechanism (if any), and the handler function that processes incoming data.
  3. For each handler, trace to sinks: database calls, filesystem operations, deserialization calls, subprocess execution, memory allocation from attacker-controlled sizes.
  4. Cross-reference with deployment configuration (Kubernetes manifests, Docker Compose, systemd units, firewall rules) to determine actual reachability — a listener bound to 0.0.0.0 inside a container might still only be reachable within a private VPC, or might be exposed via a misconfigured ingress.
  5. Prioritize by reachability × sink severity: an unauthenticated, internet-reachable listener with a deserialization sink is a critical finding; an internal-only listener with a minor information disclosure sink is a much lower priority.

Defensive Best Practices

  • Require authentication on every listener, regardless of “internal” status. Network segmentation is a defense-in-depth layer, not a substitute for authentication.
  • Never deserialize untrusted data using formats capable of arbitrary code execution (Python pickle, Java native serialization, PHP unserialize) without strict allow-listing; prefer schema-constrained formats like Protocol Buffers or JSON with strict schema validation.
  • Validate length and type fields before they influence allocation or control flow, exactly as with HTTP-adjacent parsing.
  • Inventory every listener as part of your SDLC, not just HTTP endpoints — treat “what does this service bind to on startup” as a standard code review question.
  • Apply the same rate limiting and input validation discipline to non-HTTP services that’s now standard practice for web APIs; it’s frequently missing precisely because these services were never expected to face untrusted input.

Frequently Asked Questions

Why don’t standard web vulnerability scanners catch these issues? Web scanners are built around the HTTP request/response model — they crawl links, fuzz parameters, and analyze responses. A custom binary protocol on a TCP port has none of that structure, so scanners simply never send it anything meaningful, and often don’t even recognize it as a target.

Is reverse engineering required if I have source code access? Not in the same sense as black-box reverse engineering, but you still need to reconstruct the wire format by reading the parsing code — effectively “reverse engineering the protocol from its own implementation,” which is faster and more reliable than black-box protocol reversing but requires the same systematic mindset.

How do I prioritize which non-HTTP services to review first in a large codebase? Start with anything reachable from outside the immediate trust zone (internet-facing, or reachable from a less-trusted network segment/tenant), then anything handling data from a source you don’t fully control (partner integrations, IoT devices, other microservices), then work inward.

Are gRPC services inherently safer than raw custom protocols because they use Protocol Buffers? Protobuf’s schema-driven serialization eliminates a lot of manual parsing bugs compared to hand-rolled binary formats, but it doesn’t provide authentication, authorization, or protection against logic bugs in the service implementation — those still have to be built and reviewed separately.

References

Summary and Recommendations

Non-HTTP attack surface is often the highest-value, least-tested part of a system precisely because it’s harder to find and harder to tool against. The methodology doesn’t fundamentally differ from web application security — find the entry points, trace source to sink, identify trust boundaries — but the execution requires reading source code rather than relying on off-the-shelf scanners, and building small, purpose-built tools to interact with whatever protocol you find. If your security program only tests what shows up in a browser, you’re systematically missing the services most likely to be genuinely under-reviewed.

Total
2
Shares

Leave a Reply

Previous Post
The Expanding Attack Surface of Modern Software: Risks and Exploitation Vectors

The Expanding Attack Surface of Modern Software: Risks and Exploitation Vectors

Next Post
Network Protocol Security: Decoding Data Structures and Procedures

Network Protocol Security: Decoding Data Structures and Procedures

Related Posts