Privilege Escalation Modules

Privilege Escalation is implemented using modules. Each privilege escalation module is a sub-class of the EscalateModule class. The escalate module’s primary purpose is to enumerate possible escalation techniques. Techniques are objects which implement specific escalation capabilities and can be put together to form a fully-functional code execution primitive. Each technique may implement file read, file write or shell/exec capabilities. The base escalate module will collect all available techniques and attempt to use them together to achieve the requested action.

Running an escalation module with no arguments simply returns an EscalateResult which wraps a list of techniques. This result can be used to attempt file read, file write or execution as the requested user. All escalate modules accept three boolean arguments which indicate it should attempt one of read, write or exec. If any of these arguments are true, the requested action will be attempted instead of returning the result.

When implementing an escalate module, any errors should be signaled by the EscalateError exception.

Automatic Privilege Escalation

The escalate.auto module (aliased to simply escalate) will attempt to use any available module to escalate to the desired user. Further, it will recursively attempt escalation through as many users as needed to find a path to the requested user. This module simply aggregates the results from all available escalation modules and then attempts the escalation with the available techniques. If direct escalation to the requested user is not possible, it will attempt escalation to eacho ther user available and recurse to find a path to the requested user.

This is the most common way to attempt privilege escalation, as it can quickly attempt multiple different escalation options through multiple users. However, if you know a likely vulnerability, you can execute an individual escalate module directly in the same way.

Any extra arguments passed to the escalate.auto module will be passed on to any module it executes. This allows modules with custom arguments to be included in the automatic escalation attempts. However, this can be problematic. If two modules have arguments with the same name and different required values, at least one of them will fail to run. As a result, you cannot count on escalate.auto to be able to attempt any module which requires custom arguments.

As with standard escalate modules, escalate.auto will by default simply return the escalate result containing all techniques it found. These techniques will span multiple modules. This makes it easy to quickly enumerate all known possible escalation paths.

Module Structure

Escalate modules at their core are a sub-class of BaseModule. As such, you can define custom arguments and platform requirements. If custom arguments are required, you must include the EscalateModule arguments in your definition as noted in the class reference below.

class Module(EscalateModule):
    """ Simple example module that does nothing. """

    # Define supported platform(s)
    PLATFORM = Platform.LINUX
    # Default priority is 100. Higher value = lower priority. Must be > 0.
    PRIORITY = 100
    # Custom arguments. Remove this entirely if unneeded.
    ARGUMENTS = {
        **EscalateModule.ARGUMENTS,
        "custom_arg": Argument(str),
    }

    def enumerate(self, user, custom_arg):
        """ Implement a generator of Technique's """

        # Technique implementation is what does the work of an
        # escalate method. You should implement a technique class
        # specific to your module.
        # yield YourCustomTechnique(Capability.SHELL, "root", self)

    def human_name(self, tech: YourCustomTechnique):
        """ Create a pretty-printed representation of this module/technique """
        return "a really cool custom technique"

Implementing A Technique

Techniques are the heart and soul of an escalation module. pwncat uses techniques with different capabilities together to attempt to perform various actions. For example, if you request file read, pwncat may use a exec technique to gain a shell, and then read the file normally. Alternatively, attempting exec may require pwncat to use read and write techniques to escalate privileges.

An individual technique is identified by a Capability, a user name, and a module. The capabilities are taken from pwncat.gtfobins and include things such as file read, file write or shell. There are associated methods within a technique to execute these various capabilities and these are the methods you must implement depending on the techniques supported capabilities. The module is simply your module that created the technique. The user represents the name of the user which this technique allows access as. For example, for a SETUID binary, the user would be the owner of the binary itself.

Here is an example of a skeleton technique class:

# This decorator is not required, but if your technique may
# result in a EUID vs RUID mismatch, use this decorator to
# correct this issue automatically if needed.
@euid_fix
class YourCustomTechnique(Technique):
    """ Implement the various capabilities your module provides """

    def exec(self, binary: str) -> str:
        """ Called for techniques which provide Capability.SHELL.
        Execute the specified shell the other user, and return a
        string which will exit the shell and return to the current
        state. """

    def write(self, filepath: str, data: bytes):
        """ Called for techniques which provide Capability.WRITE.
        Write ``data`` to the specified file as the other user. """

    def read(self, filepath: str):
        """ Called for techniques which provide Capability.READ.
        Open the remote file for reading and return a file-like
        object which yields it's contents. """

Utility Classes and Functions

pwncat.modules.escalate.euid_fix(technique_class)

Decorator for Technique classes which may end up with a RUID/EUID mismatch. This will check the resulting UID after to see if the change was affective and attempt to fix it. If the fix fails, then the resulting action is undone and an EscalateError is raised.

class pwncat.modules.escalate.GTFOTechnique(target_user: str, module: pwncat.modules.escalate.EscalateModule, method: pwncat.gtfobins.MethodWrapper, **kwargs)

A technique which is based on a GTFO binary capability. This is mainly used for sudo and setuid techniques, but could theoretically be used for other techniques.

Parameters:
  • target_user (str) – The user which this techniques allows access as
  • module (EscalateModule) – The module which generated this technique
  • method (pwncat.gtfobins.MethodWrapper) – The GTFObins MethodWrapper
  • kwargs – Arguments passed to the gtfobins build method.
class pwncat.modules.escalate.FileContentsResult(filepath: str, pipe: pwncat.file.RemoteBinaryPipe, data: bytes = None)

Result which contains the contents of a file. This is the result returned from an EscalateModule when the read parameter is true. It allows for the file to be used as a stream programmatically, and also nicely formats the file data if run from the prompt.

category
Meta private:
data = None

The data that was read from the file. It is buffered here to allow multiple reads when the data is streamed back from the remote host. It should not be accessed directly, instead use the stream property to access a stream of data regardless of the state of the underlying pipe object.

description
Meta private:
filepath = None

Path to the file which this data came from

pipe = None

Until it is read, this is a stream which will return the file data from the victim. It should not be used directly, and instead should be accessed through the stream property.

stream

Access the file data. This should be used to access the data. The pipe and data properties should not be used. This is a file-like object which contains the raw file data.

title
Meta private:
class pwncat.modules.escalate.EscalateChain(user: str, chain: List[Tuple[pwncat.modules.escalate.Technique, str]])

Chain of techniques used to escalate. When escalating through multiple users, this allows pwncat to easily track the different techniques and users that were traversed. When exec is used, this object is returned instead of the EscalateResult object.

It has methods to unwrap the escalations to return to the original user if needed.

add(technique: pwncat.modules.escalate.Technique, exit_cmd: str)

Add a link in this chain.

category
Meta private:
chain = None

Chain of techniques used to escalate

description
Meta private:
extend(chain: pwncat.modules.escalate.EscalateChain)

Extend this chain with another chain. The two chains are concatenated.

pop()

Exit and remove the last link in the chain

title
Meta private:
unwrap()

Exit each shell in the chain with the provided exit script. This should return the state of the remote shell to prior to escalation.

user = None

Initial user before escalation

class pwncat.modules.escalate.EscalateResult(techniques: Dict[str, List[pwncat.modules.escalate.Technique]])

The result of running an escalate module. This object contains all the enumerated techniques and provides an abstract way to employ the techniques to attempt privilege escalation. This is the meat and bones of the automatic escalation logic, and shouldn’t generally need to be modified. It will put together basic techniques into a working primitive.

Parameters:techniques (Dict[str, List[Technique]]) – List of techniques that were enumerated
add(technique: pwncat.modules.escalate.Technique)

Add a new technique to this result object

category

EscalateResults are uncategorized

Meta private:
description

Description of these results (list of techniques)

Meta private:
exec(user: str, shell: str, progress)

Attempt to use all the techniques enumerated to execute a shell as the specified user.

Parameters:
  • user (str) – The user to execute a shell as
  • shell (str) – The shell to execute
  • progress – A rich Progress bar to update during escalation.
extend(result: pwncat.modules.escalate.EscalateResult)

Extend this result with another escalation enumeration result. This allows you to enumerate multiple modules and utilize all their techniques together to perform escalation.

read(user: str, filepath: str, progress, no_exec: bool = False)

Attempt to use all the techniques enumerated to read a file as the given user. This method returns a file-like object capable of reading the file.

Parameters:
  • user (str) – The user to read the file as
  • filepath (str) – Path to the file to read
  • progress – A rich Progress bar to update during escalation.
  • no_exec (bool) – When true, do not attempt exec to write the file. This is needed when recursing automatically, and should normally be left as false.
techniques = None

List of techniques available keyed by the user

title

The title of the section when displayed on the terminal

Meta private:
write(user: str, filepath: str, data: bytes, progress, no_exec: bool = False)

Attempt to use all the techniques enumerated to write to a file as the given user

Parameters:
  • user (str) – The user you would like to write a file as
  • filepath (str) – The file you would like to write to
  • data (bytes) – The data you would like to place in the file
  • progress – A rich Progress bar to update during escalation.
  • no_exec (bool) – When true, do not attempt exec to write the file. This is needed when recursing automatically, and should normally be left as false.

Technique Base Class

class pwncat.modules.escalate.Technique(caps: pwncat.gtfobins.Capability, user: str, module: pwncat.modules.escalate.EscalateModule)

Describes a technique possible through some module.

Modules should subclass this class in order to implement their techniques. Only the methods corresponding to the returned caps need be implemented.

caps = None

What capabilities this technique provides

exec(binary: str)

Execute a shell as the specified user.

Parameters:binary (str) – the shell to execute
Returns:A string which when sent over the socket exits this shell
Return type:str
module = None

The module which provides these capabilities

read(filepath: str)

Read the given file as the specified user

Parameters:filepath (str) – path to the target file
Returns:A file-like object representing the remote file
Return type:File-like
user = None

The user this provides access as

write(filepath: str, data: bytes)

Write the given data to the specified file as another user.

Parameters:
  • filepath (str) – path to the target file
  • data (bytes) – the data to write

Escalate Module Base Class

class pwncat.modules.escalate.EscalateModule

The base module for all escalation modules. This module is responsible for enumerating Technique objects which can be used to attempt various escalation actions.

With no arguments, a standard escalate module will return an EscalateResult object which contains all techniques enumerated and provides helper methods for programmatically performing escalation and combining results from multiple modules.

Alternatively, the exec, write, and read arguments can be used to have the module automatically attempt the respective operation basedo on the arguments passed.

PRIORITY = 100

The priority of this escalation module. Values <= 0 are reserved. Indicates the order in which techniques are executed when attempting escalation. Lower values execute first.

enumerate(**kwargs) → Generator[Technique, None, None]

Enumerate techniques for this module. Each technique must implement at least one capability, and all techniques will be used together to escalate privileges. Any custom arguments are passed to this method through keyword arguments. None of the default arguments are passed here.

human_name(tech: pwncat.modules.escalate.Technique)

Defines the human readable name/description of this vuln

run(user, exec, read, write, shell, path, data, **kwargs)

This method is not overriden by subclasses. Subclasses should should implement the enumerate method which yields techniques.

Running a module results in an EnumerateResult object which can be formatted by the default run command or used to execute various privilege escalation primitives utilizing the techniques enumerated.