Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/linux/gather/enum_containers.rb
Views: 11702
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File78def initialize(info = {})9super(10update_info(11info,12'Name' => 'Linux Container Enumeration',13'Description' => %q{14This module attempts to enumerate containers on the target machine and optionally run a command on each active container found.15Currently it supports Docker, LXC and RKT.16},17'License' => MSF_LICENSE,18'Author' => ['stealthcopter'],19'Platform' => ['linux'],20'SessionTypes' => ['shell', 'meterpreter'],21'Notes' => {22'Stability' => [CRASH_SAFE],23'SideEffects' => [IOC_IN_LOGS],24'Reliability' => []25}26)27)28register_options(29[30OptString.new('CMD', [false, 'Optional command to run on each running container', ''])31]32)33end3435def cmd36datastore['CMD']37end3839# Check if a container program is installed and usable by current user40def runnable(container_type)41case container_type42when 'docker'43command = 'docker >/dev/null 2>&1 && echo true'44when 'lxc'45command = 'lxc >/dev/null 2>&1 && echo true'46when 'rkt'47# Apparently rkt doesn't play nice with 2>&1 for most commands, though `rkt help`48# seems to be fine so this is why its used here vs just 'rkt'49command = 'rkt help >/dev/null 2>&1 && echo true'50else51print_error("Invalid container type #{container_type}")52return false53end54cmd_exec(command) =~ /true$/55end5657# Count the number of currently running containers58def count_containers(container_type, count_inactive: true)59case container_type60when 'docker'61command = if count_inactive62'docker container ls --format "{{.Names}}" | wc -l'63else64'docker container ls -a --format "{{.Names}}" | wc -l'65end66when 'lxc'67command = if count_inactive68'lxc list -c n --format csv | wc -l'69else70'lxc list -c n,s --format csv | grep ,RUNNING | wc -l'71end72when 'rkt'73command = if count_inactive74'rkt list | tail -n +2 | wc -l'75else76'rkt list | tail -n +2 | grep running | wc -l'77end78else79print_error("Invalid container type '#{container_type}'")80return 081end8283result = cmd_exec(command)84if result =~ /denied/85print_error("Was unable to enumerate the number of #{container_type} containers due to a lack of permissions!")86return 087else88result.to_i89end90end9192# List containers93def list_containers(container_type)94case container_type95when 'docker'96result = cmd_exec('docker container ls -a')97when 'lxc'98# LXC does some awful table formatting, lets try and fix it to be more uniform99result = cmd_exec('lxc list').each_line.reject { |st| st =~ /^\+--/ }.map.with_index.map do |s, i|100if i == 0101s.split('| ').map { |t| t.strip.ljust(t.size, ' ').gsub(/\|/, '') }.join + "\n"102else103s.gsub(/\| /, '').gsub(/\|/, '')104end105end.join.strip106when 'rkt'107result = cmd_exec('rkt list')108else109print_error("Invalid container type '#{container_type}'")110return nil111end112result113end114115# List running containers identifiers116def list_running_containers_id(container_type)117case container_type118when 'docker'119command = 'docker container ls --format "{{.Names}}"'120when 'lxc'121command = 'lxc list -c n,s --format csv 2>/dev/null | grep ,RUNNING|cut -d, -f1'122when 'rkt'123command = 'rkt list | tail -n +2 | cut -f1'124else125print_error("Invalid container type '#{container_type}'")126return nil127end128cmd_exec(command).each_line.map(&:strip)129end130131# Execute a command on a container132def container_execute(container_type, container_identifier, command)133case container_type134when 'docker'135command = "docker exec '#{container_identifier}' #{command}"136when 'lxc'137command = "lxc exec '#{container_identifier}' -- #{command}"138when 'rkt'139print_error("RKT containers do not support command execution\nUse the command \"rkt enter '#{container_identifier}'\" to manually enumerate this container")140return nil141else142print_error("Invalid container type '#{container_type}'")143return nil144end145vprint_status("Running #{command}")146cmd_exec(command)147end148149# Run Method for when run command is issued150def run151platforms = %w[docker lxc rkt].select { |p| runnable(p) }152153if platforms.empty?154print_error('No container software appears to be installed or runnable by the current user')155return156end157158platforms.each do |platform|159print_good("#{platform} was found on the system!")160num_containers = count_containers(platform, count_inactive: false)161162if num_containers == 0163print_error("No active or inactive containers were found for #{platform}\n")164else165num_running_containers = count_containers(platform, count_inactive: true)166print_good("#{platform}: #{num_running_containers} Running Containers / #{num_containers} Total")167end168169next unless num_containers > 0170171containers = list_containers(platform)172next if containers.nil?173174# Using print so not to mess up table formatting175print_line(containers.to_s)176177p = store_loot("host.#{platform}_containers", 'text/plain', session, containers, "#{platform}_containers.txt", "#{platform} Containers")178print_good("Results stored in: #{p}\n")179180next if cmd.blank?181182running_container_ids = list_running_containers_id(platform)183next if running_container_ids.nil?184185running_container_ids.each do |container_id|186print_status("Executing command on #{platform} container #{container_id}")187command_result = container_execute(platform, container_id, cmd)188next if command_result.nil?189190print_good(command_result)191p = store_loot("host.#{platform}_command_results", 'text/plain', session, command_result, "#{platform}_containers_command_results.txt", "#{platform} Containers Command Results")192print_good("Command execution results stored in: #{p}\n")193end194end195end196end197198199