1
0
mirror of https://github.com/calebstewart/pwncat.git synced 2024-11-27 19:04:15 +01:00

Added documentation for new compile method

This commit is contained in:
Caleb Stewart 2020-06-02 19:03:05 -04:00
parent 668eadbaef
commit ffa1059a43
4 changed files with 68 additions and 13 deletions

View File

@ -164,6 +164,68 @@ Starting, stopping or enabling a service is as easy as calling a method or setti
except ValueError: except ValueError:
print("sshd doesn't exist!") print("sshd doesn't exist!")
Compiling Code for the Victim
-----------------------------
``pwncat`` provides an abstract capability to compile binaries in ``C`` for the victim. By setting
the ``cross`` configuration item to the path to valid C compiler on your attacking system capable
of generating compiled binaries for the victim, you can have ``pwncat`` compile exploits locally
and upload only the compiled binaries. This not only speeds up privilege escalation checks, but also
enables some methods in the case the remote host does not have a working C compiler. If no ``cross``
value is provided, ``pwncat`` will still check for an utilize a remote compiler if available.
To access, this functionality, you can use the ``pwncat.victim.compile`` method. This method takes
a list of source files, an output suffix, and a list of CFLAGS and LDFLAGS. The result is the path
to the compiled binary on the remote host. Ideally, it will utilize a local cross-compiler and upload
the binary, but it is also capable of uploading the specified source files and compiling remotely
as well.
.. code-block:: python
:caption: Compiling Local Source Files For A Victim
import pwncat
# Compile your code for the remote host
remote_path = pwncat.victim.compile(["main.c", "other.c"], cflags=["-static"], ldflags=["-lssl"])
# Run the new binary
pwncat.victim.run(remote_path)
# Track the new binary in the tamper database
pwncat.victim.tamper.created_file(remote_path)
The list of sources can also accept file objects instead of file paths. In this case, you can wrap
a literal string in a `io.StringIO` object in order to compile short source files from memory:
.. code-block:: python
:caption: Compiling Source From Memory
import pwncat
import textwrap
import io
# Simple in-memory source file
source = textwrap.dedent(r"""
#include <stdio.h>
int main(int argc, char** argv) {
printf("Hello World!\n");
return 0;
}
""")
# Compile the source file
remote_path = pwncat.victim.compile([io.StringIO(source)])
# will print b"Hello World!\n"
print(pwncat.victim.run(remote_path))
You can also utilize the CFLAGS argument to produce shared libraries if needed:
.. code-block:: python
:caption: Compiling Shared Libraries
import pwncat
# Compile the source as a shared library
remote_path = pwncat.victim.compile(["main.c"], cflags=["-fPIC", "-shared"], suffix=".so")
The Victim Object The Victim Object
----------------- -----------------

View File

@ -60,7 +60,9 @@ class Command(CommandDefinition):
def run(self, args): def run(self, args):
if args.action == "list": if args.action == "install":
pwncat.victim.bootstrap_busybox(args.url)
elif args.action == "list":
if pwncat.victim.host.busybox is None: if pwncat.victim.host.busybox is None:
util.error( util.error(
"busybox hasn't been installed yet (hint: run 'busybox --install'" "busybox hasn't been installed yet (hint: run 'busybox --install'"
@ -95,5 +97,3 @@ class Command(CommandDefinition):
.scalar() .scalar()
) )
util.info(f"busybox provides {Fore.GREEN}{nprovides}{Fore.RESET} applets") util.info(f"busybox provides {Fore.GREEN}{nprovides}{Fore.RESET} applets")
elif args.action == "install":
pwncat.victim.bootstrap_busybox(args.url)

View File

@ -159,7 +159,7 @@ class Command(CommandDefinition):
if not args.user: if not args.user:
self.parser.error("you must specify a user") self.parser.error("you must specify a user")
if not args.password and not args.identity: if not (args.password or args.identity):
self.parser.error("either a password or identity file is required") self.parser.error("either a password or identity file is required")
try: try:

View File

@ -397,10 +397,7 @@ class Command(CommandDefinition):
data: Dict[str, Dict[str, List[pwncat.db.Fact]]] = {} data: Dict[str, Dict[str, List[pwncat.db.Fact]]] = {}
if isinstance(typ, list): types = typ if isinstance(typ, list) else [typ]
types = typ
else:
types = [typ]
util.progress("enumerating facts") util.progress("enumerating facts")
for typ in types: for typ in types:
@ -429,10 +426,6 @@ class Command(CommandDefinition):
def flush_facts(self, typ: str, provider: str): def flush_facts(self, typ: str, provider: str):
""" Flush all facts that match criteria """ """ Flush all facts that match criteria """
if isinstance(typ, list): types = typ if isinstance(typ, list) else [typ]
types = typ
else:
types = [typ]
for typ in types: for typ in types:
pwncat.victim.enumerate.flush(typ, provider) pwncat.victim.enumerate.flush(typ, provider)