1
0
mirror of https://github.com/calebstewart/pwncat.git synced 2024-11-23 17:15:38 +01:00

Started documenting all pwncat prompt commands

This commit is contained in:
Caleb Stewart 2020-05-23 15:35:46 -04:00
parent a14c0979d3
commit b41cfd9aa9
11 changed files with 304 additions and 10 deletions

View File

@ -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).

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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$

View File

@ -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.

View File

@ -0,0 +1,12 @@
Command index
=============
.. toctree::
:caption: Contents
alias.rst
back.rst
bind.rst
bruteforce.rst
busybox.rst
connect.rst

View File

@ -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

View File

@ -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:")

View File

@ -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):

View File

@ -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)