From b41cfd9aa97c7ca2e02d585c3769e3afa5ee359d Mon Sep 17 00:00:00 2001 From: Caleb Stewart Date: Sat, 23 May 2020 15:35:46 -0400 Subject: [PATCH] Started documenting all pwncat prompt commands --- docs/source/commands/alias.rst | 15 ++++ docs/source/commands/back.rst | 7 ++ docs/source/commands/bind.rst | 41 +++++++++++ docs/source/commands/bruteforce.rst | 35 ++++++++++ docs/source/commands/busybox.rst | 79 +++++++++++++++++++++ docs/source/commands/connect.rst | 104 ++++++++++++++++++++++++++++ docs/source/commands/index.rst | 12 ++++ docs/source/index.rst | 1 + pwncat/commands/busybox.py | 6 +- pwncat/commands/help.py | 7 +- pwncat/remote/victim.py | 7 -- 11 files changed, 304 insertions(+), 10 deletions(-) create mode 100644 docs/source/commands/alias.rst create mode 100644 docs/source/commands/back.rst create mode 100644 docs/source/commands/bind.rst create mode 100644 docs/source/commands/bruteforce.rst create mode 100644 docs/source/commands/busybox.rst create mode 100644 docs/source/commands/connect.rst create mode 100644 docs/source/commands/index.rst diff --git a/docs/source/commands/alias.rst b/docs/source/commands/alias.rst new file mode 100644 index 0000000..b2ed23c --- /dev/null +++ b/docs/source/commands/alias.rst @@ -0,0 +1,15 @@ +Alias +===== + +``alias`` is a simple command. It provides the ability to rename any built-in command. Unlike aliases in common shells, +this does not allow you to provide default parameters to commands. Instead, it simply creates an alternative name. + +You can specify a new alias simply by providing the new name followed by the new name. For example, to alias "download" +to "down", you could do this in your configuration script: + +.. code-block:: bash + + alias down "download" + +``alias`` takes as it's second argument a string. Passing anything else (e.g. a code block) will not produce the desired +results. The command you are aliasing must exist and be a standard command (no aliases to other aliases are supported). \ No newline at end of file diff --git a/docs/source/commands/back.rst b/docs/source/commands/back.rst new file mode 100644 index 0000000..3910bdd --- /dev/null +++ b/docs/source/commands/back.rst @@ -0,0 +1,7 @@ +Back +==== + +The back command is used to exit the local ``pwncat`` prompt and return to your remote shell. It is not expected to be +used very often since the ``C-d`` shortcut is the primary method of switching. However, if you need to switch modes from +a script, you can do so with this command. It takes no parameters and will immediately exit the ``pwncat`` shell to +return to the remote prompt. \ No newline at end of file diff --git a/docs/source/commands/bind.rst b/docs/source/commands/bind.rst new file mode 100644 index 0000000..c4cdbf9 --- /dev/null +++ b/docs/source/commands/bind.rst @@ -0,0 +1,41 @@ +Bind +==== + +The bind command is used to create new keyboard shortcuts or change old ones. Keyboard shortcuts are accessed by first +pressing your defined "prefix" key (by default: ``C-k``). ``bind`` takes two parameters: the key to bind, and the +script to run when it is pressed. + +Key Selection +------------- + +The key argument is specified as a string. If the string is a single character, it is assumed to be that literal printed +character. For example, to bind the lowercase "a" key to a command you could: + +.. code-block:: bash + + bind "a" "some helpful command" + +If the key argument is longer than one character, it is assumed to be a key name. The key names accepted by ``pwncat`` +are taken directly at runtime from the list of known ANSI keystrokes defined in the ``prompt_toolkit`` package. They +use the same syntax as in prompt toolkit. All key names are lowercase. The prompt_toolkit documentation covers the +keys supported by their module in their `documentation here`_. Any key defined by prompt_toolkit is available for +key binding by ``pwncat``. + +Script Content +-------------- + +The target of a key binding is a script. Scripts in ``pwncat`` can be specified as a string, which can only contain a +single command, or as a code block surrounded by curly braces. When in code block mode, you can use as many commands +as you like, and even insert comments, blank lines, etc. + +.. code-block:: bash + + bind "a" { + # you can bind a series of commands which you + # do very often to a key, if you find it helpful. + privesc -l + persist -s + tamper + } + +.. _`documentation here`: https://python-prompt-toolkit.readthedocs.io/en/master/pages/advanced_topics/key_bindings.html#list-of-special-keys \ No newline at end of file diff --git a/docs/source/commands/bruteforce.rst b/docs/source/commands/bruteforce.rst new file mode 100644 index 0000000..7a442c5 --- /dev/null +++ b/docs/source/commands/bruteforce.rst @@ -0,0 +1,35 @@ +Bruteforce +---------- + +The ``bruteforce`` command is used to bruteforce authentication of a user locally. It will use the ``su`` command to +iteratively try every password for a given user. This is very slow, but does technically work. If no wordlist is +specified, the default location of ``rockyou.txt`` in Kali Linux is chosen. This may or may not exist for your system. + +.. warning:: + This command is very noisy in log files. Each failed authentication is normally logged by any modern + linux distribution. Further, if account lockout is enabled, this will almost certainly lockout the + targeted account! + +Selecting a User +---------------- + +Individual users are selected with the ``--user`` argument. This argument can be passed multiple times to test multiple +users in one go. To use the default dictionary to test the root and bob users, you would issue a command like: + +.. code-block:: bash + + bruteforce -u root -u bob + +User names are automatically tab-completed at the ``pwncat`` prompt for your victim host. + +Selecting a Wordlist +-------------------- + +Word lists are specified with the ``--dictionary`` parameter. This parameter is a path to a file on your attacking +host which contains a list of passwords to attempt for the selected users. If a correct password is found, it is stored +in the databaase, and the search is aborted for that user. To select a custom database, you would issue a command like: + +.. code-block:: bash + + bruteforce -d /opt/my-favorite-repo/my-favorite-wordlist.txt -u root + diff --git a/docs/source/commands/busybox.rst b/docs/source/commands/busybox.rst new file mode 100644 index 0000000..b4deca8 --- /dev/null +++ b/docs/source/commands/busybox.rst @@ -0,0 +1,79 @@ +Busybox +======= + +``pwncat`` works by try as much as possible not to depend on specific binaries on the remote system. It does this +most of the time by selecting an unidentified existing binary from the GTFOBins database in order to perform a +generic capability (e.g. file read, file write or shell). However, sometimes a critical binary is missing on the +target host which has been removed (either maliciously or never installed). In these situations, obtaining a stable +version of all basic binaries is very helpful. To this end, ``pwncat`` has the capability to automatically upload a +copy of the ``busybox`` program to the remote host. + +The ``busybox`` command manages the installation, status, and removal of the installed busybox. Installing busybox lets +``pwncat`` know that it has a list of standard binaries with known good interfaces easily accessible. The ``busybox`` +command also understands how to locate a ``busybox`` binary precompiled for the victim architecture and upload it +through the existing C2 channel. The new busybox installation will be installed in a temporary directory, and any +further automated tools within ``pwncat`` will use it's implementation of common unix tools. + +Installation +------------ + +To install busybox on the remote victim, you can use the ``--install`` option to the ``busybox`` command. This will +first check for an existing, distribution specific, installation on the remote host. If the ``busybox`` command exists, +it will utilize that vice installing a new copy. If it doesn't, it will begin proxying a connection to the official +busybox servers to upload a busybox binary specific to the victim architecture. + +After installation, ``pwncat`` will examine the endpoints provided by busybox, and remove any that are provided SUID by +the remote system. This prevents ``pwncat`` from replacing the real ``su`` binary with ``busybox su`` in it's database. + +.. code-block:: + + (local) pwncat$ busybox --install + uploading busybox for x86_64 + 100.0% [==================================================>] 1066640/1066640 eta [00:00] + [+] uploaded busybox to /tmp/busyboxIu1gu + [+] pruned 164 setuid entries + (local) pwncat$ + +Status and Applet List +---------------------- + +To check if busybox has been installed and is known by ``pwncat`` (for example from a previous session), you can use the +``--status`` option. This is the default action, and can be accessed by passing no parameters to ``busybox``: + +.. code-block:: bash + + (local) pwncat$ busybox + [+] busybox is installed to: /tmp/busyboxIu1gu + [+] busybox provides 232 applets + (local) pwncat$ + +If you would like to see a list of binaries which busybox is currently providing for ``pwncat``, you can use the ``--list`` +option. This is normally a large list (232 lines in this case), but it is provided for completeness sake. + +.. code-block:: bash + + (local) pwncat$ busybox --list + [+] binaries which the remote busybox provides: + * [ + * [[ + * acpid + * add-shell + * addgroup + * adduser + * adjtimex + ... removed for brevity ... + +Removing Busybox +---------------- + +Busybox is tracked by ``pwncat`` as a remote tamper. This means that the ``tamper`` command will show that you have +installed busybox, and ``busybox`` can be uninstalled using the ``tamper`` command: + +.. code-block:: + + (local) pwncat$ tamper + 0 - installed busybox to /tmp/busyboxIu1gu + (local) pwncat$ tamper -r -t 0 + (local) pwncat$ busybox --status + [!] busybox hasn't been installed yet + (local) pwncat$ diff --git a/docs/source/commands/connect.rst b/docs/source/commands/connect.rst new file mode 100644 index 0000000..eb7e798 --- /dev/null +++ b/docs/source/commands/connect.rst @@ -0,0 +1,104 @@ +Connect +======= + +The ``connect`` command is used to connect to a remote victim. It can be used to catch a reverse shell, open a bind +shell, utilize legitimate SSH credentials, or reconnect via a previous persistence methood to a known host. + +This command is also the command which is run if you pass arguments to the external ``pwncat`` script. All arguments +to ``pwncat`` are passed directly to the ``connect`` command at startup. If no connection is made during this command, +``pwncat`` will automatically exit after command completion. + +The ``connect`` command is only accessible prior to an active connection. If you attempt to run this command after a +connection has been established, it will not attempt a new connection and will not load your configuration script. +Because the ``pwncat`` prompt is only accessible after a connection, this command is effectively only useful +when used as the arguments to the main ``pwncat`` application or in configuration scripts. Replacing ``connect`` +with ``pwncat`` in any examples below will also function the same way at startup. + +Catching a Reverse Shell +------------------------ + +Reverse shell listeners are started with the ``--listen`` parameter. This mode requires the ``--host`` and ``--port`` +parameters as well. If ``--host`` is not specified, it is assumed to be ``0.0.0.0`` to bind to all interfaces. To +listen for incoming shell connections on port 4444, you could issue a command like: + +.. code-block:: + + connect -l -H 0.0.0.0 -p 4444 + +Connecting to a Bind Shell +-------------------------- + +Making an outbound connection to a bind shell is accomplished through the ``--connect`` parameter. This mode requires +both the ``--host`` and ``--port`` parameters to be specified. + +.. code-block:: + + connect -c -H 1.1.1.1 -p 4444 + +Connecting to an SSH Server +--------------------------- + +If you have valid credentials to a remote SSH server, but would like to utilize ``pwncat`` to manage your session, you +can use the ``--ssh`` option. This mode requires the ``--host``, ``--user``, and ``--port`` options. If no port is +specified, it will default to ``22``. Along with these options, you must specify either a ``--password`` or ``--identity`` +for the remote password or private key identity file respectively. ``pwncat`` will use Paramiko to connect to the +victim and establish a PTY shell. It will then act normally and provide you access to this shell. All normal ``pwncat`` +features are still available over the SSH transport! + +.. code-block:: + :caption: Connecting with a known password + + connect -s -H 1.1.1.1 -u root -p "P@ssw0rd" + +.. code-block:: + :caption: Connection with a known private key + + connect -s -H 1.1.1.1 -u root -i "./exfiled-privkey" + +Listing Known Persistence Methods +--------------------------------- + +The ``connect`` command has the ability to query the database for all known remote hosts and list installed persistence +methods. It also provides the ability to leverage installed persistence methods to reconnect to a specific host. This +allows you to easily re-establish your session after disconnection if you installed some form of persistence. + +In ``pwncat`` hosts are identified by a "host hash". This has is generated by combining some unique data taken from the +remote host the last time a session was established and should be unique across all hosts (unlike IP addresses). The +ideal way to reference a remote host is by it's host hash. With an open session, you can retrieve your host hash with +the ``sysinfo`` command. To retrieve known hosts with persistence methods after disconnection, you can use the +``--list`` option to the ``connect`` command: + +.. code-block:: + :caption: Retrieving a list of known hosts + + $ pwncat -C data/pwncatrc --list + 1.1.1.1 - debian - d87b9646813d250ac433decdee70112a + - pam as system + - authorized_keys as debian + +When reconnecting to a host, you will need either the host hash or the IP address. While the host hash is preferred, +``pwncat`` will lookup a host by IP address in the database. In cases where multiple hosts are NAT'd behind a single +IP address, ``pwncat`` will choose the first host from the database with a matching IP address. + +Reconnecting to a Victim +------------------------ + +Once you have your victim's IP address or host hash, you are ready to reconnect. Reconnecting is simple and automatic in +most cases. The simplest option is to supply the victim IP or host hash to the ``--host`` parameter and specify the +``--reconnect`` option. This will try each persistence method individually until one succeeds in a session: + +.. code-block:: + + $ pwncat -C data/pwncatrc -r -H d87b9646813d250ac433decdee70112a + [+] setting terminal prompt + [+] running in /bin/bash + [+] terminal state synchronized + [+] pwncat is ready 🐈 + + (remote) debian@debian-s-1vcpu-1gb-nyc1-01:~$ + +If you have installed multiple persistence methods for multiple users, you can also specify a persistence method or user +to connect with. If only one of ``--method`` or ``--user`` is specified, all methods matching your search will be tried. +For example, specifying only ``method`` will cause ``pwncat`` to attempt each user for which that method is installed. +On the other hand, specifying only ``--user`` will cause ``pwncat`` to attempt connection with every method which +offers persistence as that user. When both are specified, only the exact matching persistence method will be attempted. diff --git a/docs/source/commands/index.rst b/docs/source/commands/index.rst new file mode 100644 index 0000000..1811655 --- /dev/null +++ b/docs/source/commands/index.rst @@ -0,0 +1,12 @@ +Command index +============= + +.. toctree:: + :caption: Contents + + alias.rst + back.rst + bind.rst + bruteforce.rst + busybox.rst + connect.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index dcea85e..621dab8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -68,6 +68,7 @@ well. Pull requests are always welcome! installation.rst usage.rst configuration.rst + commands/index.rst upload.rst download.rst tamper.rst diff --git a/pwncat/commands/busybox.py b/pwncat/commands/busybox.py index b2db66c..41281c4 100644 --- a/pwncat/commands/busybox.py +++ b/pwncat/commands/busybox.py @@ -61,8 +61,10 @@ class Command(CommandDefinition): def run(self, args): if args.action == "list": - if not pwncat.victim.has_busybox: - util.error("busybox hasn't been installed yet (hint: run 'busybox'") + if pwncat.victim.host.busybox is None: + util.error( + "busybox hasn't been installed yet (hint: run 'busybox --install'" + ) return util.info("binaries which the remote busybox provides:") diff --git a/pwncat/commands/help.py b/pwncat/commands/help.py index 329c878..dd65807 100644 --- a/pwncat/commands/help.py +++ b/pwncat/commands/help.py @@ -10,8 +10,13 @@ from pwncat import util class Command(CommandDefinition): """ List known commands and print their associated help documentation. """ + def get_command_names(self): + if pwncat.victim and pwncat.victim.command_parser: + return [c.PROG for c in pwncat.victim.command_parser.commands] + return [] + PROG = "help" - ARGS = {"topic": parameter(Complete.NONE, nargs="?")} + ARGS = {"topic": parameter(Complete.CHOICES, choices=get_command_names, nargs="?")} LOCAL = True def run(self, args): diff --git a/pwncat/remote/victim.py b/pwncat/remote/victim.py index 7ff2f84..d3d0e5a 100644 --- a/pwncat/remote/victim.py +++ b/pwncat/remote/victim.py @@ -569,13 +569,6 @@ class Victim: :return: The full path to the requested binary or None if it was not found. """ - if self.host.busybox is not None: - if name in self.busybox_provides: - if quote: - return f"{shlex.quote(str(self.busybox_path))} {name}" - else: - return f"{self.busybox_path} {name}" - binary = ( self.session.query(pwncat.db.Binary) .filter_by(name=name, host_id=self.host.id)