From 0c430b7293a3a2d0601283f89160621aaf0160e3 Mon Sep 17 00:00:00 2001 From: allfro Date: Mon, 17 Dec 2012 05:40:49 -0500 Subject: [PATCH] Added cross-lang support to canari packages --- setup.py | 4 +- src/canari/commands/create_package.py | 10 ++++- src/canari/commands/run_server.py | 58 ++++++++++++++++---------- src/canari/framework.py | 60 ++++++++++++++++++++++++++- src/canari/resource.py | 10 ++++- src/canari/utils/stack.py | 21 ++++++++++ 6 files changed, 134 insertions(+), 29 deletions(-) create mode 100644 src/canari/utils/stack.py diff --git a/setup.py b/setup.py index 99f8d08..ef33f01 100755 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ if name == 'nt': setup( name='canari', author='Nadeem Douba', - version='0.4', + version='0.5', author_email='ndouba@gmail.com', description='Rapid transform development and transform execution framework for Maltego.', license='GPL', @@ -37,4 +37,4 @@ setup( 'argparse' ], dependency_links=[] -) \ No newline at end of file +) diff --git a/src/canari/commands/create_package.py b/src/canari/commands/create_package.py index 7d62dfe..5b69432 100644 --- a/src/canari/commands/create_package.py +++ b/src/canari/commands/create_package.py @@ -13,7 +13,7 @@ __copyright__ = 'Copyright 2012, Canari Project' __credits__ = [] __license__ = 'GPL' -__version__ = '0.1' +__version__ = '0.2' __maintainer__ = 'Nadeem Douba' __email__ = 'ndouba@gmail.com' __status__ = 'Development' @@ -48,7 +48,7 @@ def write_root(base, init): def write_resources(package_name, resources, init, values): write_template( path.join(resources, '__init__.py'), - init + generate_all('etc', 'images', 'maltego') + init + generate_all('etc', 'images', 'maltego', 'external') ) write_template( @@ -61,6 +61,11 @@ def write_resources(package_name, resources, init, values): init ) + write_template( + path.join(resources, 'external', '__init__.py'), + init + ) + write_template( path.join(resources, 'maltego', '__init__.py'), init @@ -175,6 +180,7 @@ def run(args): resources, [resources, 'etc'], [resources, 'images'], + [resources, 'external'], [resources, 'maltego'] ) else: diff --git a/src/canari/commands/run_server.py b/src/canari/commands/run_server.py index 310a3b6..070a247 100755 --- a/src/canari/commands/run_server.py +++ b/src/canari/commands/run_server.py @@ -14,9 +14,10 @@ from argparse import ArgumentParser from cStringIO import StringIO from socket import getfqdn from urlparse import urlsplit +from re import sub, findall from hashlib import md5 from sys import argv -from re import sub + __author__ = 'Nadeem Douba' @@ -24,7 +25,7 @@ __copyright__ = 'Copyright 2012, Canari Project' __credits__ = [] __license__ = 'GPL' -__version__ = '0.3' +__version__ = '0.4' __maintainer__ = 'Nadeem Douba' __email__ = 'ndouba@gmail.com' __status__ = 'Development' @@ -109,19 +110,29 @@ def message(m, r): r.send_header('Connection', 'close') r.end_headers() - sio = StringIO() - for e in m.entities: - if e.iconurl is not None: - e.iconurl = e.iconurl.strip() - if e.iconurl.startswith('file://'): - path = '/%s' % md5(e.iconurl).hexdigest() - new_url = '%s://%s%s' % ('https' if r.server.is_ssl else 'http', r.server.hostname, path) - if path not in r.server.resources: - r.server.resources[path] = e.iconurl[7:] - e.iconurl = new_url - - Message(MaltegoMessage(m)).write(sio) - v = sio.getvalue() + v = None + if isinstance(m, basestring): + for url in findall("\s*(file://[^\s<]+)\s*(?im)", m): + path = '/%s' % md5(url).hexdigest() + new_url = '%s://%s%s' % ('https' if r.server.is_ssl else 'http', r.server.hostname, path) + if path not in r.server.resources: + r.server.resources[path] = url[7:] + m.replace(url, new_url, 1) + v = m + else: + sio = StringIO() + for e in m.entities: + if e.iconurl is not None: + e.iconurl = e.iconurl.strip() + if e.iconurl.startswith('file://'): + path = '/%s' % md5(e.iconurl).hexdigest() + new_url = '%s://%s%s' % ('https' if r.server.is_ssl else 'http', r.server.hostname, path) + if path not in r.server.resources: + r.server.resources[path] = e.iconurl[7:] + e.iconurl = new_url + + Message(MaltegoMessage(m)).write(sio) + v = sio.getvalue() # Get rid of those nasty unicode 32 characters r.wfile.write(sub(r'(&#\d{5};){2}', r'', v)) @@ -150,13 +161,14 @@ class MaltegoTransformRequestHandler(BaseHTTPRequestHandler): def dotransform(self, t): - try: if 'Content-Length' not in self.headers: self.send_error(500, 'What?') return - xml = fromstring(self.rfile.read(int(self.headers['Content-Length']))).find('MaltegoTransformRequestMessage') + request_str = self.rfile.read(int(self.headers['Content-Length'])) + + xml = fromstring(request_str).find('MaltegoTransformRequestMessage') e = xml.find('Entities/Entity') etype = e.get('Type', '') @@ -169,9 +181,13 @@ class MaltegoTransformRequestHandler(BaseHTTPRequestHandler): fields = dict([(f.get('Name', ''), f.text) for f in xml.findall('Entities/Entity/AdditionalFields/Field')]) params = dict([(f.get('Name', ''), f.text) for f in xml.findall('TransformFields/Field')]) for k, i in params.items(): - config[k.replace('.', '/', 1)] = i + if '.' in k: + config[k.replace('.', '/', 1)] = i + else: + config['default/%s' % k] = i limits = xml.find('Limits').attrib + msg = t[0]( type( 'MaltegoTransformRequestMessage', @@ -183,15 +199,13 @@ class MaltegoTransformRequestHandler(BaseHTTPRequestHandler): 'limits' : limits } )(), - MaltegoTransformResponseMessage() + request_str if hasattr(t[0], 'cmd') and callable(t[0].cmd) else MaltegoTransformResponseMessage() ) - if isinstance(msg, MaltegoTransformResponseMessage): + if isinstance(msg, MaltegoTransformResponseMessage) or isinstance(msg, basestring): message(msg, self) return - elif isinstance(msg, basestring): - raise MaltegoException(msg) else: raise MaltegoException('Could not resolve message type returned by transform.') diff --git a/src/canari/framework.py b/src/canari/framework.py index 25e10d3..e6602d0 100644 --- a/src/canari/framework.py +++ b/src/canari/framework.py @@ -1,11 +1,19 @@ #!/usr/bin/env python +from subprocess import PIPE, Popen + +from canari.resource import external_resource +from canari.utils.stack import modulecallee + +from os import execvp, path +from re import split + __author__ = 'Nadeem Douba' __copyright__ = 'Copyright 2012, Canari Project' __credits__ = [] __license__ = 'GPL' -__version__ = '0.1' +__version__ = '0.2' __maintainer__ = 'Nadeem Douba' __email__ = 'ndouba@gmail.com' __status__ = 'Development' @@ -38,8 +46,58 @@ class configure(object): raise TypeError('Expected type list (got %s instead)' % type(kwargs['inputs'])) kwargs['description'] = kwargs.get('description', '') kwargs['debug'] = kwargs.get('debug', False) + self.function = kwargs.get('cmd', None) self.specification = kwargs def __call__(self, f): + if callable(self.function): + self.function.__dict__.update(f.__dict__) + f = self.function f.__dict__.update(self.specification) return f + + +class ExternalCommand(object): + + def __init__(self, transform_name, transform_args=[], interpreter=None, is_resource=True): + self._extra_external_args = [] + + if interpreter is not None: + self._extra_external_args.append(interpreter) + libpath = external_resource( + path.dirname(transform_name), + '%s.resources.external' % modulecallee().__name__.split('.')[0] + ) + if interpreter.startswith('perl') or interpreter.startswith('ruby'): + self._extra_external_args.extend([ '-I', libpath ]) + elif interpreter.startswith('java'): + self._extra_external_args.extend([ '-cp', libpath ]) + + if ' ' in transform_name: + raise ValueError('Transform name %s cannot have spaces.' % repr(transform_name)) + elif not is_resource: + self._extra_external_args.append(transform_name) + else: + self._extra_external_args.append( + external_resource( + transform_name, + '%s.resources.external' % modulecallee().__name__.split('.')[0] + ) + ) + + if isinstance(transform_args, basestring): + self._extra_external_args = split('\s+', transform_args) + else: + self._extra_external_args.extend(transform_args) + + def __call__(self, request, request_xml): + args = [request.value] + if isinstance(request.params, list) and request.params: + args.extend(request.params) + if request.fields: + args.append('#'.join(['%s=%s' % (k, v) for k, v in request.fields.iteritems()])) + if isinstance(request_xml, basestring): + p = Popen(self._extra_external_args + list(args), stdin=PIPE, stdout=PIPE) + out, err = p.communicate(request_xml) + return out + execvp(self._extra_external_args[0], self._extra_external_args + list(args)) diff --git a/src/canari/resource.py b/src/canari/resource.py index af8d44a..1f890a1 100644 --- a/src/canari/resource.py +++ b/src/canari/resource.py @@ -1,14 +1,15 @@ #!/usr/bin/env python -from pkg_resources import resource_filename +from utils.stack import modulecallee +from pkg_resources import resource_filename __author__ = 'Nadeem Douba' __copyright__ = 'Copyright 2012, Canari Project' __credits__ = [] __license__ = 'GPL' -__version__ = '0.1' +__version__ = '0.2' __maintainer__ = 'Nadeem Douba' __email__ = 'ndouba@gmail.com' __status__ = 'Development' @@ -24,6 +25,11 @@ def imageicon(pkg, name): def imagepath(pkg, name): return '%s' % resource_filename(pkg, name) +def external_resource(name, pkg=None): + if pkg is None: + pkg = '%s.resources.external' % modulecallee().__name__.split('.')[0] + return resource_filename(pkg, name) + # etc conf = resource_filename(etc, 'canari.conf') \ No newline at end of file diff --git a/src/canari/utils/stack.py b/src/canari/utils/stack.py new file mode 100644 index 0000000..2c38987 --- /dev/null +++ b/src/canari/utils/stack.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +from inspect import stack, getmodule + +__author__ = 'Nadeem Douba' +__copyright__ = 'Copyright 2012, Canari Project' +__credits__ = [] + +__license__ = 'GPL' +__version__ = '0.1' +__maintainer__ = 'Nadeem Douba' +__email__ = 'ndouba@gmail.com' +__status__ = 'Development' + +__all__ = [ + 'modulecallee' +] + +def modulecallee(atframe=2): + frame = stack()[atframe] + return getmodule(frame[0]) \ No newline at end of file -- 2.45.1