rapid7 / metasploit-framework

Metasploit Framework
https://www.metasploit.com/
Other
32.92k stars 13.72k forks source link

New process launch API #19108

Open smashery opened 4 weeks ago

smashery commented 4 weeks ago

This creates a new API, create_process, which allows the creation of processes from an array of args, rather than from a commandline string that needs to go through a subshell. This places the escaping logic in one place, and lets module developers create more robust code.

Verification

You'll need to pull in mettle, as well as the various metasploit-payloads (php, py, c, java)

https://github.com/rapid7/metasploit-payloads/pull/701 https://github.com/rapid7/mettle/pull/258

Test for each of the following:

For each of the above:

You can observe process launches (to check for the presence/absence of subshells) using:

sudo bpftrace -e 'tracepoint:syscalls:sys_enter_exec*{ printf("pid: %d, comm: %s, args: ", pid, comm); join(args->argv); }'

Tests

Windows, new Metasploit, old Meterp

>> print_line(create_process('showargs.exe'))

>> print_line(create_process("%showargs'.exe", args:['', '', '']))

>> print_line(create_process('showargs.exe', args:['basic','args']))
basic
args
>> print_line(create_process('showargs.exe', args:['with space']))
with space
>> print_line(create_process('show args.exe', args:['with space']))
with space
>> print_line(create_process("%showargs'.exe", args:['with space']))
with space
>> print_line(create_process('showargs.exe', args:['%PATH%']))
%PATH%

>> print_line(cmd_exec('"show args.exe"', 'test words "with space"'))
test
words
with space
>> print_line(cmd_exec('showargs.exe', 'test words'))
test
words
>> print_line(cmd_exec('showargs.exe', '%PATH%'))
%PATH%

Windows, new Metasploit, new Meterp

>> print_line(create_process('showargs.exe'))

>> print_line(create_process('showargs.exe', args:['basic','args']))
basic
args
>> print_line(create_process('showargs.exe', args:['with space']))
with space
>> print_line(create_process('show args.exe', args:['with space']))
with space
>> print_line(create_process("%showargs'.exe", args:['with space']))
with space
>> print_line(create_process('showargs.exe', args:['%PATH%']))
%PATH%

>> print_line(cmd_exec('"show args.exe"', 'test words "with space"'))
test
words
with space
>> print_line(cmd_exec('showargs.exe', 'test words'))
test
words
>> print_line(cmd_exec('showargs.exe', '%PATH%'))
%PATH%

Linux, new Metasploit, old Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/system/bin:/system/sbin:/system/xbin

Linux, new Metasploit, new Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/system/bin:/system/sbin:/system/xbin

Java, new Metasploit, old Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin

Java, new Metasploit, new Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin

Python, new Metasploit, old Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin

Python, new Metasploit, new Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin

PHP, new Metasploit, old Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin

PHP, new Metasploit, new Meterp

>> print_line(create_process('./run', args:[]))
Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin

PHP < 7.4, new Metasploit, new Meterp

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['a','','b','','c']))
./run
a

b

c
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/home/smash/.local/bin:/home/smash/.rbenv/shims:/home/smash/.local/bin:/home/smash/.rbenv/shims:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/tools:/opt/apache-maven-3.5.4/bin:/tools:/opt/apache-maven-3.5.4/bin

Windows, Command shell

>> print_line(create_process('showargs.exe'))

>> print_line(create_process("%showargs'.exe", args:['', '', '']))

>> print_line(create_process('showargs.exe', args:['basic','args']))
basic
args
>> print_line(create_process('showargs.exe', args:['with space']))
with space
>> print_line(create_process('show args.exe', args:['with space']))
with space
>> print_line(create_process("%showargs'.exe", args:['with space']))
with space
>> print_line(create_process('showargs.exe', args:['%PATH%']))
%PATH%
>>
>> print_line(cmd_exec('"show args.exe"', 'test words "with space"'))
test
words
with space
>> print_line(cmd_exec('showargs.exe', 'test words'))
test
words
>> print_line(cmd_exec('showargs.exe', '%PATH%'))
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;

Linux, Command shell

>> print_line(create_process('./run', args:[]))

Usage: ./run [argument1] [argument2] ... [argumentN]
>> print_line(create_process('./run', args:['basic','args']))
./run
basic
args
>> print_line(create_process('./run', args:['with spaces']))
./run
with spaces
>> print_line(create_process('./run', args:['$PATH']))
./run
$PATH
>> print_line(create_process('./run', args:["it's $PATH"]))
./run
it's $PATH
>> print_line(create_process('./run', args:['~!@#$%^&*(){`1234567890[]",.\'<>']))
./run
~!@#$%^&*(){`1234567890[]",.'<>
>> print_line(create_process('./run', args:["run&echo"]))
./run
run&echo
>> print_line(create_process('./run', args:["run&echo;test"]))
./run
run&echo;test
>> print_line(create_process('./run file', args:["arg1"]))
./run file
arg1
>> print_line(create_process('./~!@#$%^&*(){}', args:["arg1"]))
./~!@#$%^&*(){}
arg1
>> print_line(cmd_exec('./run', 'something here'))
./run
something
here
>> print_line(cmd_exec('./run', '$PATH'))
./run
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

PowerShell

>> print_line(create_process('.\\showargs.exe'))

>> print_line(create_process(".\\%showargs'.exe", args:['', '', '']))

>> print_line(create_process('.\\showargs.exe', args:['basic','args']))
basic
args
>> print_line(create_process('.\\showargs.exe', args:['with space']))
with space
>> print_line(create_process('.\\show args.exe', args:['with space']))
with space
>> print_line(create_process(".\\%showargs'.exe", args:['with space']))
with space
>> print_line(create_process('.\\showargs.exe', args:['$env:path']))
$env:path

>> print_line(cmd_exec('& ".\show args.exe"', 'test words "with space"'))
test
words
with space
>> print_line(cmd_exec('.\showargs.exe', 'test words'))
test
words
>> print_line(cmd_exec('.\showargs.exe', '$env:PATH'))
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;
adfoster-r7 commented 3 weeks ago

So we actually have a set of integration tests now that run through the meterpreter test suite on multiple different host environments, i.e. windows/ubuntu/osx, so potentially we could update these tests:

https://github.com/rapid7/metasploit-framework/blob/b607c70611b2427ff8cb277acbcb4c8233300f7d/test/modules/post/test/cmd_exec.rb

And it should automatically run through all of the meterpreters on different runtimes - which would give more confidence that things will work beyond just the unit tests that have been added