8from colorama
import Fore, Back, Style
10from flask
import Flask, request, cli
11from multiprocessing
import Process, SimpleQueue
14from rich.logging
import RichHandler
20 handlers=[RichHandler(rich_tracebacks=
True)]
24log = logging.getLogger(
'werkzeug')
25log.setLevel(logging.ERROR)
31cli.show_server_banner =
lambda *_:
None
33parser = argparse.ArgumentParser(description=
'POST command object from file to commanded endpoint.')
34parser.add_argument(
'--host', type=str, default=
'localhost', help=
'target host/endpoint')
35parser.add_argument(
'-p',
'--port', type=int, default=12345, help=
'target port')
36parser.add_argument(
'-a',
'--answer-port', type=int, default=12333, help=
'answer to service listening on this port')
37parser.add_argument(
'-o',
'--answer-host', type=str, default=
None, help=
'answer to service listening on this host')
38parser.add_argument(
'-x',
'--proxy', type=str, default=
None, help=
'Use proxy for posting requests')
40parser.add_argument(
'-r',
'--route', type=str, default=
'command', help=
'target route on endpoint')
41parser.add_argument(
'-f',
'--file', type=str, required=
True, help=
'file that contains command to be posted')
42group = parser.add_mutually_exclusive_group()
43group.add_argument(
'-c',
'--command', type=str, default=
None, help=
'Only send command COMMAND, not all commands in file')
44parser.add_argument(
'-w',
'--wait', type=int, default=2, help=
'seconds to wait between sending commands')
45group.add_argument(
'-i',
'--interactive', dest=
'interactive', action=
'store_true', help=
'interactive mode')
46parser.add_argument(
'--non-interactive', dest=
'interactive', action=
'store_false')
47parser.set_defaults(interactive=
False)
49args = parser.parse_args()
51reply_queue = SimpleQueue()
55@app.route('/response', methods = ['POST'])
57 json = request.get_json(force=
True)
60 return 'Response received'
62if __name__ ==
"__main__":
63 flask_server = Process(target=app.run, kwargs={
'port': args.answer_port})
66url =
'http://'+args.host+
':'+
str(args.port)+
'/'+args.route
68logging.info(f
'Target url: {url}')
69headers = {
'content-type':
'application/json',
'X-Answer-Port':
str(args.answer_port)}
70if not args.answer_host
is None:
71 headers[
'X-Answer-Host'] = args.answer_host
75 with open(args.file)
as f:
79 logging.error(f
"ERROR: failed to open file '{str(args.file)}'.")
82if isinstance(cmdstr, dict):
83 logging.info(f
'Found single command in {args.file}.')
85 response = requests.post(
87 data=json.dumps(cmdstr),
90 'http': f
'socks5h://{args.proxy}',
91 'https': f
'socks5h://{args.proxy}'}
92 if args.proxy
else None
95 logging.info(f
'Response code: {str(response)} with content: {response.content.decode("utf-8")}')
96 except Exception
as e:
97 logging.error(f
'Failed to send due to: {e}')
98elif isinstance(cmdstr, list):
99 print(f
'Found a list of commands in {args.file}')
100 avacmds = [cdict[
'id']
for cdict
in cmdstr
if cdict[
"id"]]
101 if args.command
and not args.command
in avacmds:
102 raise SystemExit(f
"\nERROR: No command '{args.command}' found in file '{str(args.file)}'.")
103 if not args.interactive:
106 if args.command
and cmd[
'id']!=args.command:
108 response = requests.post(
110 data=json.dumps(cmd),
113 'http': f
'socks5h://{args.proxy}',
114 'https': f
'socks5h://{args.proxy}'}
115 if args.proxy
else None
118 print(f
'Response code: {str(response)} with content: {response.content.decode("utf-8")}')
120 r = reply_queue.get()
122 print(f
" Application : {Fore.CYAN}{r['appname']}{Style.RESET_ALL}")
123 print(f
" Command : {Fore.CYAN}{r['data']['cmdid']}{Style.RESET_ALL}")
124 print(f
" Result : {Fore.GREEN if r['success'] else Fore.RED}{r['result']}{Style.RESET_ALL}")
125 time.sleep(args.wait)
127 print(
'Failed to send due to: %s' % sys.exc_info()[0])
129 print(
'\nInteractive mode. Type the ID of the next command to send, or type \'end\' to finish.')
132 print(f
'\nAvailable commands: {", ".join([Fore.CYAN+c+Style.RESET_ALL for c in avacmds])}')
133 nextcmd = input(
'command >> ')
136 cmdobj = [cdict
for cdict
in cmdstr
if cdict[
"id"] == nextcmd]
138 print(
'Unrecognized command %s. (Not present in the command list?)' % nextcmd)
140 print(f
'\nSending {Fore.CYAN+nextcmd+Style.RESET_ALL} command.')
142 response = requests.post(
144 data=json.dumps(cmdobj[0]),
147 'http': f
'socks5h://{args.proxy}',
148 'https': f
'socks5h://{args.proxy}'}
149 if args.proxy
else None
152 print(f
'Response code: {str(response)} with content: {response.content.decode("utf-8")}')
154 r = reply_queue.get()
156 print(f
" Command : {Fore.CYAN}{r['data']['cmdid']}{Style.RESET_ALL}")
157 print(f
" Result : {Fore.GREEN if r['success'] else Fore.RED}{r['result']}{Style.RESET_ALL}")
159 print(
'Failed to send due to: %s' % sys.exc_info()[0])
160 except KeyboardInterrupt
as ki:
162 except EOFError
as e:
166flask_server.terminate()