mirror of https://github.com/n1nj4sec/pupy.git
Add basic tags support to dnscnc and sessions
This commit is contained in:
parent
96bbb4f895
commit
c8d4f68359
|
@ -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 = []
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue