1
0
mirror of https://github.com/calebstewart/pwncat.git synced 2024-12-02 21:34:15 +01:00
pwncat/docs/source/api/commandparser.rst
Caleb Stewart 14098a32a3 Changed pwncat arguments, added connect command
New connect scheme. Also added ability to abuse previous
persistence methods to gain another shell on the same
host without another reverse or bind shell (currently
only implemented for authorized_keys persistence, but
is abstracted for any persistence method).
2020-05-21 22:20:49 -04:00

120 lines
5.3 KiB
ReStructuredText

Command Parser
==============
The local ``pwncat`` prompt and scripting configuration language are powered by the ``CommandParser``
class which is responsible for parsing lines of text, extracting arguments, and dispatching them
to the appropriate command.
Commands are loaded automatically through the ``pkgutils`` module in Python from the ``pwncat/commands``
directory. Every Python file from this directory is loaded as a module and checked for a ``Command``
attribute. This attribute must be a class which inherits from the ``pwncat.commands.base.CommandDefinition``
class. This class defines the structure of a command and allows the ``CommandParser`` to intelligently
create ``argparse`` objects, syntax highlighting lexers, and ``prompt_toolkit`` completers for your
commands.
To create a new command, simply create a python file under the ``pwncat/commands`` directory. The name
can be anything that conforms to python module naming standards. As an example, the ``sysinfo`` command
is fairly straightforward:
.. code-block:: python
from colorama import Fore
from pwncat.commands.base import CommandDefinition, Complete, parameter
import pwncat
class Command(CommandDefinition):
"""
Display remote system information including host ID, IP address,
architecture, kernel version, distribution and init system. This
command also provides the capability to view installed services
if the init system is supported by ``pwncat``.
"""
PROG = "sysinfo"
ARGS = {
"--services,-s": parameter(
Complete.NONE, action="store_true", help="List all services and their state"
)
}
def run(self, args):
if args.services:
for service in pwncat.victim.services:
if service.running:
print(
f"{Fore.GREEN}{service.name}{Fore.RESET} - {service.description}"
)
else:
print(
f"{Fore.RED}{service.name}{Fore.RESET} - {service.description}"
)
else:
print(f"Host ID: {Fore.CYAN}{pwncat.victim.host.hash}{Fore.RESET}")
print(
f"Remote Address: {Fore.GREEN}{pwncat.victim.client.getpeername()}{Fore.RESET}"
)
print(f"Architecture: {Fore.RED}{pwncat.victim.host.arch}{Fore.RESET}")
print(f"Kernel Version: {Fore.RED}{pwncat.victim.host.kernel}{Fore.RESET}")
print(f"Distribution: {Fore.RED}{pwncat.victim.host.distro}{Fore.RESET}")
print(f"Init System: {Fore.BLUE}{pwncat.victim.host.init}{Fore.RESET}")
This is a simple command that will print system information from the host database and provide
the capability to view installed services, provided the init system is supported. This command also shows a
basic example of interacting with the remote victim. The ``pwncat.victim`` object allows you to
interact abstractly with the currently connected victim. The ``LOCAL`` property tells the ``CommandParser``
whether this command operates only on local resources. If set to true, the command will be allowed
to run prior to a connected victim. In this case, we interact directly with the victim, and therefore
set the ``LOCAL`` property to false.
Command Arguments
-----------------
Argument parsing is achieved using the python built-in module ``argparse``. The parser is automatically
created based on the ``ARGS``, and ``DEFAULTS`` dictionaries defined in your ``Command`` class.
``DEFAULTS`` is a dictionary mapping argument names to default values. This is passed directly to
the ``argparse.ArgumentParser.set_defaults`` method. This allows you to set defaults for values which
can't be set in the argument definition (such as values referenced in multiple arguments with
`dest` parameter).
The ``ARGS`` property is a dictionary which matches argument names to the ``parameter`` objects.
The key for this dictionary is a string representing the a comma-separated list of parameter
names (e.g. "--param,-p"). The values in this dictionary are built from the ``parameter`` method
imported above:
.. code-block:: python
def parameter(complete, token=Name.Label, *args, **kwargs):
The first parameter is one of the ``pwncat.commands.base.Complete`` enumeration items. Which includes
things like ``Complete.REMOTE_FILE``, ``Complete.LOCAL_FILE``, ``Complete.CHOICES`` and ``Complete.NONE``.
For parameters with no argument ("switches"), this should be ``Complete.NONE``. This controls how
the CommandParser tab-completes your command at the local prompt.
The second parameter is the Pygments token which this option should be highlighted with. Normally,
you can leave this as default, but you may change it if you like. The remaining arguments are passed
directly to ``argparse.ArgumentParser.add_argument``.
Command Helpers
---------------
.. autoclass:: pwncat.commands.base.Complete
:members:
.. autofunction:: pwncat.commands.base.parameter
.. autoclass:: pwncat.commands.base.StoreConstOnce
.. autofunction:: pwncat.commands.base.StoreForAction
.. autofunction:: pwncat.commands.base.RemoteFileType
CommandDefinition Object
------------------------
.. autoclass:: pwncat.commands.base.CommandDefinition
:members: