Lucene search
K

GTP Echo Scanner

🗓️ 26 Apr 2019 01:55:19Reported by Daniel Mende, Spencer McIntyreType 
metasploit
 metasploit
🔗 www.rapid7.com👁 32 Views

GTP Echo Scanner sends UDP GTP echo requests to identify GPRS servers without SCTP suppor

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

class MetasploitModule < Msf::Auxiliary
  include Msf::Auxiliary::Report
  include Msf::Auxiliary::UDPScanner

  def initialize
    super(
      'Name'        => 'GTP Echo Scanner',
      'Description' => %q{
        This module sends UDP GTP (GTP-U) echo requests to the target RHOSTS and
        reports on which ones respond, thus identifying General Packet Radio
        Service (GPRS) servers. This module does not support scanning with SCTP.
      },
      'References'  =>
        [
          ['URL', 'https://insinuator.net/tag/gtp/'],
          ['URL', 'https://www.etsi.org/deliver/etsi_ts/129200_129299/129281/08.00.00_60/ts_129281v080000p.pdf']
        ],
      'Author'      =>
        [
          'Daniel Mende',    # original gtp-scan.py script
          'Spencer McIntyre' # metasploit module
        ],
      'License'     => MSF_LICENSE
    )

    register_options([
      OptEnum.new('VERSION', [ true, 'The GTP version to use', '1', ['1', '2'] ]),
      Opt::RPORT(2152)
    ])
  end

  class GTPv1 < BinData::Record
    endian  :big

    default_parameter version: 1
    default_parameter protocol_type: 1
    default_parameter has_next_extension_header: 0
    default_parameter has_sequence_number: 0
    default_parameter has_n_pdu_number: 0
    default_parameter message_type: 0
    default_parameter data: ""

    # header
    bit3   :version, :initial_value => :version
    bit1   :protocol_type, :initial_value => :protocol_type
    bit1   :reserved
    bit1   :has_next_extension_header, :initial_value => :has_next_extension_header
    bit1   :has_sequence_number, :initial_value => :has_sequence_number
    bit1   :has_n_pdu_number, :initial_value => :has_n_pdu_number
    uint8  :message_type, :initial_value => :message_type
    uint16 :len, :value => :calc_length
    uint32 :teid

    # body
    uint16  :sequence_number, onlyif: -> { has_sequence_number.nonzero? }
    uint8   :n_pdu_number, onlyif: -> { has_n_pdu_number.nonzero? }
    uint8   :next_extension_header_type, onlyif: -> { has_next_extension_header.nonzero? }
    string :data, :initial_value => :data, :read_length => :calc_length_read

    def calc_length
      length = data.length
      length += 2 if has_sequence_number.nonzero?
      length += 1 if has_n_pdu_number.nonzero?
      length += 1 if has_next_extension_header.nonzero?
      length
    end

    def calc_length_read
      length = len
      length -= 2 if has_sequence_number.nonzero?
      length -= 1 if has_n_pdu_number.nonzero?
      length -= 1 if has_next_extension_header.nonzero?
      length
    end
  end

  class GTPv1EchoRequest < GTPv1
    default_parameter has_sequence_number: 1
    default_parameter message_type: 1
  end

  class GTPv2 < BinData::Record
    endian  :big

    default_parameter version: 2
    default_parameter piggybacking: 0
    default_parameter message_priority: 0
    default_parameter message_type: 0
    default_parameter data: ""

    # header
    bit3   :version, :initial_value => :version
    bit1   :piggybacking, :initial_value => :piggybacking
    bit1   :has_teid
    bit1   :message_priority, :initial_value => :message_priority
    uint8  :message_type, :initial_value => :message_type
    uint16 :len, :value => :calc_length

    # body
    uint32 :teid, onlyif: -> { has_teid.nonzero? }
    uint24 :sequence_number
    uint8  :spare
    string :data, :initial_value => :data, :read_length => :calc_length_read

    def calc_length
      length = data.length + 4
      length += 4 if has_teid.nonzero?
      length
    end

    def calc_length_read
      length = len - 4
      length -= 4 if has_teid.nonzero?
      length
    end
  end

  class GTPv2EchoRequest < GTPv2
    default_parameter message_type: 1
  end

  def build_probe
    # the tunnel endpoint identifier (TEID) field must be 0 for echo requests
    # per the specification
    if datastore['VERSION'] == '1'
      @probe = GTPv1EchoRequest.new.to_binary_s
    else
      @probe = GTPv2EchoRequest.new.to_binary_s
    end
  end

  def scanner_postscan(batch)
    @results.each do |rhost, data|
      next unless data.length == 1
      data = data[0]

      if datastore['VERSION'] == '1'
        gtp = GTPv1
      else
        gtp = GTPv2
      end
      begin
        response = gtp.read(data)
      rescue EOFError
        next
      end

      if datastore['VERSION'] == '1'
        next unless response.version == 1
        next unless response.teid == 0
      else
        next unless response.version == 2
        next unless response.sequence_number == 0
      end

      peer = "#{rhost}:#{rport}"
      print_good("GTP v#{datastore['VERSION']} echo response received from: #{peer}")

      report_service(
        :host  => rhost,
        :proto => 'udp',
        :port  => rport,
        :name  => 'gtp'
      )
    end
  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