def run(self, args): if args.list: ListSids = self.client.remote('pupwinutils.security', 'ListSids') sids = ListSids() process_table = [] sids_table = [] sids_dict = {} for (pid, process, sid, username) in sids: process_table.append({ 'pid': pid, 'process': process, 'sid': sid, 'username': username }) sids_dict[sid] = username for sid, username in sids_dict.iteritems(): sids_table.append({ 'sid': sid, 'username': username }) self.log(MultiPart([ Table(process_table, [ 'pid', 'process', 'username', 'sid' ], caption='Process table'), Table(sids_table, [ 'sid', 'username' ], caption='Available Sids') ])) elif args.impersonate: if args.migrate: create_proc_as_sid = self.client.remote('pupwinutils.security', 'create_proc_as_sid', False) proc_pid = create_proc_as_sid(args.impersonate) migrate(self, proc_pid, keep=True) else: impersonate_sid_long_handle = self.client.remote( 'pupwinutils.security', 'impersonate_sid_long_handle', False) self.client.impersonated_dupHandle = impersonate_sid_long_handle(args.impersonate, close=False) self.success('Sid {} impersonated !'.format(args.impersonate)) elif args.rev2self: rev2self = self.client.remote('pupwinutils.security', 'rev2self', False) rev2self() self.client.impersonated_dupHandle = None self.success('rev2self called') else: self.error('no option supplied')
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 pack_scriptlets(display, scriptlets, args_scriptlet, os=None, arch=None, debug=False): sp = ScriptletsPacker(os, arch) for sc in args_scriptlet: tab = sc.split(",", 1) sc_args = {} name = tab[0] if len(tab) == 2: try: for x, y in [x.strip().split("=") for x in tab[1].split(",")]: sc_args[x.strip()] = y.strip() except: raise ValueError( "usage: pupygen ... -s %s,arg1=value,arg2=value,..." % name) if name not in scriptlets: raise ValueError("unknown scriptlet %s, valid choices are : %s" % (repr(name), [x for x in scriptlets.iterkeys()])) display( Success('loading scriptlet {}{}'.format( repr(name), 'with args {}'.format(' '.join( '{}={}'.format(k, repr(v)) for k, v in sc_args.iteritems())) if sc_args else ''))) try: sp.add_scriptlet(scriptlets[name], sc_args) except ScriptletArgumentError as e: display( MultiPart( Error('Scriptlet {} argument error: {}'.format( repr(name), str(e))), scriptlets[name].format_help())) raise ValueError('{}'.format(e)) script_code = sp.pack() return script_code
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']) line.append(NewLine()) parts.append(Line(*line)) handler.display(MultiPart(parts)) handler.display(NewLine()) except Exception, e: handler.display(Error(e)) return
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 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 getinfo(self, args): info = self.client.remote('ad', 'info') desc = from_tuple_deep(info(args.realm, args.global_catalog), False) idesc = desc.get('info', {}) infos = [] versions = idesc.get('supported_ldap_versions', []) if not hasattr(versions, '__iter__'): versions = [versions] infos.append( List([ 'Bind: ' + desc.get('bind', ''), 'Root: ' + desc.get('root', ''), 'LDAP: ' + desc.get('ldap', ''), 'DNS: ' + desc['dns'][4][0] if desc.get('dns', None) else '', 'Schema: ' + idesc.get('schema_entry', ''), 'Versions: ' + ', '.join(str(version) for version in versions), 'SASL Mechs: ' + ', '.join( mech for mech in idesc.get('supported_sasl_mechanisms', [])) ], caption='Connection')) if desc['ldap_servers']: infos.append( Table(desc['ldap_servers'], ['address', 'port', 'priority'], caption='LDAP Servers')) if desc['dns_servers']: infos.append( Table([{ 'IP': dns[0][4][0] + ('/tcp' if dns[0][2] == 2 else '/udp'), 'Delay': '{:.02f}ms'.format(dns[1] * 1000), } for dns in desc['dns_servers']], ['IP', 'Delay'], caption='DNS Servers')) if not idesc: self.log(MultiPart(infos)) return if idesc['alt_servers']: infos.append( List(idesc['alt_servers'], caption='Alternate servers')) if idesc['naming_contexts'] and not isinstance( idesc['naming_contexts'], (str, unicode)): infos.append( List(idesc['naming_contexts'], caption='Naming contexts')) supported = [] for table in ('supported_controls', 'supported_extensions', 'supported_features'): for oid, klass, name, vendor in idesc[table]: supported.append({ 'OID': oid, 'Type': klass, 'Name': name, 'Vendor': vendor }) if supported: infos.append( Table(supported, ['OID', 'Type', 'Name', 'Vendor'], caption='Supported features and extensions')) if 'other' in idesc: infos.append( List(tuple('{}: {}'.format(key, value) for key, value in idesc['other'].iteritems() if key not in ('supportedLDAPPolicies', )), caption='Other info')) self.log(MultiPart(infos))
class FStat(PupyModule): '''Show a bit more info about file path. ACLs/Caps/Owner for now''' dependencies = { 'all': ['pupyutils.basic_cmds', 'fsutils', 'fsutils_ext'], 'windows': ['junctions', 'ntfs_streams', 'pupwinutils.security'], 'linux': ['xattr', 'posix1e', 'prctl', '_prctl'] } @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog='stat', description=cls.__doc__) cls.arg_parser.add_argument( '-v', '--verbose', action='store_true', default=False, help='Print more information (certificates for example)') cls.arg_parser.add_argument('path', type=str, nargs=REMAINDER, help='path of a specific file', completer=remote_path_completer) def run(self, args): getfilesec = self.client.remote('fsutils_ext', 'getfilesec') path = ' '.join(args.path) try: sec = getfilesec(path) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return ctime, atime, mtime, size, owner, group, header, mode, extra = sec owner_id, owner_name, owner_domain = owner group_id, group_name, group_domain = group default = { 'Created': file_timestamp(ctime, time=True), 'Accessed': file_timestamp(atime, time=True), 'Modified': file_timestamp(mtime, time=True), 'Size': '{} ({})'.format(size_human_readable(size), size), 'Owner': '{}{} ({})'.format(owner_domain + '\\' if owner_domain else '', owner_name, owner_id), 'Group': '{}{} ({})'.format(group_domain + '\\' if group_domain else '', group_name, group_id), 'Mode': mode, } infos = [] infos.append( Table([{ 'Property': p, 'Value': default[p] } for p in ('Created', 'Accessed', 'Modified', 'Size', 'Owner', 'Group', 'Mode')], ['Property', 'Value'], legend=False)) oneliners = [] certificates = None for extra, values in extra.iteritems(): if extra == 'Certificates': certificates = [ load_cert_string(cert, FORMAT_DER).as_text() for cert in values ] elif isinstance(values, dict): records = [{ 'KEY': k.decode('utf-8'), 'VALUE': v.decode('utf-8') if isinstance(v, str) else str(v) } for k, v in values.iteritems()] infos.append(Table(records, ['KEY', 'VALUE'], caption=extra)) elif isinstance(values, (list, tuple)): if all( isinstance(value, (list, tuple)) and len(value) == 2 for value in values): infos.append( List('{}: {}'.format(key, value) for key, value in values)) else: infos.append(List(values, caption=extra)) elif isinstance(values, int): oneliners.append('{}: {}'.format(extra, values)) elif '\n' in values: infos.append(Line(extra + ':', values)) else: oneliners.append(extra + ': ' + values) if args.verbose: magic = '' if header: with Magic() as libmagic: magic = libmagic.id_buffer(header) if magic: oneliners.append('Magic: {}'.format(magic)) if certificates: infos.extend(certificates) if oneliners: infos.append(List(oneliners, caption='Other')) self.log(MultiPart(infos))
def run(self, args): if self.client.is_posix(): tier1 = ('network', 'fuse', 'dm', 'block', 'vm') mounts = self.client.remote('mount', 'mounts') getuid = self.client.remote('os', 'getuid') getgid = self.client.remote('os', 'getgid') mountinfo = mounts() uid = getuid() gid = getgid() option_colors = { 'rw': 'yellow', 'nosuid': 'grey', 'nodev': 'grey', 'noexec': 'lightgreen', 'uid': { '0': 'green', str(uid): 'red' }, 'gid': { '0': 'green', str(gid): 'red' }, 'ro': 'green', 'user_id': { '0': 'green', str(uid): 'red' }, 'group_id': { '0': 'green', str(gid): 'red' }, 'allow_other': 'yellow', 'xattr': 'yellow', 'acl': 'yellow', 'username': '******', 'domain': 'red', 'forceuid': 'yellow', 'forcegid': 'yellow', 'addr': 'red', 'unix': 'red' } def colorize_option(option): if len(option) > 1: k, v = option else: k = option[0] v = None color = option_colors.get(k) if color: if type(color) == dict: if v in color: return colorize('='.join([x for x in [k, v] if x]), color.get(v)) else: return '='.join([x for x in [k, v] if x]) else: return colorize('='.join([x for x in [k, v] if x]), color) else: return '='.join([x for x in [k, v] if x]) output = [] for fstype in mountinfo.iterkeys(): if fstype in tier1: continue output.append('{}:'.format(colorize(fstype, 'yellow'))) dst_max = max([len(x['dst']) for x in mountinfo[fstype]]) fsname_max = max([len(x['fsname']) for x in mountinfo[fstype]]) free_max = max([ len(x['hfree']) if x['total'] else 0 for x in mountinfo[fstype] ]) for info in mountinfo[fstype]: fmt = '{{:<{}}} {{:<{}}} {{:>{}}} {{}}'.format( dst_max, fsname_max, (free_max + 3 + 4) if free_max else 0) output.append( fmt.format( info['dst'], info['fsname'], (colorize( ('{{:>3}}% ({{:>{}}})'.format(free_max) ).format(info['pused'], info['hfree']), 'white' if info['pused'] < 90 else 'yellow')) if info['total'] else '', ','.join([ colorize_option(option) for option in info['options'] ]))) output.append('') for fstype in tier1: if fstype not in mountinfo: continue src_max = max([len(x['src']) for x in mountinfo[fstype]]) dst_max = max([len(x['dst']) for x in mountinfo[fstype]]) fsname_max = max([len(x['fsname']) for x in mountinfo[fstype]]) free_max = max([ len(x['hfree']) if x['total'] else 0 for x in mountinfo[fstype] ]) output.append('{}:'.format(colorize(fstype, 'green'))) for info in mountinfo[fstype]: fmt = '{{:<{}}} {{:<{}}} {{:<{}}} {{:>{}}} {{}}'.format( dst_max, src_max, fsname_max, (free_max + 3 + 4) if free_max else 0) output.append( fmt.format( info['dst'], info['src'], info['fsname'], (colorize( ('{{:>3}}% ({{:>{}}})'.format(free_max) ).format(info['pused'], info['hfree']), 'white' if info['pused'] < 90 else 'yellow')) if info['total'] else '', ','.join([ colorize_option(option) for option in info['options'] ]))) output.append('') self.log('\n'.join(output)) elif self.client.is_windows(): list_drives = self.client.remote('pupyps', 'drives') EnumNetResources = self.client.remote('netresources', 'EnumNetResources') drives = list_drives() formatted_drives = [] parts = [] for drive in drives: formatted_drives.append({ 'MP': drive['mountpoint'], 'FS': drive['fstype'], 'OPTS': drive['opts'], 'USED': ('{}% ({}/{})'.format( drive['percent'], size_human_readable(drive['used']), size_human_readable(drive['total']))) if ('used' in drive and 'total' in drive) else '?' }) parts.append(Table(formatted_drives, ['MP', 'FS', 'OPTS', 'USED'])) providers = {} net_resources = EnumNetResources() for resource in net_resources: if resource['provider'] not in providers: providers[resource['provider']] = [] if 'used' in resource: resource['used'] = '{}% ({}/{})'.format( resource['percent'], size_human_readable(resource['used']), size_human_readable(resource['total'])) else: resource['used'] = '?' providers[resource['provider']].append( dict((k, v) for k, v in resource.iteritems() if k not in ('usage', 'provider', 'scope'))) for provider, records in providers.iteritems(): parts.append( Table(records, ['remote', 'local', 'type', 'used'], caption=provider)) self.log(MultiPart(parts))
def run(self, args): close_event = threading.Event() result = [] cmdargs = None kwargs = None definitions = None safe_exec = self.client.remote('pupyutils.safepopen', 'safe_exec', False) if self.client.is_linux(): payload = open(LINUX_EXPLOIT_SUGGESTER_PATH).read() cmdargs = ['/bin/bash'] kwargs = (('stdin_data', payload), ) else: definitions = os.path.join(self.config.get_folder('plugins'), WES_LOCAL_FILE) if not os.path.isfile(definitions) or args.update: self.info( 'Updating WES defintions from {}'.format(WES_DEFINITIONS)) try: response = urlopen(WES_DEFINITIONS) with open(definitions, 'w+b') as out: while True: block = response.read(32768) if not block: break out.write(block) except Exception as e: self.error('Update failed: {}'.format(e)) if os.path.isfile(definitions): try: os.unlink(definitions) except (OSError, IOError): pass return self.info('Update completed ({})'.format(definitions)) expandvars = self.client.remote('os.path', 'expandvars') systeminfo = expandvars(r'%WINDIR%\System32\systeminfo.exe') cmdargs = [systeminfo] kwargs = tuple() self.info('Execute payload ({})'.format(' '.join(cmdargs))) self.terminate_pipe, get_returncode = safe_exec( result.append, close_event.set, cmdargs, kwargs) close_event.wait() retcode = get_returncode() if retcode != 0: self.warning('Ret: {}'.format(retcode)) else: self.success('Done') result = ''.join(result) if not result: self.error('No data') return if self.client.is_linux(): self.log(result) return wes = imp.load_source('wes', WES_PATH) try: cves, date = wes.load_definitions(definitions) except BadZipfile: self.error('Defintions were downloaded incorrectly ({})'.format( definitions)) return productfilter, win, mybuild, version, arch, hotfixes = \ wes.determine_product(result) self.log( List([ 'Definitions: ' + str(date), 'Name: ' + productfilter, 'Generation: ' + (win or 'N/A'), 'Build: ' + (str(mybuild) if mybuild else 'N/A'), 'Version: ' + (str(version) or 'N/A'), 'Architecture: ' + arch, 'Hotfixes: ' + ', '.join(['KB%s' % kb for kb in hotfixes]) ], caption='Operating System')) try: filtered, found = wes.determine_missing_patches( productfilter, cves, hotfixes) except wes.WesException as e: self.error(e.msg) return if not args.no_recent_kb: recentkb = wes.get_most_recent_kb(found) if recentkb: recentdate = int(recentkb['DatePosted']) found = list( filter(lambda kb: int(kb['DatePosted']) >= recentdate, found)) if 'Windows Server' in productfilter: self.info('Filtering duplicate vulnerabilities') found = wes.filter_duplicates(found) filtered = wes.apply_display_filters(found, args.hide, True, [], []) if not filtered: self.info('No vulnerabilities found') return results = {} proposed = set() for res in filtered: exploits = res['Exploits'].split(',') for exploit in exploits: exploit = exploit.strip() if exploit in proposed: continue proposed.add(exploit) impact = ''.join(l[0] for l in res['Impact'].split()) color = 'white' if impact == 'ID': color = 'grey' elif res['Severity'] == 'Critical' or impact in ('RCE', 'EoP'): color = 'lightred' elif res['Severity'] == 'Important': color = 'lightyellow' title = (res['AffectedComponent'] + ' / ' + res['AffectedProduct']) \ if res['AffectedComponent'] else res['AffectedProduct'] if title not in results: results[title] = [] results[title].append({ 'CVE': Color(res['CVE'], color), 'Date': res['DatePosted'], 'Impact': impact, 'Exploit': exploit }) tables = [NewLine()] for component, cves in results.iteritems(): tables.append( Table(cves, ['CVE', 'Date', 'Impact', 'Exploit'], component)) self.log(MultiPart(tables))
class FStat(PupyModule): '''Show a bit more info about file path. ACLs/Caps/Owner for now''' dependencies = { 'all': ['pupyutils', 'fsutils', 'fsutils_ext'], 'windows': ['junctions', 'ntfs_streams'], 'linux': ['xattr', 'posix1e', 'prctl', '_prctl'] } @classmethod def init_argparse(cls): cls.arg_parser = PupyArgumentParser(prog='stat', description=cls.__doc__) cls.arg_parser.add_argument('path', type=str, nargs=REMAINDER, help='path of a specific file', completer=remote_path_completer) def run(self, args): getfilesec = self.client.remote('fsutils_ext', 'getfilesec') path = ' '.join(args.path) try: sec = getfilesec(path) except Exception, e: self.error(' '.join(x for x in e.args if type(x) in (str, unicode))) return ctime, atime, mtime, size, owner, group, header, mode, extra = sec owner_id, owner_name, owner_domain = owner group_id, group_name, group_domain = group magic = '' if header: with Magic() as libmagic: magic = libmagic.id_buffer(header) default = { 'Created': file_timestamp(ctime, time=True), 'Accessed': file_timestamp(atime, time=True), 'Modified': file_timestamp(mtime, time=True), 'Size': '{} ({})'.format(size_human_readable(size), size), 'Owner': '{}{} ({})'.format(owner_domain + '\\' if owner_domain else '', owner_name, owner_id), 'Group': '{}{} ({})'.format(group_domain + '\\' if group_domain else '', group_name, group_id), 'Mode': mode, } infos = [] infos.append( Table([{ 'Property': p, 'Value': default[p] } for p in ('Created', 'Accessed', 'Modified', 'Size', 'Owner', 'Group', 'Mode')], ['Property', 'Value'], legend=False)) if magic: infos.append('Magic: {}'.format(magic)) for extra, values in extra.iteritems(): if type(values) in (list, tuple): infos.append(List(values, caption=extra)) else: infos.append(Line(extra + ':', values)) self.log(MultiPart(infos))
def render_diff(self, diff): if not diff: return listeners = [] ingress = [] egress = [] parts = [] for record in diff: new_listeners_tcp, new_listeners_udp, \ new_ingress_tcp, new_ingress_udp, \ new_egress_tcp, new_egress_udp = record for new_listeners in (new_listeners_tcp, new_listeners_udp): if not new_listeners: continue for listener in new_listeners: program, ip, port = listener listeners.append({ 'PRT': 'TCP' if id(new_listeners) == id(new_listeners_tcp) else 'UDP', 'EXE': program, 'HOST': ip, 'PORT': port }) for new_ingress in (new_ingress_tcp, new_ingress_udp): if not new_ingress: continue for record in new_ingress: program, (ip, port), remote_ip = record ingress.append({ 'PRT': 'TCP' if id(new_ingress) == id(new_ingress_tcp) else 'UDP', 'EXE': program, 'LADDR': ip, 'LPORT': port, 'RADDR': remote_ip }) for new_egress in (new_egress_tcp, new_egress_udp): if not new_egress: continue for record in new_egress: program, (ip, port) = record egress.append({ 'PRT': 'TCP' if id(new_egress) == id(new_egress_tcp) else 'UDP', 'EXE': program, 'ADDR': ip, 'PORT': port, }) if listeners: parts.append( Table(listeners, ['PRT', 'HOST', 'PORT', 'EXE'], 'Listeners')) if ingress: parts.append( Table(ingress, ['PRT', 'LADDR', 'LPORT', 'RADDR', 'EXE'], 'Ingress')) if egress: parts.append( Table(egress, ['PRT', 'ADDR', 'PORT', 'EXE'], 'Egress')) self.log(MultiPart(parts))