├── .canari ├── .gitignore ├── README.md ├── maltego └── mtz2py.py ├── setup.py └── src └── Malformity ├── __init__.py ├── resources ├── __init__.py ├── etc │ ├── Malformity.conf │ └── __init__.py ├── images │ └── __init__.py └── maltego │ ├── __init__.py │ └── entities.mtz └── transforms ├── Shadowserver_AVScan.py ├── __init__.py ├── bit9_hashdetails.py ├── common ├── __init__.py ├── bit9.py ├── entities.py ├── isc.py ├── malc0de.py ├── malwr.py ├── pdns.py ├── robtex.py ├── threatexpert.py ├── vicheck.py ├── vt.py └── whois.py ├── cymru_hashcheck.py ├── isc_asreport.py ├── isc_ipreport.py ├── malc0de_hash2as.py ├── malc0de_hash2url.py ├── malc0de_hashsearch.py ├── malc0de_ip2as.py ├── malc0de_ip2url.py ├── malc0de_ipsearch.py ├── pDNS_Domain2IP.py ├── pDNS_IP2Domain.py ├── pDNS_NS2Domains.py ├── pDNS_OtherRRset.py ├── pDNS_wildcardsearch.py ├── robtex_getSubdomains.py ├── robtex_ip2domains.py ├── threatexpert_hash2dhash.py ├── threatexpert_hash2domain.py ├── threatexpert_hash2hiddenproc.py ├── threatexpert_hash2ip.py ├── threatexpert_hash2mutex.py ├── threatexpert_hash2url.py ├── vicheck_filesearch.py ├── vicheck_hash2dhash.py ├── vicheck_hash2domain.py ├── vicheck_hash2filename.py ├── vicheck_hash2mutex.py ├── vicheck_hash2registry.py ├── vt_api_domain2ip.py ├── vt_api_ip2domain.py ├── vt_domain2ip.py ├── vt_hash2exiftool.py ├── vt_hash2filenames.py ├── vt_hash2name.py ├── vt_hash2packer.py ├── vt_hash2timestamp.py ├── vt_ip2domain.py ├── vt_priv_domain2hash.py ├── vt_priv_hash2exiftool.py ├── vt_priv_hash2netactivity.py ├── vt_priv_hash2pesig.py ├── vt_priv_ip2hash.py └── vt_url2engine.py /.canari: -------------------------------------------------------------------------------- 1 | [metadata] 2 | 3 | author = Keith Gilbert - @digital4rensics 4 | project = Malformity 5 | maintainer = Keith Gilbert - @digital4rensics 6 | email = Keith@digital4rensics.com -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | .swp 3 | .DS_Store 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Packages 9 | *.egg 10 | *.egg-info 11 | dist 12 | build 13 | eggs 14 | parts 15 | bin 16 | var 17 | sdist 18 | develop-eggs 19 | .installed.cfg 20 | lib 21 | lib64 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | 31 | # Translations 32 | *.mo 33 | 34 | # Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | 39 | *.conf 40 | src/Malformity/resources/etc/Malformity.conf 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Malformity 2 | ========== 3 | 4 | ## 1.0 Introduction 5 | 6 | Malformity is a Maltego project based upon the [Canari Framework](https://github.com/allfro/canari). 7 | Using this framework greatly simplifies the process of installing local transforms in [Maltego](http://paterva.com/). 8 | 9 | The project directory structure is as follows: 10 | 11 | * `src/Malformity` directory is where all your stuff goes in terms of auxiliary modules that you may need for your 12 | modules 13 | * `src/Malformity/transforms` directory is where all your transform modules should be placed. 14 | * `src/Malformity/transforms/common` directory is where you can put some common code for your transforms like result 15 | parsing, entities, etc. 16 | * `src/Malformity/transforms/common/entities.py` is where you define your custom entities. 17 | * `maltego/` is where you can store your Maltego entity exports. 18 | 19 | If you're going to add a new transform in the transforms directory, remember to update the `__all__` variable in 20 | `src/Malformity/transforms/__init__.py`. Otherwise, `canari install-package` won't attempt to install the transform. 21 | Alternatively, `canari create-transform ` can be used within the `src/Malformity/transforms` directory 22 | to generate a transform module and have it automatically added to the `__init__.py` file. 23 | 24 | ## 2.0 Installing Malformity 25 | 26 | ### 2.1 - Supported Platforms 27 | Malformity has been tested on Mac OSX. Transforms are written in Python version 2.7. 28 | 29 | ### 2.2 - Requirements 30 | In order to make full use of Malformity, the setup script will download additional modules. 31 | 32 | If for some reason these fail, requirements are: 33 | * Canari 0.9 34 | * Mechanize 0.2.5 35 | * BeautifulSoup 3.2.1 36 | * requests 1.2.0 37 | 38 | ### 2.3 - Installation 39 | ```bash 40 | $ sudo python setup.py install 41 | ``` 42 | 43 | After completing setup, the command below can be used to install Malformity in Maltego. 44 | 45 | ```bash 46 | $ canari install-package Malformity 47 | ``` 48 | For Tungsten users: 49 | ```bash 50 | $ canari create-profile Malformity 51 | ``` 52 | This will create a .mtz in the working directory, which can then be imported in to Maltego 53 | 54 | ## 3.0 Credits 55 | Special thanks is due to the following people: 56 | 57 | * Nadeem Douba - For creating the Canari framework and offering great support 58 | * [ohdae](https://github.com/ohdae) - For allowing us to include his entity set in Malformity 59 | 60 | # Contact 61 | 62 | [@digital4rensics](https://twitter.com/Digital4rensics) - www.digital4rensics.com - Keith@digital4rensics.com 63 | -------------------------------------------------------------------------------- /maltego/mtz2py.py: -------------------------------------------------------------------------------- 1 | __author__ = 'ndouba' 2 | 3 | # What: A fast track script to convert Maltego entities into canari class files. 4 | # Howto: Export your entities into a mtz file and then run this script against it. 5 | 6 | 7 | from xml.etree.cElementTree import XML 8 | from zipfile import ZipFile 9 | from re import sub 10 | from sys import argv 11 | 12 | zip = ZipFile(argv[1]) 13 | entities = filter(lambda x: x.endswith('.entity'), zip.namelist()) 14 | 15 | 16 | def normalize_fn(fn): 17 | # Get rid of starting underscores or numbers and bad chars for var names in python 18 | return sub(r'[^A-Za-z0-9]', '', sub(r'^[^A-Za-z]+', '', fn)) 19 | 20 | 21 | nses = dict() 22 | 23 | for e in entities: 24 | xml = XML(zip.open(e).read()) 25 | id_ = xml.get('id') 26 | 27 | ens = id_.split('.') 28 | 29 | base_classname = None 30 | namespace = '.'.join(ens[:-1]) 31 | name = ens[-1] 32 | classname = name 33 | 34 | if namespace not in nses: 35 | base_classname = '%sEntity' % (''.join([ n.title() for n in ens[:-1] ])) 36 | nses[namespace] = base_classname 37 | 38 | print 'class %s(Entity):\n namespace = %s\n\n' % (base_classname, repr(namespace)) 39 | else: 40 | base_classname = nses[namespace] 41 | 42 | 43 | for f in xml.findall('Properties/Fields/Field'): 44 | fields = [ 45 | 'name=%s' % repr(f.get('name')), 46 | 'propname=%s' % repr(normalize_fn(f.get('name'))), 47 | 'displayname=%s' % repr(f.get('displayName')) 48 | 49 | ] 50 | print '@EntityField(%s)' % ', '.join(fields) 51 | 52 | print 'class %s(%s):\n pass\n\n' % (classname, base_classname) -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='Malformity', 5 | author='Keith Gilbert - @digital4rensics', 6 | version='1.0', 7 | author_email='Keith@digital4rensics.com', 8 | description='This project is a collection of transforms and entities to assist in Malware and Malicious Infrastructure research.', 9 | license='GPL', 10 | packages=find_packages('src'), 11 | package_dir={ '' : 'src' }, 12 | zip_safe=False, 13 | package_data={ 14 | '' : [ '*.gif', '*.png', '*.conf', '*.mtz' ] # list of resources 15 | }, 16 | install_requires=[ 17 | 'canari==1.0', 18 | 'mechanize==0.2.5', 19 | 'BeautifulSoup==3.2.1', 20 | 'requests==1.2.0' 21 | ], 22 | dependency_links=[ 23 | # custom links for the install_requires 24 | ] 25 | ) 26 | -------------------------------------------------------------------------------- /src/Malformity/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'Keith Gilbert - @digital4rensics' 4 | __copyright__ = 'Copyright 2012, Malformity Project' 5 | __credits__ = [] 6 | 7 | __license__ = 'GPL' 8 | __version__ = '0.1' 9 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 10 | __email__ = 'Keith@digital4rensics.com' 11 | __status__ = 'Development' 12 | __all__ = [ 13 | 'resources', 14 | 'transforms' 15 | ] -------------------------------------------------------------------------------- /src/Malformity/resources/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'Keith Gilbert - @digital4rensics' 4 | __copyright__ = 'Copyright 2012, Malformity Project' 5 | __credits__ = [] 6 | 7 | __license__ = 'GPL' 8 | __version__ = '0.1' 9 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 10 | __email__ = 'Keith@digital4rensics.com' 11 | __status__ = 'Development' 12 | __all__ = [ 13 | 'etc', 14 | 'images' 15 | ] -------------------------------------------------------------------------------- /src/Malformity/resources/etc/Malformity.conf: -------------------------------------------------------------------------------- 1 | [pDNS] 2 | apikey = 3 | 4 | [virustotal] 5 | apikey = 6 | privkey = 7 | 8 | [bit9] 9 | username = 10 | password = 11 | 12 | [metascan] 13 | apikey = -------------------------------------------------------------------------------- /src/Malformity/resources/etc/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'Keith Gilbert - @digital4rensics' 4 | __copyright__ = 'Copyright 2012, Malformity Project' 5 | __credits__ = [] 6 | 7 | __license__ = 'GPL' 8 | __version__ = '0.1' 9 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 10 | __email__ = 'Keith@digital4rensics.com' 11 | __status__ = 'Development' -------------------------------------------------------------------------------- /src/Malformity/resources/images/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'Keith Gilbert - @digital4rensics' 4 | __copyright__ = 'Copyright 2012, Malformity Project' 5 | __credits__ = [] 6 | 7 | __license__ = 'GPL' 8 | __version__ = '0.1' 9 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 10 | __email__ = 'Keith@digital4rensics.com' 11 | __status__ = 'Development' -------------------------------------------------------------------------------- /src/Malformity/resources/maltego/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'Keith Gilbert - @digital4rensics' 4 | __copyright__ = 'Copyright 2012, Malformity Project' 5 | __credits__ = [] 6 | 7 | __license__ = 'GPL' 8 | __version__ = '0.1' 9 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 10 | __email__ = 'Keith@digital4rensics.com' 11 | __status__ = 'Development' -------------------------------------------------------------------------------- /src/Malformity/resources/maltego/entities.mtz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/digital4rensics/Malformity/2af44721c566e148672d0e4153ffb65404c9f1ca/src/Malformity/resources/maltego/entities.mtz -------------------------------------------------------------------------------- /src/Malformity/transforms/Shadowserver_AVScan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import urllib2 5 | import json 6 | from canari.maltego.utils import debug, progress 7 | from canari.maltego.message import Field 8 | from canari.framework import configure #, superuser 9 | from common.entities import Hash 10 | 11 | __license__ = 'GPL' 12 | __version__ = '0.1' 13 | __maintainer__ = 'Ned Moran' 14 | __email__ = 'ned@shadowserver.org' 15 | __status__ = 'Development' 16 | 17 | __all__ = [ 18 | 'dotransform', 19 | ] 20 | 21 | #@superuser 22 | @configure( 23 | label='AV Scan - Shadowserver', 24 | description='AV Scan - Shadowserver', 25 | uuids=[ 'malformity.v1.Shadowserver_AVScan' ], 26 | inputs=[ ('Shadowserver', Hash)], 27 | debug=True 28 | ) 29 | 30 | def dotransform(request, response): 31 | # Report transform progress 32 | progress(50) 33 | hash = request.value 34 | total="" 35 | 36 | try: 37 | e = Hash(hash) 38 | text = '' 39 | resp = urllib2.urlopen('https://innocuous.shadowserver.org/api/?query=' + hash).read() 40 | start_results = resp.find("{") 41 | end_results = resp.find("}") 42 | av_results = resp[start_results+1:end_results].replace('"','') 43 | text += av_results + ',' 44 | e += Field('AV Name', text, displayname='AV Name') 45 | response += e 46 | except IOError: 47 | print 'IO Error' 48 | 49 | # Update progress 50 | progress(100) 51 | 52 | # Return response for visualization 53 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'Keith Gilbert - @digital4rensics' 4 | __copyright__ = 'Copyright 2012, Malformity Project' 5 | __credits__ = [] 6 | 7 | __license__ = 'GPL' 8 | __version__ = '0.1' 9 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 10 | __email__ = 'Keith@digital4rensics.com' 11 | __status__ = 'Development' 12 | __all__ = [ 13 | 'robtex_getSubdomains', 14 | 'robtex_ip2domains', 15 | #'metascan_hashcheck', 16 | 'threatexpert_hash2domain', 17 | 'Shadowserver_AVScan', 18 | 'malc0de_hash2as', 19 | 'malc0de_hash2url', 20 | 'malc0de_ip2as', 21 | 'malc0de_ip2url', 22 | 'malc0de_hashsearch', 23 | 'malc0de_ipsearch', 24 | 'vt_hash2exiftool', 25 | 'vt_priv_hash2exiftool', 26 | 'vt_priv_hash2pesig', 27 | 'vt_priv_hash2netactivity', 28 | 'vt_priv_ip2hash', 29 | 'vt_priv_domain2hash', 30 | 'threatexpert_hash2url', 31 | 'vt_domain2ip', 32 | 'vt_ip2domain', 33 | 'cymru_hashcheck', 34 | 'isc_asreport', 35 | 'isc_ipreport', 36 | 'pDNS_NS2Domains', 37 | 'pDNS_wildcardsearch', 38 | 'bit9_hashdetails', 39 | 'vt_hash2filenames', 40 | 'vt_hash2packer', 41 | 'vt_hash2timestamp', 42 | 'pDNS_OtherRRset', 43 | 'vt_url2engine', 44 | 'vt_hash2name', 45 | 'vicheck_filesearch', 46 | 'vicheck_hash2filename', 47 | 'vicheck_hash2dhash', 48 | 'vicheck_hash2domain', 49 | 'vicheck_hash2registry', 50 | 'vicheck_hash2mutex', 51 | 'pDNS_Domain2IP', 52 | 'pDNS_IP2Domain', 53 | 'threatexpert_hash2hiddenproc', 54 | 'threatexpert_hash2dhash', 55 | 'threatexpert_hash2mutex', 56 | 'common', 57 | 'threatexpert_hash2ip' 58 | ] 59 | -------------------------------------------------------------------------------- /src/Malformity/transforms/bit9_hashdetails.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | NOTE: This transform is currently inefficient due to the need to login for every request. 5 | It is suggested that you don't execute the transform on a large group of hashes. 6 | """ 7 | 8 | from BeautifulSoup import BeautifulSoup 9 | from canari.maltego.utils import debug, progress 10 | from canari.framework import configure #, superuser 11 | from common.entities import Hash, Filename 12 | from canari.maltego.entities import Phrase 13 | from common.bit9 import loginSearch 14 | 15 | __author__ = 'Keith Gilbert - @digital4rensics' 16 | __copyright__ = 'Copyright 2013, Malformity Project' 17 | __credits__ = [] 18 | 19 | __license__ = 'GPL' 20 | __version__ = '0.1' 21 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 22 | __email__ = 'Keith@digital4rensics.com' 23 | __status__ = 'Development' 24 | 25 | __all__ = [ 26 | 'dotransform', 27 | ] 28 | 29 | #@superuser 30 | @configure( 31 | label='Hash Details - Bit9', 32 | description='Returns details of a hash from Bit9 FileAdvisor', 33 | uuids=[ 'malformity.v1.Bit9_HashDetails' ], 34 | inputs=[ ( 'Bit9', Hash ) ], 35 | debug=True 36 | ) 37 | 38 | def dotransform(request, response): 39 | page = loginSearch(request.value) 40 | results = BeautifulSoup(page) 41 | 42 | try: 43 | name = results.find('td', {'class' : 'FourColumns_Column_2'}).text 44 | response += Filename(name) 45 | 46 | desc = results.find('td', {'class' : 'FourColumns_Column_4'}).text 47 | response += Phrase(desc) 48 | 49 | result = results.find('td', {'bgcolor' : '#eaffea'}).text 50 | response += Phrase(result) 51 | except: 52 | #no results 53 | pass 54 | 55 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/common/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'Keith Gilbert - @digital4rensics' 4 | __copyright__ = 'Copyright 2012, Malformity Project' 5 | __credits__ = [] 6 | 7 | __license__ = 'GPL' 8 | __version__ = '0.1' 9 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 10 | __email__ = 'Keith@digital4rensics.com' 11 | __status__ = 'Development' 12 | __all__ = [ 13 | 'bit9', 14 | 'entities', 15 | 'malwr', 16 | 'pdns', 17 | 'threatexpert', 18 | 'vicheck', 19 | 'vt', 20 | 'isc', 21 | 'whois', 22 | 'malc0de', 23 | 'robtex' 24 | ] -------------------------------------------------------------------------------- /src/Malformity/transforms/common/bit9.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import mechanize 4 | from canari.framework import configure #, superuser 5 | from canari.config import config 6 | from canari.maltego.message import MaltegoException 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2013, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'build', 20 | ] 21 | 22 | def loginSearch(hash): 23 | url = 'https://fileadvisor.bit9.com/Services/login.aspx' 24 | ua = [('User-agent','Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)')] 25 | 26 | browse = mechanize.Browser() 27 | browse.addheaders = ua 28 | browse.open(url) 29 | browse.select_form("aspnetForm") 30 | browse.set_all_readonly(False) 31 | 32 | un = config['bit9/username'] 33 | pw = config['bit9/password'] 34 | if un == "" or pw == "": 35 | raise MaltegoException("Please specify Username and Password in config") 36 | 37 | browse["__EVENTTARGET"] = "" 38 | browse["__EVENTARGUMENT"]= "" 39 | browse["ctl00$ColumnBody$TextBox_UserName"] = un 40 | browse["ctl00$ColumnBody$TextBox_Password"] = pw 41 | 42 | browse.submit(name="ctl00$ColumnBody$Button_Submit") 43 | 44 | browse.select_form("aspnetForm") 45 | browse.set_all_readonly(False) 46 | 47 | browse["__EVENTTARGET"] = "" 48 | browse["__EVENTARGUMENT"]= "" 49 | browse["ctl00$ColumnBody$RadComboBox1_input"] = hash 50 | browse["submitbt"] = "Search »" 51 | 52 | results = browse.submit() 53 | return results.read() -------------------------------------------------------------------------------- /src/Malformity/transforms/common/entities.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.message import Entity, EntityField, EntityFieldType, MatchingRule 4 | 5 | __author__ = 'Keith Gilbert - @digital4rensics' 6 | __copyright__ = 'Copyright 2012, Malformity Project' 7 | __credits__ = ['Special thanks to Ohdae for the original entity creation. https://github.com/ohdae'] 8 | 9 | __license__ = 'GPL' 10 | __version__ = '0.1' 11 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 12 | __email__ = 'Keith@digital4rensics.com' 13 | __status__ = 'Development' 14 | 15 | __all__ = [ 16 | 'MalformityEntity', 17 | # 'MyMalformityEntity', 18 | # 'InsiderThreat', 19 | # 'AdvancedTargetedAttacker', 20 | # 'OpportunityAttacker', 21 | # 'OrganizedCrime', 22 | # 'ZombieHost', 23 | # 'CompromisedHost', 24 | # 'BotnetDNSNode', 25 | # 'C2', 26 | 'ServiceName', 27 | 'Hash', 28 | # 'FilePath', 29 | # 'HiddenFile', 30 | 'RegistryEntry', 31 | # 'UserAccount', 32 | 'MaliciousProcess', 33 | # 'BrowserCookie', 34 | 'HTTPRequest', 35 | 'Filename', 36 | # 'MaliciousWebsite', 37 | # 'Certificate', 38 | # 'Exploit', 39 | # 'ExploitationChain', 40 | # 'Phishing', 41 | 'UserAgent' 42 | ] 43 | 44 | """ 45 | DO NOT EDIT: 46 | The following entity is the base entity type from which all your entities will inherit from. This provides you with the 47 | default namespace that all your entities will use for their unique entity type in Maltego. For example, MyMalformityEntity will 48 | have an entity type name of Malformity.MyMalformityEntity. When adding a new entity in Maltego, you will have to specify this 49 | name (Malformity.MyMalformityEntity) in the 'Unique entity type' field. 50 | """ 51 | class MalformityEntity(Entity): 52 | _namespace_ = 'malformity' 53 | 54 | 55 | """ 56 | You can specify as many entity fields as you want by just adding an extra @EntityField() decorator to your entities. The 57 | @EntityField() decorator takes the following parameters: 58 | - name: the name of the field without spaces or special characters except for dots ('.') (required) 59 | - propname: the name of the object's property used to get and set the value of the field (required, if name contains dots) 60 | - displayname: the name of the entity as it appears in Maltego (optional) 61 | - type: the data type of the field (optional, default: EntityFieldType.String) 62 | - required: whether or not the field's value must be set before sending back the message (optional, default: False) 63 | - choices: a list of acceptable field values for this field (optional) 64 | - matchingrule: whether or not the field should be loosely or strictly matched (optional, default: MatchingRule.Strict) 65 | - decorator: a function that is invoked each and everytime the field's value is set or changed. 66 | TODO: define as many custom fields and entity types as you wish:) 67 | """ 68 | #@EntityField(name='Malformity.fieldN', propname='fieldN', displayname='Field N', matchingrule=MatchingRule.Loose) 69 | #@EntityField(name='Malformity.field1', propname='field1', displayname='Field 1', type=EntityFieldType.Integer) 70 | #class MyMalformityEntity(MalformityEntity): 71 | # """ 72 | # Uncomment the line below and comment out the pass if you wish to define a ridiculous entity type name like 73 | # 'my.fancy.EntityType' 74 | # """ 75 | # # name = my.fancy.EntityType 76 | # pass 77 | 78 | #@EntityField(name='malformity.insiderthreat', propname='propertiesinsiderthreat', displayname='Insider Threat') 79 | #class InsiderThreat(MalformityEntity): 80 | # pass 81 | 82 | 83 | #@EntityField(name='malformity.advancedtargetedattacker', propname='propertiesadvancedtargetedattacker', displayname='Advanced Targeted Attacker') 84 | #class AdvancedTargetedAttacker(MalformityEntity): 85 | # pass 86 | 87 | 88 | #@EntityField(name='malformity.opportunityattacker', propname='propertiesopportunityattacker', displayname='Opportunity Attacker') 89 | #class OpportunityAttacker(MalformityEntity): 90 | # pass 91 | 92 | 93 | #@EntityField(name='malformity.organizedcrime', propname='propertiesorganizedcrime', displayname='Organized Crime') 94 | #class OrganizedCrime(MalformityEntity): 95 | # pass 96 | 97 | 98 | #@EntityField(name='malformity.zombie', propname='propertieszombie', displayname='Zombie') 99 | #class ZombieHost(MalformityEntity): 100 | # pass 101 | 102 | 103 | #@EntityField(name='malformity.compromisedhost', propname='propertiescompromisedhost', displayname='Compromised Host') 104 | #class CompromisedHost(MalformityEntity): 105 | # pass 106 | 107 | 108 | #@EntityField(name='malformity.botnetdnsrelay', propname='propertiesbotnetdnsrelay', displayname='Botnet DNS Relay') 109 | #class BotnetDNSNode(MalformityEntity): 110 | # pass 111 | 112 | 113 | #@EntityField(name='malformity.c2', propname='propertiesc2', displayname='C2') 114 | #class C2(MalformityEntity): 115 | # pass 116 | 117 | 118 | @EntityField(name='properties.servicename', propname='servicename', displayname='Service Name') 119 | class ServiceName(MalformityEntity): 120 | pass 121 | 122 | 123 | @EntityField(name='properties.hash', propname='hash', displayname='Hash') 124 | class Hash(MalformityEntity): 125 | pass 126 | 127 | 128 | #@EntityField(name='malformity.filepath', propname='propertiesfilepath', displayname='File Path') 129 | #class FilePath(MalformityEntity): 130 | # pass 131 | 132 | 133 | #@EntityField(name='malformity.hiddenfile', propname='propertieshiddenfile', displayname='Hidden File') 134 | #class HiddenFile(MalformityEntity): 135 | # pass 136 | 137 | 138 | @EntityField(name='properties.registryentry', propname='registryentry', displayname='Registry Entry') 139 | class RegistryEntry(MalformityEntity): 140 | pass 141 | 142 | 143 | #@EntityField(name='malformity.useraccount', propname='propertiesuseraccount', displayname='User Account') 144 | #class UserAccount(MalformityEntity): 145 | # pass 146 | 147 | 148 | @EntityField(name='properties.maliciousprocess', propname='maliciousprocess', displayname='Malicious Process') 149 | class MaliciousProcess(MalformityEntity): 150 | pass 151 | 152 | 153 | #@EntityField(name='malformity.browsercookie', propname='propertiesbrowsercookie', displayname='Browser Cookie') 154 | #class BrowserCookie(MalformityEntity): 155 | # pass 156 | 157 | 158 | @EntityField(name='properties.httprequest', propname='httprequest', displayname='HTTP Request') 159 | class HTTPRequest(MalformityEntity): 160 | pass 161 | 162 | 163 | @EntityField(name='properties.filename', propname='filename', displayname='Filename') 164 | class Filename(MalformityEntity): 165 | pass 166 | 167 | 168 | #@EntityField(name='malformity.maliciouswebsite', propname='propertiesmaliciouswebsite', displayname='Malicious Host') 169 | #class MaliciousWebsite(MalformityEntity): 170 | # pass 171 | 172 | 173 | #@EntityField(name='malformity.certificate', propname='propertiescertificate', displayname='Certificate') 174 | #class Certificate(MalformityEntity): 175 | # pass 176 | 177 | 178 | #@EntityField(name='malformity.exploit', propname='propertiesexploit', displayname='Exploit') 179 | #class Exploit(MalformityEntity): 180 | # pass 181 | 182 | 183 | #@EntityField(name='malformity.exploitationchain', propname='propertiesexploitationchain', displayname='Exploitation Chain') 184 | #class ExploitationChain(MalformityEntity): 185 | # pass 186 | 187 | 188 | #@EntityField(name='malformity.phishing', propname='propertiesphishing', displayname='Phishing') 189 | #class Phishing(MalformityEntity): 190 | # pass 191 | 192 | 193 | @EntityField(name='properties.useragent', propname='useragent', displayname='User Agent') 194 | class UserAgent(MalformityEntity): 195 | pass 196 | -------------------------------------------------------------------------------- /src/Malformity/transforms/common/isc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import mechanize 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.framework import configure #, superuser 6 | from canari.maltego.message import MaltegoException 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2013, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'build', 20 | ] 21 | 22 | def build(ip): 23 | #Build request 24 | url = 'https://isc.sans.edu/ipdetails.html?ip=' + ip 25 | browser = mechanize.Browser() 26 | 27 | #Retrieve page and create BS entity if the page exists 28 | try: 29 | report = browser.open(url) 30 | html = report.read() 31 | page = BeautifulSoup(html) 32 | except: 33 | pass 34 | 35 | return page 36 | 37 | def buildas(asn): 38 | #Build request 39 | url = 'https://isc.sans.edu/asreport.html?as=' + asn 40 | browser = mechanize.Browser() 41 | 42 | #Retrieve page and create BS entity if the page exists 43 | try: 44 | report = browser.open(url) 45 | html = report.read() 46 | page = BeautifulSoup(html) 47 | except: 48 | pass 49 | 50 | return page -------------------------------------------------------------------------------- /src/Malformity/transforms/common/malc0de.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import mechanize 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.framework import configure #, superuser 6 | from canari.maltego.message import MaltegoException 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2013, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'build', 20 | ] 21 | 22 | def build(term): 23 | url = 'http://malc0de.com/database/index.php?&search=' + term 24 | browser = mechanize.Browser() 25 | 26 | #Retrieve page and create BS entity if the page exists 27 | try: 28 | report = browser.open(url) 29 | html = report.read() 30 | page = BeautifulSoup(html) 31 | except: 32 | raise MaltegoException("Report Not Found.") 33 | 34 | return page -------------------------------------------------------------------------------- /src/Malformity/transforms/common/malwr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import mechanize 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.framework import configure #, superuser 6 | from canari.maltego.message import MaltegoException 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2012, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'build', 20 | ] 21 | 22 | def build(hash): 23 | #Build request 24 | url = 'http://malwr.com/analysis/' + hash + '/' 25 | browser = mechanize.Browser() 26 | 27 | #Retrieve page and create BS entity if the page exists 28 | try: 29 | report = browser.open(url) 30 | html = report.read() 31 | page = BeautifulSoup(html) 32 | except: 33 | raise MaltegoException("Report Not Found.") 34 | 35 | return page -------------------------------------------------------------------------------- /src/Malformity/transforms/common/pdns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Original script authored by ISC, found here: https://www.farsightsecurity.com/Services/DNSDB/ 3 | # Modifications made by @digital4rensics for use in the Malformity project 4 | 5 | import json 6 | import optparse 7 | import os 8 | import sys 9 | import time 10 | import urllib2 11 | from cStringIO import StringIO 12 | from canari.config import config 13 | 14 | class DnsdbClient(object): 15 | def __init__(self, server, apikey): 16 | self.server = server 17 | self.apikey = apikey 18 | 19 | def query_rrset(self, oname, rrtype=None, bailiwick=None): 20 | if bailiwick: 21 | if not rrtype: 22 | rrtype = 'ANY' 23 | path = 'rrset/name/%s/%s/%s' % (oname, rrtype, bailiwick) 24 | elif rrtype: 25 | path = 'rrset/name/%s/%s' % (oname, rrtype) 26 | else: 27 | path = 'rrset/name/%s' % oname 28 | return self._query(path) 29 | 30 | def query_rdata_name(self, rdata_name, rrtype=None): 31 | if rrtype: 32 | path = 'rdata/name/%s/%s' % (rdata_name, rrtype) 33 | else: 34 | path = 'rdata/name/%s' % rdata_name 35 | return self._query(path) 36 | 37 | def query_rdata_ip(self, rdata_ip): 38 | path = 'rdata/ip/%s' % rdata_ip.replace('/', ',') 39 | return self._query(path) 40 | 41 | def _query(self, path): 42 | res = [] 43 | url = '%s/lookup/%s' % (self.server, path) 44 | #if limit != 0: 45 | #url += '?limit=%d' % lim 46 | req = urllib2.Request(url) 47 | req.add_header('Accept', 'application/json') 48 | req.add_header('X-Api-Key', self.apikey) 49 | try: 50 | http = urllib2.urlopen(req) 51 | while True: 52 | line = http.readline() 53 | if not line: 54 | break 55 | else: 56 | res.append(line) 57 | except urllib2.HTTPError, e: 58 | sys.stderr.write(str(e) + '\n') 59 | return res 60 | 61 | def query(opt, sub, lim, sor): 62 | #global cfg 63 | #global options 64 | #global limit 65 | #limit = lim 66 | 67 | DEFAULT_DNSDB_SERVER = 'https://api.dnsdb.info' 68 | 69 | options = None 70 | """ 71 | parser = optparse.OptionParser() 72 | parser.add_option('-r', '--rrset', dest='rrset', type='string', 73 | help='rrset [/[/BAILIWICK]]') 74 | parser.add_option('-n', '--rdataname', dest='rdata_name', type='string', 75 | help='rdata name [/]') 76 | parser.add_option('-i', '--rdataip', dest='rdata_ip', type='string', 77 | help='rdata ip ') 78 | parser.add_option('-s', '--sort', dest='sort', type='string', help='sort key') 79 | parser.add_option('-R', '--reverse', dest='reverse', action='store_true', default=False, 80 | help='reverse sort') 81 | parser.add_option('-j', '--json', dest='json', action='store_true', default=False, 82 | help='output in JSON format') 83 | parser.add_option('-l', '--limit', dest='limit', type='int', default=0, 84 | help='limit number of results') 85 | 86 | options, args = parser.parse_args() 87 | if args: 88 | parser.print_help() 89 | sys.exit(1) 90 | """ 91 | 92 | cfg = config['pDNS/apikey'] 93 | srv = DEFAULT_DNSDB_SERVER 94 | 95 | client = DnsdbClient(srv, cfg) 96 | if opt == '-r': 97 | res_list = client.query_rrset(sub) 98 | elif opt == '-n': 99 | res_list = client.query_rdata_name(*sub.split('/')) 100 | elif opt == '-i': 101 | res_list = client.query_rdata_ip(sub) 102 | else: 103 | parser.print_help() 104 | sys.exit(1) 105 | 106 | fmt_func = lambda x: x 107 | 108 | if len(res_list) > 0: 109 | if sor == 'y': 110 | if not sor in res_list[0]: 111 | sort_keys = res_list[0].keys() 112 | sort_keys.sort() 113 | sys.stderr.write('isc_dnsdb_query: invalid sort key "%s". valid sort keys are %s\n' % (sor, ', '.join(sort_keys))) 114 | sys.exit(1) 115 | res_list.sort(key=lambda r: r[sor], reverse=options.reverse) 116 | 117 | return res_list 118 | -------------------------------------------------------------------------------- /src/Malformity/transforms/common/robtex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import mechanize 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.framework import configure #, superuser 6 | from canari.maltego.message import MaltegoException 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2013, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'build', 20 | ] 21 | 22 | def build(ip): 23 | url = 'http://ip.robtex.com/' + ip + '.html' 24 | browser = mechanize.Browser() 25 | 26 | report = browser.open(url) 27 | html = report.read() 28 | page = BeautifulSoup(html) 29 | 30 | return page -------------------------------------------------------------------------------- /src/Malformity/transforms/common/threatexpert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import mechanize 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.framework import configure #, superuser 6 | from canari.maltego.message import MaltegoException 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2012, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'build', 20 | ] 21 | 22 | def build(hash): 23 | # Construct the request 24 | url = 'http://www.threatexpert.com/report.aspx?md5=' + hash 25 | browser = mechanize.Browser() 26 | 27 | # Retrieve the page and construct BS entity if it exists 28 | try: 29 | report = browser.open(url) 30 | html = report.read() 31 | page = BeautifulSoup(html) 32 | except: 33 | raise MaltegoException("Report Not Found.") 34 | 35 | return page -------------------------------------------------------------------------------- /src/Malformity/transforms/common/vicheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import mechanize 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.framework import configure 6 | from canari.maltego.message import MaltegoException 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2012, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'build', 20 | ] 21 | 22 | def build(data, type): 23 | #Build Request based on type 24 | if type == 'hash': 25 | url = 'https://vicheck.ca/md5query.php?hash=' + data 26 | elif type == 'mutex': 27 | url = 'https://vicheck.ca/searchsb.php?mutex=' + data 28 | elif type == 'network': 29 | url = 'https://www.vicheck.ca/searchsb.php?server=' + data 30 | elif type == 'name': 31 | url = 'https://www.vicheck.ca/searchsb.php?filename=' + data 32 | else: 33 | raise MaltegoException("No type given") 34 | 35 | browser = mechanize.Browser() 36 | 37 | #Retrieve page and create BS entity 38 | try: 39 | report = browser.open(url) 40 | html = report.read() 41 | page = BeautifulSoup(html) 42 | except: 43 | raise MaltegoException("Report Not Found.") 44 | 45 | return page -------------------------------------------------------------------------------- /src/Malformity/transforms/common/vt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import mechanize 5 | import requests 6 | from BeautifulSoup import BeautifulSoup 7 | from canari.framework import configure 8 | from canari.config import config 9 | from canari.maltego.message import MaltegoException 10 | 11 | __author__ = 'Keith Gilbert - @digital4rensics' 12 | __copyright__ = 'Copyright 2013, Malformity Project' 13 | __credits__ = [] 14 | 15 | __license__ = 'GPL' 16 | __version__ = '0.3' 17 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 18 | __email__ = 'Keith@digital4rensics.com' 19 | __status__ = 'Development' 20 | 21 | __all__ = [ 22 | 'build', 23 | ] 24 | 25 | def build(hash): 26 | url = 'https://www.virustotal.com/en/file/' + hash + '/analysis/' 27 | 28 | browser = mechanize.Browser() 29 | browser.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36')] 30 | 31 | # Retrieve the page and construct BS entity if it exists 32 | try: 33 | report = browser.open(url) 34 | html = report.read() 35 | page = BeautifulSoup(html) 36 | except: 37 | raise MaltegoException("Report Not Found.") 38 | 39 | return page 40 | 41 | 42 | def bsearch(term): 43 | privkey = config['virustotal/privkey'] 44 | params = {'apikey': privkey, 'query': 'behaviour:'+term} 45 | response = requests.get('https://www.virustotal.com/vtapi/v2/file/search', params=params, verify=False) 46 | try: 47 | json_response = response.json() 48 | return json_response 49 | except: 50 | return None 51 | 52 | def getbehavior(hash): 53 | privkey = config['virustotal/privkey'] 54 | params = {'apikey' : privkey, 'hash' : hash} 55 | response = requests.get('https://www.virustotal.com/vtapi/v2/file/behaviour', params=params, verify=False) 56 | try: 57 | json_response = response.json() 58 | return json_response 59 | except: 60 | return None 61 | 62 | def getreport(hash): 63 | privkey = config['virustotal/privkey'] 64 | params = {'apikey': privkey, 'resource': hash, 'allinfo' : 1} 65 | response = requests.get('https://www.virustotal.com/vtapi/v2/file/report', params=params, verify=False) 66 | try: 67 | json_response = response.json() 68 | return json_response 69 | except: 70 | return None -------------------------------------------------------------------------------- /src/Malformity/transforms/common/whois.py: -------------------------------------------------------------------------------- 1 | ## {{{ http://code.activestate.com/recipes/577364/ (r6) 2 | """ 3 | Whois client for python 4 | 5 | transliteration of: 6 | http://www.opensource.apple.com/source/adv_cmds/adv_cmds-138.1/whois/whois.c 7 | 8 | Copyright (c) 2010 Chris Wolf 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | 28 | Last edited by: $Author$ 29 | on: $DateTime$ 30 | Revision: $Revision$ 31 | Id: $Id$ 32 | Author: Chris Wolf 33 | """ 34 | import sys 35 | import socket 36 | #import optparse 37 | #import pdb 38 | 39 | """ 40 | class NICClient(object) : 41 | 42 | ABUSEHOST = "whois.abuse.net" 43 | NICHOST = "whois.crsnic.net" 44 | INICHOST = "whois.networksolutions.com" 45 | DNICHOST = "whois.nic.mil" 46 | GNICHOST = "whois.nic.gov" 47 | ANICHOST = "whois.arin.net" 48 | LNICHOST = "whois.lacnic.net" 49 | RNICHOST = "whois.ripe.net" 50 | PNICHOST = "whois.apnic.net" 51 | MNICHOST = "whois.ra.net" 52 | QNICHOST_TAIL = ".whois-servers.net" 53 | SNICHOST = "whois.6bone.net" 54 | BNICHOST = "whois.registro.br" 55 | NORIDHOST = "whois.norid.no" 56 | IANAHOST = "whois.iana.org" 57 | GERMNICHOST = "de.whois-servers.net" 58 | DEFAULT_PORT = "nicname" 59 | WHOIS_SERVER_ID = "Whois Server:" 60 | WHOIS_ORG_SERVER_ID = "Registrant Street1:Whois Server:" 61 | 62 | 63 | WHOIS_RECURSE = 0x01 64 | WHOIS_QUICK = 0x02 65 | 66 | ip_whois = [ LNICHOST, RNICHOST, PNICHOST, BNICHOST ] 67 | 68 | def __init__(self) : 69 | self.use_qnichost = False 70 | 71 | def findwhois_server(self, buf, hostname): 72 | """"""Search the initial TLD lookup results for the regional-specifc 73 | whois server for getting contact details.""" 74 | """ 75 | nhost = None 76 | parts_index = 1 77 | start = buf.find(NICClient.WHOIS_SERVER_ID) 78 | if (start == -1): 79 | start = buf.find(NICClient.WHOIS_ORG_SERVER_ID) 80 | parts_index = 2 81 | 82 | if (start > -1): 83 | end = buf[start:].find('\n') 84 | whois_line = buf[start:end+start] 85 | whois_parts = whois_line.split(':') 86 | nhost = whois_parts[parts_index].strip() 87 | elif (hostname == NICClient.ANICHOST): 88 | for nichost in NICClient.ip_whois: 89 | if (buf.find(nichost) != -1): 90 | nhost = nichost 91 | break 92 | return nhost 93 | """ 94 | def whois(query, hostname): 95 | """Perform initial lookup with TLD whois server 96 | then, if the quick flag is false, search that result 97 | for the region-specifc whois server and do a lookup 98 | there for contact details 99 | """ 100 | #pdb.set_trace() 101 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 102 | s.connect((hostname, 43)) 103 | # if (hostname == NICClient.GERMNICHOST): 104 | # s.send("-T dn,ace -C US-ASCII " + query + "\r\n") 105 | # else: 106 | s.send(query + "\r\n") 107 | response = '' 108 | while True: 109 | d = s.recv(4096) 110 | response += d 111 | if not d: 112 | break 113 | s.close() 114 | #pdb.set_trace() 115 | # nhost = None 116 | # if (flags & NICClient.WHOIS_RECURSE and nhost == None): 117 | # nhost = self.findwhois_server(response, hostname) 118 | # if (nhost != None): 119 | # response += self.whois(query, nhost, 0) 120 | return response 121 | """ 122 | def choose_server(self, domain): 123 | """"""Choose initial lookup NIC host"""""" 124 | if (domain.endswith("-NORID")): 125 | return NICClient.NORIDHOST 126 | pos = domain.rfind('.') 127 | if (pos == -1): 128 | return None 129 | tld = domain[pos+1:] 130 | if (tld[0].isdigit()): 131 | return NICClient.ANICHOST 132 | 133 | return tld + NICClient.QNICHOST_TAIL 134 | 135 | def whois_lookup(self, options, query_arg, flags): 136 | """"""Main entry point: Perform initial lookup on TLD whois server, 137 | or other server to get region-specific whois server, then if quick 138 | flag is false, perform a second lookup on the region-specific 139 | server for contact records"""""" 140 | nichost = None 141 | #pdb.set_trace() 142 | # this would be the case when this function is called by other then main 143 | if (options == None): 144 | options = {} 145 | 146 | if ( (not options.has_key('whoishost') or options['whoishost'] == None) 147 | and (not options.has_key('country') or options['country'] == None)): 148 | self.use_qnichost = True 149 | options['whoishost'] = NICClient.NICHOST 150 | if ( not (flags & NICClient.WHOIS_QUICK)): 151 | flags |= NICClient.WHOIS_RECURSE 152 | 153 | if (options.has_key('country') and options['country'] != None): 154 | result = self.whois(query_arg, options['country'] + NICClient.QNICHOST_TAIL, flags) 155 | elif (self.use_qnichost): 156 | nichost = self.choose_server(query_arg) 157 | if (nichost != None): 158 | result = self.whois(query_arg, nichost, flags) 159 | else: 160 | result = self.whois(query_arg, options['whoishost'], flags) 161 | 162 | return result 163 | #---- END OF NICClient class def --------------------- 164 | 165 | def parse_command_line(argv): 166 | """"""Options handling mostly follows the UNIX whois(1) man page, except 167 | long-form options can also be used."""""" 168 | flags = 0 169 | 170 | usage = "usage: %prog [options] name" 171 | 172 | parser = optparse.OptionParser(add_help_option=False, usage=usage) 173 | parser.add_option("-a", "--arin", action="store_const", 174 | const=NICClient.ANICHOST, dest="whoishost", 175 | help="Lookup using host " + NICClient.ANICHOST) 176 | parser.add_option("-A", "--apnic", action="store_const", 177 | const=NICClient.PNICHOST, dest="whoishost", 178 | help="Lookup using host " + NICClient.PNICHOST) 179 | parser.add_option("-b", "--abuse", action="store_const", 180 | const=NICClient.ABUSEHOST, dest="whoishost", 181 | help="Lookup using host " + NICClient.ABUSEHOST) 182 | parser.add_option("-c", "--country", action="store", 183 | type="string", dest="country", 184 | help="Lookup using country-specific NIC") 185 | parser.add_option("-d", "--mil", action="store_const", 186 | const=NICClient.DNICHOST, dest="whoishost", 187 | help="Lookup using host " + NICClient.DNICHOST) 188 | parser.add_option("-g", "--gov", action="store_const", 189 | const=NICClient.GNICHOST, dest="whoishost", 190 | help="Lookup using host " + NICClient.GNICHOST) 191 | parser.add_option("-h", "--host", action="store", 192 | type="string", dest="whoishost", 193 | help="Lookup using specified whois host") 194 | parser.add_option("-i", "--nws", action="store_const", 195 | const=NICClient.INICHOST, dest="whoishost", 196 | help="Lookup using host " + NICClient.INICHOST) 197 | parser.add_option("-I", "--iana", action="store_const", 198 | const=NICClient.IANAHOST, dest="whoishost", 199 | help="Lookup using host " + NICClient.IANAHOST) 200 | parser.add_option("-l", "--lcanic", action="store_const", 201 | const=NICClient.LNICHOST, dest="whoishost", 202 | help="Lookup using host " + NICClient.LNICHOST) 203 | parser.add_option("-m", "--ra", action="store_const", 204 | const=NICClient.MNICHOST, dest="whoishost", 205 | help="Lookup using host " + NICClient.MNICHOST) 206 | parser.add_option("-p", "--port", action="store", 207 | type="int", dest="port", 208 | help="Lookup using specified tcp port") 209 | parser.add_option("-Q", "--quick", action="store_true", 210 | dest="b_quicklookup", 211 | help="Perform quick lookup") 212 | parser.add_option("-r", "--ripe", action="store_const", 213 | const=NICClient.RNICHOST, dest="whoishost", 214 | help="Lookup using host " + NICClient.RNICHOST) 215 | parser.add_option("-R", "--ru", action="store_const", 216 | const="ru", dest="country", 217 | help="Lookup Russian NIC") 218 | parser.add_option("-6", "--6bone", action="store_const", 219 | const=NICClient.SNICHOST, dest="whoishost", 220 | help="Lookup using host " + NICClient.SNICHOST) 221 | parser.add_option("-?", "--help", action="help") 222 | 223 | 224 | return parser.parse_args(argv) 225 | 226 | if __name__ == "__main__": 227 | flags = 0 228 | nic_client = NICClient() 229 | (options, args) = parse_command_line(sys.argv) 230 | if (options.b_quicklookup is True): 231 | flags = flags|NICClient.WHOIS_QUICK 232 | print nic_client.whois_lookup(options.__dict__, args[1], flags) 233 | ## end of http://code.activestate.com/recipes/577364/ }}} 234 | """ -------------------------------------------------------------------------------- /src/Malformity/transforms/cymru_hashcheck.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from canari.maltego.message import Field 6 | from common.entities import Hash 7 | from common.whois import whois 8 | from datetime import datetime 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform' 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Team CYMRU Hashcheck', 27 | description='Returns targeted ports from ISC IP reports', 28 | uuids=[ 'malformity.v1.CYMRU_HashCheck' ], 29 | inputs=[ ( 'CYMRU', Hash ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | hash = request.value 35 | host = 'hash.cymru.com' 36 | 37 | result = whois(hash, host) 38 | attribs = result.split() 39 | 40 | hsh = attribs[0] 41 | time = float(attribs[1]) 42 | percent = attribs[2] 43 | 44 | if attribs[2] == "NO_DATA": 45 | e = Hash(hsh) 46 | e += Field("TeamCymru", "Not Detected", displayname='TeamCymru') 47 | else: 48 | e = Hash(hsh) 49 | e += Field("Cymru Date", datetime.utcfromtimestamp(time), displayname='Cymru Date') 50 | e += Field("Percent Detected", percent, displayname='Percent Detected') 51 | 52 | response += e 53 | 54 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/isc_asreport.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure #, superuser 6 | from canari.maltego.entities import IPv4Address, AS 7 | from canari.maltego.message import Label 8 | from common.isc import buildas 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform' 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='AS Report - ISC', 27 | description='Returns tracked IPs from ISC AS reports', 28 | uuids=[ 'malformity.v1.ISC_ASReport' ], 29 | inputs=[ ( 'ISC', AS ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | #Build Request 35 | page = buildas(request.value) 36 | 37 | try: 38 | tables = page.find('table').findNext('table') 39 | for entry in tables.findAll('a'): 40 | ip = entry.text 41 | rpts = entry.findNext('td') 42 | trgts = rpts.findNext('td') 43 | first = trgts.findNext('td') 44 | last = first.findNext('td') 45 | 46 | temp = IPv4Address(ip) 47 | temp += Label('Reports', rpts.text) 48 | temp += Label('Targets', trgts.text) 49 | temp.linklabel = first.text + ' - ' + last.text 50 | 51 | 52 | response += temp 53 | except: 54 | return response 55 | 56 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/isc_ipreport.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure #, superuser 6 | from canari.maltego.entities import IPv4Address, Phrase, Service 7 | from common.isc import build 8 | 9 | __author__ = 'Keith Gilbert - @digital4rensics' 10 | __copyright__ = 'Copyright 2013, Malformity Project' 11 | __credits__ = [] 12 | 13 | __license__ = 'GPL' 14 | __version__ = '0.1' 15 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 16 | __email__ = 'Keith@digital4rensics.com' 17 | __status__ = 'Development' 18 | 19 | __all__ = [ 20 | 'dotransform' 21 | ] 22 | 23 | #@superuser 24 | @configure( 25 | label='IP Report - ISC', 26 | description='Returns targeted ports from ISC IP reports', 27 | uuids=[ 'malformity.v1.ISC_IPReport' ], 28 | inputs=[ ( 'ISC', IPv4Address ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | #Build Request 34 | page = build(request.value) 35 | 36 | try: 37 | comment = page.find('div', {'class' : 'altborder'}) 38 | response += Phrase(comment.text) 39 | 40 | prts = page.findAll('td', text = "-NA-") 41 | for entry in prts: 42 | prt = entry.findNext('td') 43 | prot = prt.findNext('td') 44 | 45 | if prot.text != "": 46 | msg = "Noted targeting port " + prt.text + ", using protocol " + prot.text 47 | else: 48 | msg = "Noted targeting port " + prt.text 49 | 50 | response += Service(msg) 51 | except: 52 | return response 53 | 54 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/malc0de_hash2as.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from common.entities import Hash 6 | from canari.maltego.entities import AS 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2013, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'dotransform', 20 | ] 21 | 22 | #@superuser 23 | @configure( 24 | label='Hash to AS [Malc0de result]', 25 | description='Run this to extract AS from IPSearch result entities', 26 | uuids=[ 'malformity.v1.Malc0de_Hash2AS' ], 27 | inputs=[ ( 'Malc0de', Hash ) ], 28 | debug=True 29 | ) 30 | def dotransform(request, response): 31 | if request.fields['AS']: 32 | response += AS(request.fields['AS']) 33 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/malc0de_hash2url.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from common.entities import Hash 6 | from canari.maltego.entities import URL 7 | 8 | __author__ = 'Keith Gilbert - @digital4rensics' 9 | __copyright__ = 'Copyright 2013, Malformity Project' 10 | __credits__ = [] 11 | 12 | __license__ = 'GPL' 13 | __version__ = '0.1' 14 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 15 | __email__ = 'Keith@digital4rensics.com' 16 | __status__ = 'Development' 17 | 18 | __all__ = [ 19 | 'dotransform', 20 | ] 21 | 22 | #@superuser 23 | @configure( 24 | label='Hash to URL [Malc0de result]', 25 | description='Run this to extract URL from IPSearch result entities', 26 | uuids=[ 'malformity.v1.Malc0de_Hash2URL' ], 27 | inputs=[ ( 'Malc0de', Hash ) ], 28 | debug=True 29 | ) 30 | 31 | def dotransform(request, response): 32 | if request.fields['URL']: 33 | e = URL(request.fields['URL']) 34 | e.url = request.fields['URL'] 35 | response += e 36 | 37 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/malc0de_hashsearch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from common.malc0de import build 6 | from common.entities import Hash 7 | from canari.maltego.entities import IPv4Address 8 | from canari.maltego.message import Field 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.2' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform' 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Hash to IP [Malc0de]', 27 | description='Returns IP and URL entities from search matches on Malc0de', 28 | uuids=[ 'malformity.v1.Malc0de_HashSearch' ], 29 | inputs=[ ( 'Malc0de', Hash ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | page = build(request.value) 35 | 36 | if page.find('span', {'id' : 'error'}): 37 | # No Matches in Malc0de 38 | return response 39 | else: 40 | for hit in page.findAll('tr', {'class' : 'class1'}): 41 | temp = [] 42 | for column in hit.findAll('td'): 43 | temp.append(column.text) 44 | 45 | e = IPv4Address(temp[2]) 46 | e += Field('URL', temp[1], displayname='URL') 47 | e += Field('AS', temp[4], displayname='AS') 48 | e += Field('Date', temp[0], displayname='Date') 49 | response += e 50 | 51 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/malc0de_ip2as.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from canari.maltego.entities import IPv4Address, AS 6 | 7 | __author__ = 'Keith Gilbert - @digital4rensics' 8 | __copyright__ = 'Copyright 2013, Malformity Project' 9 | __credits__ = [] 10 | 11 | __license__ = 'GPL' 12 | __version__ = '0.1' 13 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 14 | __email__ = 'Keith@digital4rensics.com' 15 | __status__ = 'Development' 16 | 17 | __all__ = [ 18 | 'dotransform', 19 | ] 20 | 21 | #@superuser 22 | @configure( 23 | label='IPv4Address to AS [Malc0de result]', 24 | description='Run this to extract AS from HashSearch result entities', 25 | uuids=[ 'malformity.v1.Malc0de_IP2AS' ], 26 | inputs=[ ( 'Malc0de', IPv4Address ) ], 27 | debug=True 28 | ) 29 | def dotransform(request, response): 30 | if request.fields['AS']: 31 | response += AS(request.fields['AS']) 32 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/malc0de_ip2url.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from canari.maltego.entities import IPv4Address, URL 6 | 7 | __author__ = 'Keith Gilbert - @digital4rensics' 8 | __copyright__ = 'Copyright 2013, Malformity Project' 9 | __credits__ = [] 10 | 11 | __license__ = 'GPL' 12 | __version__ = '0.1' 13 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 14 | __email__ = 'Keith@digital4rensics.com' 15 | __status__ = 'Development' 16 | 17 | __all__ = [ 18 | 'dotransform', 19 | ] 20 | 21 | #@superuser 22 | @configure( 23 | label='IPv4Address to URL [Malc0de result]', 24 | description='Run this to extract URL from HashSearch result entities', 25 | uuids=[ 'malformity.v1.Malc0de_IP2URL' ], 26 | inputs=[ ( 'Malc0de', IPv4Address ) ], 27 | debug=True 28 | ) 29 | def dotransform(request, response): 30 | if request.fields['URL']: 31 | e = URL(request.fields['URL']) 32 | e.url = request.fields['URL'] 33 | response += e 34 | 35 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/malc0de_ipsearch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from common.malc0de import build 6 | from common.entities import Hash 7 | from canari.maltego.entities import IPv4Address 8 | from canari.maltego.message import Field 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.2' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | 25 | #@superuser 26 | @configure( 27 | label='IP to Hash [Malc0de]', 28 | description='Returns Hash and URL entities from search matches on Malc0de', 29 | uuids=[ 'malformity.v1.Malc0de_IPSearch' ], 30 | inputs=[ ( 'Malc0de', IPv4Address ) ], 31 | debug=True 32 | ) 33 | 34 | def dotransform(request, response): 35 | page = build(request.value) 36 | 37 | if page.find('span', {'id' : 'error'}): 38 | # No Matches in Malc0de 39 | return response 40 | else: 41 | for hit in page.findAll('tr', {'class' : 'class1'}): 42 | temp = [] 43 | for column in hit.findAll('td'): 44 | temp.append(column.text) 45 | 46 | e = Hash(temp[6]) 47 | e += Field('URL', temp[1], displayname='URL') 48 | e += Field('AS', temp[4], displayname='AS') 49 | e += Field('Date', temp[0], displayname='Date') 50 | response += e 51 | 52 | return response 53 | -------------------------------------------------------------------------------- /src/Malformity/transforms/pDNS_Domain2IP.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import datetime 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure #, superuser 7 | from canari.maltego.entities import IPv4Address, Domain 8 | from common.pdns import query 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = ['ISC for the original pDNS python script'] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.2' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Domain to IPs - pDNS', 27 | description='The transform will take a domain and return IP addresses based on pDNS rrset records', 28 | uuids=[ 'malformity.v1.pDNS_Domain2IP' ], 29 | inputs=[ ( 'pDNS', Domain ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | domain = request.value 35 | results = query('-r', domain, 0, 'n') 36 | 37 | for result in results: 38 | data = json.loads(result) 39 | if data.has_key('time_first'): 40 | first = data['time_first'] 41 | last = data['time_last'] 42 | elif data.has_key('zone_time_first'): 43 | first = data['zone_time_first'] 44 | last = data['zone_time_last'] 45 | 46 | fnice = datetime.datetime.fromtimestamp(int(first)).strftime('%m-%d-%Y') 47 | lnice = datetime.datetime.fromtimestamp(int(last)).strftime('%m-%d-%Y') 48 | 49 | if data['rrtype'] == 'A': 50 | for item in data['rdata']: 51 | e = IPv4Address(item) 52 | e.linklabel = fnice + ' - ' + lnice 53 | response += e 54 | 55 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/pDNS_IP2Domain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import datetime 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure #, superuser 7 | from canari.maltego.entities import IPv4Address, Domain 8 | from common.pdns import query 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = ['ISC for the original pDNS python script'] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='IP to Domains - pDNS', 27 | description='The transform will take an IP address and return domains based on pDNS rdata records', 28 | uuids=[ 'malformity.v1.pDNS_IP2Domain' ], 29 | inputs=[ ( 'pDNS', IPv4Address ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | ip = request.value 35 | results = query('-i', ip, 0, 'n') 36 | 37 | for result in results: 38 | data = json.loads(result) 39 | if data.has_key('rrname'): 40 | if data.has_key('time_first'): 41 | first = data['time_first'] 42 | last = data['time_last'] 43 | elif data.has_key('zone_time_first'): 44 | first = data['zone_time_first'] 45 | last = data['zone_time_last'] 46 | 47 | fnice = datetime.datetime.fromtimestamp(int(first)).strftime('%m-%d-%Y') 48 | lnice = datetime.datetime.fromtimestamp(int(last)).strftime('%m-%d-%Y') 49 | 50 | e = Domain(data['rrname'].rstrip('.')) 51 | e.linklabel = fnice + ' - ' + lnice 52 | response += e 53 | 54 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/pDNS_NS2Domains.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import datetime 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure #, superuser 7 | from canari.maltego.entities import NSRecord, Domain 8 | from common.pdns import query 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = ['ISC for the original pDNS python script'] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='NSRecord to Domains - pDNS', 27 | description='The transform will return all domains associated with a specific NS Record', 28 | uuids=[ 'malformity.v1.pDNS_NS2Domains' ], 29 | inputs=[ ( 'pDNS', NSRecord ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | ns = request.value 35 | results = query('-n', ns, 0, 'n') 36 | 37 | for result in results: 38 | data = json.loads(result) 39 | if data.has_key('rrname'): 40 | if data.has_key('time_first'): 41 | first = data['time_first'] 42 | last = data['time_last'] 43 | elif data.has_key('zone_time_first'): 44 | first = data['zone_time_first'] 45 | last = data['zone_time_last'] 46 | 47 | fnice = datetime.datetime.fromtimestamp(int(first)).strftime('%m-%d-%Y') 48 | lnice = datetime.datetime.fromtimestamp(int(last)).strftime('%m-%d-%Y') 49 | 50 | e = Domain(data['rrname'].rstrip('.')) 51 | e.linklabel = fnice + ' - ' + lnice 52 | response += e 53 | 54 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/pDNS_OtherRRset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import datetime 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure #, superuser 7 | from canari.maltego.entities import Phrase, Domain, MXRecord, NSRecord 8 | from common.pdns import query 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = ['ISC for the original pDNS python script'] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Other RRSet Records - pDNS', 27 | description='The transform will take a domain and return non A records from an rrset', 28 | uuids=[ 'malformity.v1.pDNS_OtherRRset' ], 29 | inputs=[ ( 'pDNS', Domain ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | domain = request.value 35 | results = query('-r', domain, 0, 'n') 36 | 37 | for result in results: 38 | data = json.loads(result) 39 | if data.has_key('time_first'): 40 | first = data['time_first'] 41 | last = data['time_last'] 42 | elif data.has_key('zone_time_first'): 43 | first = data['zone_time_first'] 44 | last = data['zone_time_last'] 45 | 46 | fnice = datetime.datetime.fromtimestamp(int(first)).strftime('%m-%d-%Y') 47 | lnice = datetime.datetime.fromtimestamp(int(last)).strftime('%m-%d-%Y') 48 | 49 | if data['rrtype'] == 'NS': 50 | for item in data['rdata']: 51 | e = NSRecord(item) 52 | e.linklabel = fnice + ' - ' + lnice 53 | response += e 54 | elif data['rrtype'] == 'MX': 55 | for item in data['rdata']: 56 | e = MXRecord(item) 57 | e.linklabel = fnice + ' - ' + lnice 58 | response += e 59 | elif data['rrtype'] == 'CNAME': 60 | for item in data['rdata']: 61 | e = Domain(item.rstrip('.')) 62 | e.linklabel = fnice + ' - ' + lnice 63 | response += e 64 | elif data['rrtype'] == 'A': 65 | pass 66 | else: 67 | type = data['rrtype'] 68 | for item in data['rdata']: 69 | label = type + ' ' + item 70 | e = Phrase(label) 71 | e.linklabel = fnice + ' - ' + lnice 72 | response += e 73 | 74 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/pDNS_wildcardsearch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import datetime 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure #, superuser 7 | from canari.maltego.entities import Domain 8 | from common.pdns import query 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = ['ISC for the original pDNS python script'] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Wildcard Domain Search - pDNS', 27 | description='The transform will return domains retrieved from a wildcard rrset search', 28 | uuids=[ 'malformity.v1.pDNS_WildcardSearch' ], 29 | inputs=[ ( 'pDNS', Domain ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | domain = request.value 35 | results = query('-r', domain, 0, 'n') 36 | 37 | for result in results: 38 | data = json.loads(result) 39 | if data.has_key('time_first'): 40 | first = data['time_first'] 41 | last = data['time_last'] 42 | elif data.has_key('zone_time_first'): 43 | first = data['zone_time_first'] 44 | last = data['zone_time_last'] 45 | 46 | fnice = datetime.datetime.fromtimestamp(int(first)).strftime('%m-%d-%Y') 47 | lnice = datetime.datetime.fromtimestamp(int(last)).strftime('%m-%d-%Y') 48 | 49 | if data['rrtype'] == 'A': 50 | # for item in data['rrname']: 51 | e = Domain(data['rrname'].rstrip('.')) 52 | e.linklabel = fnice + ' - ' + lnice 53 | response += e 54 | 55 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/robtex_getSubdomains.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from common.robtex import build 6 | from canari.maltego.entities import Domain 7 | from canari.maltego.message import UIMessage 8 | 9 | __author__ = 'Keith Gilbert - @digital4rensics' 10 | __copyright__ = 'Copyright 2013, Malformity Project' 11 | __credits__ = [] 12 | 13 | __license__ = 'GPL' 14 | __version__ = '0.1' 15 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 16 | __email__ = 'Keith@digital4rensics.com' 17 | __status__ = 'Development' 18 | 19 | __all__ = [ 20 | 'dotransform', 21 | ] 22 | 23 | @configure( 24 | label='Get Subdomains [Robtex]', 25 | description='Returns Domains listed on Robtex for an IP', 26 | uuids=[ 'malformity.v1.Robtex_getSubdomains' ], 27 | inputs=[ ( 'Robtex', Domain ) ], 28 | debug=True 29 | ) 30 | def dotransform(request, response): 31 | page = build(request.value) 32 | 33 | doms = [] 34 | if page.find("span", {"id" : "sharedsub"}): 35 | section = page.find("span", {"id" : "sharedsub"}).findNext('ul') 36 | for entry in section.findAll("li"): 37 | response += Domain(entry.text) 38 | elif page.find("span", {"id" : "sharedsubv"}): 39 | section = page.find("span", {"id" : "sharedsubv"}).findNext('ul') 40 | for entry in section.findAll("li"): 41 | response += Domain(entry.text) 42 | else: 43 | response += UIMessage('No subdomains in robtex') 44 | 45 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/robtex_ip2domains.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from common.robtex import build 6 | from canari.maltego.entities import IPv4Address, Domain 7 | from canari.maltego.message import UIMessage 8 | 9 | __author__ = 'Keith Gilbert - @digital4rensics' 10 | __copyright__ = 'Copyright 2013, Malformity Project' 11 | __credits__ = [] 12 | 13 | __license__ = 'GPL' 14 | __version__ = '0.1' 15 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 16 | __email__ = 'Keith@digital4rensics.com' 17 | __status__ = 'Development' 18 | 19 | __all__ = [ 20 | 'dotransform', 21 | ] 22 | 23 | @configure( 24 | label='IP to Domains [Robtex]', 25 | description='Returns Domains listed on Robtex for an IP', 26 | uuids=[ 'malformity.v1.Robtex_IP2Domain' ], 27 | inputs=[ ( 'Robtex', IPv4Address ) ], 28 | debug=True 29 | ) 30 | def dotransform(request, response): 31 | page = build(request.value) 32 | 33 | doms = [] 34 | try: 35 | section = page.find("span", {"id" : "sharedha"}).findNext('ul') 36 | for entry in section.findAll("li"): 37 | response += Domain(entry.text) 38 | except: 39 | response += UIMessage('No domains in robtex') 40 | 41 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/threatexpert_hash2dhash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure #, superuser 7 | from common.threatexpert import build 8 | from common.entities import Hash 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform' 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Hash to Dropped File Hash - ThreatExpert', 27 | description='Returns MD5 hashes of all dropped files from a ThreatExpert report for a Hash', 28 | uuids=[ 'malformity.v1.ThreatExpert_Hash2dHash' ], 29 | inputs=[ ( 'ThreatExpert', Hash ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | #Build the request 35 | page = build(request.value) 36 | 37 | #Locate the dropped files section of the report 38 | try: 39 | dfiles = page.find(text='The following files were created in the system:').findNext('table') 40 | except: 41 | dfiles = None 42 | pass 43 | 44 | if dfiles is not None: 45 | #Find the appropriate cell and extract the MD5 hash 46 | for file in dfiles.findAll("td", {"class" : "cell_1"}): 47 | text = file.text.splitlines() 48 | for entry in text: 49 | if re.search('MD5:', entry): 50 | response += Hash(entry[7:39]) 51 | else: 52 | return response 53 | 54 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/threatexpert_hash2domain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure #, superuser 6 | from common.entities import Hash 7 | from canari.maltego.entities import Domain 8 | from common.threatexpert import build 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform' 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Hash to Domain - ThreatExpert', 27 | description='Returns Domains from a ThreatExpert report for a Hash', 28 | uuids=[ 'malformity.v1.ThreatExpert_Hash2Domain' ], 29 | inputs=[ ( 'ThreatExpert', Hash ) ], 30 | debug=True 31 | ) 32 | def dotransform(request, response): 33 | page = build(request.value) 34 | 35 | try: 36 | single = page.find(text='The following Host Name was requested from a host database:').findNext() 37 | except: 38 | single = None 39 | pass 40 | 41 | try: 42 | single = page.find(text='The following Host Names were requested from a host database:').findNext() 43 | except: 44 | single = None 45 | pass 46 | 47 | try: 48 | single2 = page.find(text='The following Internet Connection was established:').findNext() 49 | except: 50 | single2 = None 51 | pass 52 | 53 | try: 54 | multi = page.find(text='The following Internet Connections were established:').findNext('table') 55 | except: 56 | multi = None 57 | pass 58 | 59 | if single is not None: 60 | for dom in single.findAll("li"): 61 | text = dom.text 62 | response += Domain(text) 63 | 64 | if single2 is not None: 65 | dom = single2.findNext('tr').findNext('tr').findNext('td') 66 | text = dom.text 67 | response += Domain(text) 68 | 69 | if multi is not None: 70 | for entry in multi.findAll('tr')[1::]: 71 | dom = entry.findNext('td') 72 | text = dom.text 73 | response += Domain(text) 74 | 75 | return response 76 | -------------------------------------------------------------------------------- /src/Malformity/transforms/threatexpert_hash2hiddenproc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure #, superuser 6 | from common.entities import Hash, MaliciousProcess 7 | from common.threatexpert import build 8 | 9 | __author__ = 'Keith Gilbert - @digital4rensics' 10 | __copyright__ = 'Copyright 2012, Malformity Project' 11 | __credits__ = [] 12 | 13 | __license__ = 'GPL' 14 | __version__ = '0.1' 15 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 16 | __email__ = 'Keith@digital4rensics.com' 17 | __status__ = 'Development' 18 | 19 | __all__ = [ 20 | 'dotransform' 21 | ] 22 | 23 | #@superuser 24 | @configure( 25 | label='Hash to Hidden Process - ThreatExpert', 26 | description='Returns a list of hidden processes from a ThreatExpert report for a Hash', 27 | uuids=[ 'malformity.v1.ThreatExpert_Hash2HiddenProc' ], 28 | inputs=[ ( 'ThreatExpert', Hash ) ], 29 | debug=True 30 | ) 31 | def dotransform(request, response): 32 | page = build(request.value) 33 | 34 | try: 35 | dfiles = page.find(text=' from the user:').findNext('table') 36 | except: 37 | dfiles = None 38 | pass 39 | 40 | if dfiles is not None: 41 | for file in dfiles.findAll("td", {"class" : "cell_1"}): 42 | text = file.text.splitlines() 43 | for entry in text: 44 | response += MaliciousProcess(entry) 45 | 46 | return response 47 | -------------------------------------------------------------------------------- /src/Malformity/transforms/threatexpert_hash2ip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.maltego.entities import IPv4Address 6 | from common.entities import Hash 7 | from canari.maltego.utils import debug, progress 8 | from canari.framework import configure #, superuser 9 | from common.threatexpert import build 10 | 11 | __author__ = 'Keith Gilbert - @digital4rensics' 12 | __copyright__ = 'Copyright 2012, Malformity Project' 13 | __credits__ = [] 14 | 15 | __license__ = 'GPL' 16 | __version__ = '0.1' 17 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 18 | __email__ = 'Keith@digital4rensics.com' 19 | __status__ = 'Development' 20 | 21 | __all__ = [ 22 | 'dotransform' 23 | ] 24 | 25 | #@superuser 26 | @configure( 27 | label='Hash to IP - ThreatExpert', 28 | description='Returns an IP from an existing ThreatExpert report for a Hash', 29 | uuids=[ 'malformity.v1.ThreatExpert_Hash2IP' ], 30 | inputs=[ ( 'ThreatExpert', Hash ) ], 31 | debug=True 32 | ) 33 | 34 | def dotransform(request, response): 35 | # Build the request 36 | page = build(request.value) 37 | 38 | # Search the page to extract all IP addresses present 39 | try: 40 | for element in page.findAll(text=re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")): 41 | response += IPv4Address(element) 42 | except: 43 | pass 44 | 45 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/threatexpert_hash2mutex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure #, superuser 6 | from common.entities import Hash 7 | from canari.maltego.entities import Phrase 8 | from common.threatexpert import build 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | #@superuser 25 | @configure( 26 | label='Hash to Mutex - ThreatExpert', 27 | description='Returns a Mutex from an existing ThreatExpert report for a Hash', 28 | uuids=[ 'malformity.v1.ThreatExpert_Hash2Mutex' ], 29 | inputs=[ ( 'ThreatExpert', Hash ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | #Build the request 35 | page = build(request.value) 36 | 37 | try: 38 | try: 39 | # Searching for the string that indicates a single mutex was created 40 | single = page.find(text='To mark the presence in the system, the following Mutex object was created:').findNext('ul').li.text 41 | except: 42 | single = None 43 | try: 44 | # Searching for the string that indicates multiple mutexes were created 45 | multiple = page.find(text='To mark the presence in the system, the following Mutex objects were created:').findNext('ul') 46 | except: 47 | multiple = None 48 | 49 | # If a single mutex was found 50 | if single is not None: 51 | response += Phrase(single) 52 | # Account for the instance in which a dropped file may have had additional mutexes 53 | if multiple is not None: 54 | for mutex in multiple.findAll('li'): 55 | current = mutex.text 56 | response += Phrase(current) 57 | # If multiple mutexes were found 58 | elif multiple is not None: 59 | for mutex in multiple.findAll('li'): 60 | current = mutex.text 61 | response += Phrase(current) 62 | return response 63 | else: 64 | pass 65 | 66 | except: 67 | pass 68 | 69 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/threatexpert_hash2url.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure #, superuser 7 | from common.threatexpert import build 8 | from common.entities import Hash 9 | from canari.maltego.entities import URL 10 | 11 | __author__ = 'Keith Gilbert - @digital4rensics' 12 | __copyright__ = 'Copyright 2013, Malformity Project' 13 | __credits__ = [] 14 | 15 | __license__ = 'GPL' 16 | __version__ = '0.1' 17 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 18 | __email__ = 'Keith@digital4rensics.com' 19 | __status__ = 'Development' 20 | 21 | __all__ = [ 22 | 'dotransform' 23 | ] 24 | 25 | #@superuser 26 | @configure( 27 | label='Hash to URL - ThreatExpert', 28 | description='Returns URLs from a ThreatExpert report for a Hash', 29 | uuids=[ 'malformity.v1.ThreatExpert_Hash2URL' ], 30 | inputs=[ ( 'ThreatExpert', Hash ) ], 31 | debug=True 32 | ) 33 | 34 | def dotransform(request, response): 35 | #Build the request 36 | page = build(request.value) 37 | 38 | #Locate the URL files section of the report 39 | try: 40 | urls = page.find(text='The data identified by the following URLs was then requested from the remote web server:').findNext('ul') 41 | except: 42 | urls = None 43 | pass 44 | try: 45 | url = page.find(text='The data identified by the following URL was then requested from the remote web server:').findNext('ul') 46 | except: 47 | url = None 48 | 49 | if urls is not None: 50 | #Find the appropriate cell and extract the MD5 hash 51 | for file in urls.findAll("li"): 52 | text = file.text 53 | e = URL(text) 54 | e.url = text 55 | response += e 56 | elif url is not None: 57 | for file in url.findAll("li"): 58 | text = file.text 59 | e = URL(text) 60 | e.url = text 61 | response += e 62 | else: 63 | return response 64 | 65 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vicheck_filesearch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import Field, MaltegoException 7 | from canari.maltego.entities import Phrase 8 | from common.entities import Hash 9 | from common.vicheck import build 10 | 11 | __author__ = 'Keith Gilbert - @digital4rensics' 12 | __copyright__ = 'Copyright 2012, Malformity Project' 13 | __credits__ = [] 14 | 15 | __license__ = 'GPL' 16 | __version__ = '0.1' 17 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 18 | __email__ = 'Keith@digital4rensics.com' 19 | __status__ = 'Development' 20 | 21 | __all__ = [ 22 | 'dotransform', 23 | ] 24 | 25 | @configure( 26 | label='Filename Search - ViCheck', 27 | description='Returns Hashes from a ViCheck Phrase search and sets the filename', 28 | uuids=[ 'malformity.v1.ViCheck_FileSearch' ], 29 | inputs=[ ( 'ViCheck', Phrase ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | #Build the request 35 | type = 'name' 36 | page = build(request.value, type) 37 | 38 | try: 39 | list = page.findAll(text='MD5:') 40 | except: 41 | raise MaltegoException('No DNS Queries') 42 | 43 | for item in list: 44 | if item != 'none': 45 | md5 = Hash(item.next.next) 46 | name = item.previous.previous.previous 47 | md5 += Field('Filename', name) 48 | response += md5 49 | 50 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vicheck_hash2dhash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import Field, MaltegoException 7 | from common.entities import Hash 8 | from common.vicheck import build 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='Hash to Dropped Hash - ViCheck', 26 | description='Returns Dropped Files from a ViCheck report for a hash', 27 | uuids=[ 'malformity.v1.ViCheck_Hash2dHash' ], 28 | inputs=[ ( 'ViCheck', Hash ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | #Build the request 34 | type = 'hash' 35 | page = build(request.value, type) 36 | 37 | global count 38 | global count2 39 | count = 1 40 | 41 | try: 42 | list = page.find(text='Dropped File').previous.previous.parent.findAll('p') 43 | except: 44 | raise MaltegoException('No Dropped Files') 45 | 46 | for item in list: 47 | count2 = 1 48 | if count % 2 == 1: 49 | split = item.findAll('a') 50 | for s in split: 51 | if count2 % 2 == 1: 52 | pass 53 | else: 54 | e = Hash(s.text) 55 | name = s.previous.previous.previous.text 56 | e += Field('Filename', name) 57 | response += e 58 | count2+=1 59 | elif count % 2 == 0: 60 | pass 61 | count+=1 62 | 63 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vicheck_hash2domain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import MaltegoException 7 | from canari.maltego.entities import Domain 8 | from common.entities import Hash 9 | from common.vicheck import build 10 | 11 | __author__ = 'Keith Gilbert - @digital4rensics' 12 | __copyright__ = 'Copyright 2012, Malformity Project' 13 | __credits__ = [] 14 | 15 | __license__ = 'GPL' 16 | __version__ = '0.1' 17 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 18 | __email__ = 'Keith@digital4rensics.com' 19 | __status__ = 'Development' 20 | 21 | __all__ = [ 22 | 'dotransform', 23 | ] 24 | 25 | @configure( 26 | label='Hash to Domains - ViCheck', 27 | description='Returns Domains from a ViCheck report for a hash', 28 | uuids=[ 'malformity.v1.ViCheck_Hash2Domain' ], 29 | inputs=[ ( 'ViCheck', Hash ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | #Build the request 35 | type = 'hash' 36 | page = build(request.value, type) 37 | 38 | try: 39 | list = page.find(text='PCAP Raw DNS Queries').previous.previous.parent.findAll('p') 40 | except: 41 | raise MaltegoException('No DNS Queries') 42 | 43 | for item in list: 44 | if item.text != 'none': 45 | response += Domain(item.text) 46 | 47 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vicheck_hash2filename.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import MaltegoException 7 | from common.entities import Hash, Filename 8 | from common.vicheck import build 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='Hash to Filename - ViCheck', 26 | description='Returns Filename from a ViCheck report for a hash', 27 | uuids=[ 'malformity.v1.ViCheck_Hash2Filename' ], 28 | inputs=[ ( 'ViCheck', Hash ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | #Build the request 34 | type = 'hash' 35 | page = build(request.value, type) 36 | 37 | try: 38 | list = page.find(text='File: ').findNext('b') 39 | except: 40 | raise MaltegoException('No filename') 41 | 42 | if list.text != '': 43 | response += Filename(list.text) 44 | 45 | return response 46 | -------------------------------------------------------------------------------- /src/Malformity/transforms/vicheck_hash2mutex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.entities import Phrase 7 | from canari.maltego.message import MaltegoException 8 | from common.entities import Hash 9 | from common.vicheck import build 10 | 11 | __author__ = 'Keith Gilbert - @digital4rensics' 12 | __copyright__ = 'Copyright 2012, Malformity Project' 13 | __credits__ = [] 14 | 15 | __license__ = 'GPL' 16 | __version__ = '0.1' 17 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 18 | __email__ = 'Keith@digital4rensics.com' 19 | __status__ = 'Development' 20 | 21 | __all__ = [ 22 | 'dotransform', 23 | ] 24 | 25 | @configure( 26 | label='Hash to Mutex - ViCheck', 27 | description='Returns Mutexes from a ViCheck report for a hash', 28 | uuids=[ 'malformity.v1.ViCheck_Hash2Mutex' ], 29 | inputs=[ ( 'ViCheck', Hash ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | #Build the request 35 | type = 'hash' 36 | page = build(request.value, type) 37 | 38 | try: 39 | list = page.find(text='Mutex Created').previous.previous.parent.findAll('p') 40 | except: 41 | raise MaltegoException('No Mutexes Created') 42 | 43 | for item in list: 44 | if item.text != 'none': 45 | response += Phrase(item.text) 46 | 47 | return response 48 | -------------------------------------------------------------------------------- /src/Malformity/transforms/vicheck_hash2registry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import MaltegoException 7 | from common.entities import Hash, RegistryEntry 8 | from common.vicheck import build 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2012, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='Hash to Registry - ViCheck', 26 | description='Returns Registry Items from a ViCheck report for a hash', 27 | uuids=[ 'malformity.v1.ViCheck_Hash2Registry' ], 28 | inputs=[ ( 'ViCheck', Hash ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | #Build the request 34 | type = 'hash' 35 | page = build(request.value, type) 36 | 37 | try: 38 | list = page.find(text='Registry Item Created').previous.previous.parent.findAll('p') 39 | except: 40 | raise MaltegoException('No Registry Items Created') 41 | 42 | for item in list: 43 | if item.text != 'none': 44 | response += RegistryEntry(item.text) 45 | 46 | return response 47 | -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_api_domain2ip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import urllib2 4 | import urllib 5 | import json 6 | from canari.maltego.utils import debug, progress 7 | from canari.framework import configure #, superuser 8 | from canari.maltego.entities import IPv4Address, Domain 9 | from canari.config import config 10 | 11 | __author__ = 'Marcus' 12 | 13 | # ... 14 | #@superuser 15 | @configure( 16 | label='Domain to IP - pDNS API[VT]', 17 | description='Domain to IP - VT pDNS data', 18 | uuids=[ 'malformity.v1.VT_API_Domain2IP' ], 19 | inputs=[ ('VirusTotal', Domain)], 20 | debug=True 21 | ) 22 | 23 | def dotransform(request, response): 24 | # Report transform progress 25 | progress(50) 26 | domain = request.value 27 | url = 'https://www.virustotal.com/vtapi/v2/domain/report' 28 | 29 | parameters = {'domain': domain, 'apikey': config['virustotal/apikey']} 30 | resp = urllib2.urlopen('%s?%s' % (url, urllib.urlencode(parameters))).read() 31 | response_dict = json.loads(resp) 32 | 33 | #Latest detected IPs" 34 | try: 35 | for i in range(0,len(response_dict['resolutions'])): 36 | ip = response_dict['resolutions'][i]['ip_address'] 37 | ip = IPv4Address(ip) 38 | response += ip 39 | except IOError: 40 | response = 'IO Error' 41 | except KeyError: 42 | response = 'Not Found' 43 | 44 | 45 | # Update progress 46 | progress(100) 47 | 48 | 49 | # Return response for visualization 50 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_api_ip2domain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import urllib2 4 | import urllib 5 | import json 6 | from canari.maltego.utils import debug, progress 7 | from canari.framework import configure #, superuser 8 | from canari.maltego.entities import IPv4Address, Domain 9 | from canari.config import config 10 | 11 | __author__ = 'Marcus' 12 | 13 | # ... 14 | #@superuser 15 | @configure( 16 | label='IP to Domain - pDNS API[VT]', 17 | description='IP to Domain - VT pDNS data', 18 | uuids=[ 'malformity.v1.VT_API_IP2Domain' ], 19 | inputs=[ ('VirusTotal', IPv4Address)], 20 | debug=True 21 | ) 22 | 23 | def dotransform(request, response): 24 | # Report transform progress 25 | progress(50) 26 | ip = request.value 27 | url = 'https://www.virustotal.com/vtapi/v2/ip-address/report' 28 | 29 | parameters = {'ip': ip, 'apikey': config['virustotal/apikey']} 30 | resp = urllib2.urlopen('%s?%s' % (url, urllib.urlencode(parameters))).read() 31 | response_dict = json.loads(resp) 32 | 33 | #Latest detected URLs" 34 | try: 35 | for i in range(0,len(response_dict['resolutions'])): 36 | host = response_dict['resolutions'][i]['hostname'] 37 | host = Domain(host) 38 | response += host 39 | except IOError: 40 | response = 'IO Error' 41 | except KeyError: 42 | response = 'Not Found' 43 | 44 | 45 | # Update progress 46 | progress(100) 47 | 48 | 49 | # Return response for visualization 50 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_domain2ip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import urllib2 4 | from canari.maltego.utils import debug, progress 5 | from BeautifulSoup import BeautifulSoup, NavigableString 6 | from canari.framework import configure #, superuser 7 | from canari.maltego.entities import IPv4Address, Domain 8 | 9 | __author__ = 'Marcus' 10 | __copyright__ = 'Copyright 2013, Marcus' 11 | __credits__ = [] 12 | 13 | __license__ = 'GPL' 14 | __version__ = '0.1' 15 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 16 | __email__ = 'Keith@digital4rensics.com' 17 | __status__ = 'Development' 18 | 19 | __all__ = [ 20 | 'dotransform', 21 | ] 22 | 23 | #@superuser 24 | @configure( 25 | label='Domain to IP - pDNS [VT]', 26 | description='Domain to IP - VT pDNS data', 27 | uuids=[ 'malformity.v1.VT_Domain2IP' ], 28 | inputs=[ ('VirusTotal', Domain)], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | # Report transform progress 34 | progress(50) 35 | total="" 36 | 37 | urldom = 'https://www.virustotal.com/en/domain/'+request.value+'/information/' 38 | soup = BeautifulSoup(urllib2.urlopen(urldom).read()) 39 | try: 40 | links = soup.findAll('div', attrs={'class':'enum'}) 41 | for link in links: 42 | total += str(link) 43 | total = BeautifulSoup(total) 44 | for totals in total.findAll('a',href=True): 45 | totals=totals['href'] 46 | theIP = totals.replace("/en/ip-address/", "") 47 | e = theIP.replace("/information/", "") 48 | response += IPv4Address(e) 49 | except IOError: 50 | print 'IO Error' 51 | 52 | 53 | # Update progress 54 | progress(100) 55 | 56 | 57 | # Return response for visualization 58 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_hash2exiftool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import MaltegoException 7 | from common.entities import Hash, Filename 8 | from canari.maltego.entities import Phrase 9 | from common.vt import build 10 | import re 11 | 12 | __author__ = 'Keith Gilbert - @digital4rensics' 13 | __copyright__ = 'Copyright 2013, Malformity Project' 14 | __credits__ = [] 15 | 16 | __license__ = 'GPL' 17 | __version__ = '0.1' 18 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 19 | __email__ = 'Keith@digital4rensics.com' 20 | __status__ = 'Development' 21 | 22 | __all__ = [ 23 | 'dotransform', 24 | ] 25 | 26 | @configure( 27 | label='Hash to ExifTool - VirusTotal', 28 | description='Returns ExifTool details from a report on VT', 29 | uuids=[ 'malformity.v1.VT_Hash2ExifTool' ], 30 | inputs=[ ( 'VirusTotal', Hash ) ], 31 | debug=True 32 | ) 33 | 34 | def dotransform(request, response): 35 | page = build(request.value) 36 | try: 37 | results = page.findAll('span', {"class" : "field-key"}) 38 | for entry in results: 39 | text = entry.text 40 | if re.search('TimeStamp', text): 41 | e = entry.next.next.strip() 42 | response += Phrase(e) 43 | elif re.search('FileType', text): 44 | e = entry.next.next.strip() 45 | response += Phrase(e) 46 | elif re.search('EntryPoint', text): 47 | e= entry.next.next.strip() 48 | response += Phrase(e) 49 | elif re.search('FileVersionNumber', text): 50 | e= entry.next.next.strip() 51 | response += Phrase(e) 52 | elif re.search('LanguageCode', text): 53 | e= entry.next.next.strip() 54 | response += Phrase(e) 55 | elif re.search('CharacterSet', text): 56 | e= entry.next.next.strip() 57 | response += Phrase(e) 58 | elif re.search('InternalName', text): 59 | e= entry.next.next.strip() 60 | response += Phrase(e) 61 | elif re.search('FileDescription', text): 62 | e= entry.next.next.strip() 63 | response += Phrase(e) 64 | elif re.search('OriginalFilename', text): 65 | e= entry.next.next.strip() 66 | response += Filename(e) 67 | elif re.search('ProductVersionNumber', text): 68 | e= entry.next.next.strip() 69 | response += Phrase(e) 70 | except: 71 | raise MaltegoException('Could not Exif Information') 72 | 73 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_hash2filenames.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import re 4 | from BeautifulSoup import BeautifulSoup 5 | from canari.maltego.utils import debug, progress 6 | from canari.framework import configure 7 | from canari.maltego.message import MaltegoException 8 | from common.entities import Hash, Filename 9 | from common.vt import build 10 | 11 | __author__ = 'Keith Gilbert - @digital4rensics' 12 | __copyright__ = 'Copyright 2013, Malformity Project' 13 | __credits__ = [] 14 | 15 | __license__ = 'GPL' 16 | __version__ = '0.1' 17 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 18 | __email__ = 'Keith@digital4rensics.com' 19 | __status__ = 'Development' 20 | 21 | __all__ = [ 22 | 'dotransform', 23 | ] 24 | 25 | @configure( 26 | label='Hash to Filenames - VirusTotal', 27 | description='Returns submitted filenames for a hash from a VirusTotal report', 28 | uuids=[ 'malformity.v1.VT_Hash2Filenames' ], 29 | inputs=[ ( 'VirusTotal', Hash ) ], 30 | debug=True 31 | ) 32 | 33 | def dotransform(request, response): 34 | page = build(request.value) 35 | try: 36 | results = page.findAll('td', {"class" : "field-key"}) 37 | for entry in results: 38 | text = entry.text 39 | if re.search('File names', text): 40 | lines = ''.join(entry.next.next.next.findAll(text=True)) 41 | for line in lines.split('\n'): 42 | if line.strip() != "": 43 | response += Filename(line) 44 | except: 45 | raise MaltegoException('Could not find Filenames') 46 | 47 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_hash2name.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from canari.config import config 6 | from common.entities import Hash 7 | from canari.maltego.entities import Phrase 8 | from canari.maltego.message import Label, UIMessage 9 | from urllib import urlopen, urlencode 10 | from json import loads 11 | 12 | 13 | __author__ = 'Kyle Maxwell' 14 | __copyright__ = 'Copyright 2012, Kyle Maxwell' 15 | __credits__ = [] 16 | 17 | __license__ = 'GPL' 18 | __version__ = '0.1' 19 | __maintainer__ = 'Kyle Maxwell' 20 | __email__ = '@kylemaxwell' 21 | __status__ = 'Development' 22 | 23 | __all__ = [ 24 | 'dotransform' 25 | ] 26 | 27 | 28 | @configure( 29 | label="To malware name [VT]", 30 | description="Returns names of malware associated with a particular hash", 31 | uuids=['malformity.v1.VT_Hash2Name'], 32 | inputs=[('VirusTotal', Hash)], 33 | debug=False 34 | ) 35 | 36 | def dotransform(request, response): 37 | debug('VT API key %s\n' % request.value) 38 | 39 | r = urlopen( 40 | "https://www.virustotal.com/vtapi/v2/file/report", 41 | urlencode({ 42 | "resource": request.value, 43 | "apikey": config['virustotal/apikey'] 44 | }) 45 | ) 46 | 47 | if r.code == 200: 48 | d = loads(r.read()) 49 | debug('VT output: %s\n' % d) 50 | # If it's not a clean file, tell Maltego the names of the malware 51 | if d['response_code'] == 1: 52 | for engine in d['scans'].iteritems(): 53 | if engine[1]['detected']: 54 | e = Phrase(engine[1]['result']) 55 | e += Label("VirusTotal Report", d['permalink']) 56 | response += e 57 | 58 | response += UIMessage(d['verbose_msg']) 59 | 60 | return response 61 | 62 | -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_hash2packer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import MaltegoException 7 | from common.entities import Hash 8 | from canari.maltego.entities import Phrase 9 | from common.vt import build 10 | import re 11 | 12 | __author__ = 'Keith Gilbert - @digital4rensics' 13 | __copyright__ = 'Copyright 2013, Malformity Project' 14 | __credits__ = [] 15 | 16 | __license__ = 'GPL' 17 | __version__ = '0.1' 18 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 19 | __email__ = 'Keith@digital4rensics.com' 20 | __status__ = 'Development' 21 | 22 | __all__ = [ 23 | 'dotransform', 24 | ] 25 | 26 | @configure( 27 | label='Hash to Packer - VirusTotal', 28 | description='Returns detected packers for a hash from a VirusTotal report', 29 | uuids=[ 'malformity.v1.VT_Hash2Packer' ], 30 | inputs=[ ( 'VirusTotal', Hash ) ], 31 | debug=True 32 | ) 33 | 34 | def dotransform(request, response): 35 | page = build(request.value) 36 | try: 37 | results = page.findAll('span', {"class" : "field-key"}) 38 | for entry in results: 39 | text = entry.text 40 | if re.search('F-PROT', text): 41 | e = entry.next.next.strip() 42 | response += Phrase(e) 43 | elif re.search('Command', text): 44 | e = entry.next.next.strip() 45 | response += Phrase(e) 46 | elif re.search('PEiD packer identifier', text): 47 | e= entry.next.next.strip() 48 | response += Phrase(e) 49 | except: 50 | raise MaltegoException('Could not find Packers') 51 | 52 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_hash2timestamp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from BeautifulSoup import BeautifulSoup 4 | from canari.maltego.utils import debug, progress 5 | from canari.framework import configure 6 | from canari.maltego.message import MaltegoException 7 | from common.entities import Hash 8 | from canari.maltego.entities import Phrase 9 | from common.vt import build 10 | import re 11 | 12 | __author__ = 'Keith Gilbert - @digital4rensics' 13 | __copyright__ = 'Copyright 2013, Malformity Project' 14 | __credits__ = [] 15 | 16 | __license__ = 'GPL' 17 | __version__ = '0.1' 18 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 19 | __email__ = 'Keith@digital4rensics.com' 20 | __status__ = 'Development' 21 | 22 | __all__ = [ 23 | 'dotransform', 24 | ] 25 | 26 | @configure( 27 | label='Hash to Compile Time - VirusTotal', 28 | description='Returns compile time of a hash from a VirusTotal report', 29 | uuids=[ 'malformity.v1.VT_Hash2Timestamp' ], 30 | inputs=[ ( 'VirusTotal', Hash ) ], 31 | debug=True 32 | ) 33 | 34 | def dotransform(request, response): 35 | page = build(request.value) 36 | try: 37 | comptime = page.find(text=re.compile('timedatestamp.....: '))[34:51] 38 | except: 39 | raise MaltegoException('Could not find Compile Time') 40 | 41 | response += Phrase(comptime) 42 | 43 | return response 44 | -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_ip2domain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import urllib2 4 | from canari.maltego.utils import debug, progress 5 | from BeautifulSoup import BeautifulSoup, NavigableString 6 | from canari.framework import configure #, superuser 7 | from canari.maltego.entities import IPv4Address, Domain 8 | 9 | __author__ = 'Marcus' 10 | __copyright__ = 'Copyright 2013, Marcus' 11 | __credits__ = [] 12 | 13 | __license__ = 'GPL' 14 | __version__ = '0.1' 15 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 16 | __email__ = 'Keith@digital4rensics.com' 17 | __status__ = 'Development' 18 | 19 | __all__ = [ 20 | 'dotransform', 21 | ] 22 | 23 | #@superuser 24 | @configure( 25 | label='IP to Domain - pDNS [VT]', 26 | description='IP to Domain - VT pDNS data', 27 | uuids=[ 'malformity.v1.VT_IP2Domain' ], 28 | inputs=[ ('VirusTotal', IPv4Address)], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | # Report transform progress 34 | progress(50) 35 | ip = request.value 36 | total="" 37 | 38 | urldom = 'https://www.virustotal.com/en/ip-address/'+ip+'/information/' 39 | soup = BeautifulSoup(urllib2.urlopen(urldom).read()) 40 | try: 41 | links = soup.findAll('div', attrs={'class':'enum'}) 42 | for link in links: 43 | total += str(link) 44 | total = BeautifulSoup(total) 45 | for totals in total.findAll('a',href=True): 46 | totals=totals['href'] 47 | theIP = totals.replace("/en/domain/", "") 48 | e = theIP.replace("/information/", "") 49 | e = Domain(e) 50 | response += e 51 | except IOError: 52 | print 'IO Error' 53 | 54 | 55 | # Update progress 56 | progress(100) 57 | 58 | 59 | # Return response for visualization 60 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_priv_domain2hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure 5 | from common.entities import Hash 6 | from canari.maltego.entities import Domain 7 | from common.vt import bsearch 8 | from canari.maltego.message import UIMessage 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='Domain Search - VirusTotal [Private]', 26 | description='Searches VirusTotal for samples based on a domain', 27 | uuids=[ 'malformity.v1.VT_Priv_Domain2Hash' ], 28 | inputs=[ ( 'VirusTotal', Domain ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | data = bsearch(request.value) 34 | try: 35 | if data['response_code'] == 1: 36 | results = data['hashes'] 37 | for result in results: 38 | response += Hash(result) 39 | except: 40 | response += UIMessage(data['verbose_msg']) 41 | 42 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_priv_hash2exiftool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure 5 | from common.entities import Hash, Filename 6 | from canari.maltego.entities import Phrase 7 | from canari.maltego.message import UIMessage 8 | from common.vt import getreport 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='Hash to ExifTool - VirusTotal [Private]', 26 | description='Returns ExifTool details from a report on VT', 27 | uuids=[ 'malformity.v1.VT_Priv_Hash2ExifTool' ], 28 | inputs=[ ( 'VirusTotal', Hash ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | data = getreport(request.value) 34 | 35 | try: 36 | try: 37 | exif = data['additional_info']['exiftool'] 38 | except: 39 | #no exif data 40 | pass 41 | try: 42 | prod = exif['ProductName'] 43 | response += Phrase(prod) 44 | except: 45 | #no Product Name 46 | pass 47 | try: 48 | lang = exif['LanguageCode'] 49 | response += Phrase(lang) 50 | except: 51 | #no language code 52 | pass 53 | try: 54 | char = exif['CharacterSet'] 55 | response += Phrase(char) 56 | except: 57 | #no character set 58 | pass 59 | try: 60 | orig = exif['OriginalFilename'] 61 | response += Filename(orig) 62 | except: 63 | #no original name 64 | pass 65 | try: 66 | time = exif['Timestamp'] 67 | response += Phrase(time) 68 | except: 69 | #no timestamp 70 | pass 71 | try: 72 | intern = exif['InternalName'] 73 | response += Phrase(intern) 74 | except: 75 | #no internal name 76 | pass 77 | try: 78 | type = exif['FileType'] 79 | response += Phrase(type) 80 | except: 81 | #no filetype 82 | pass 83 | try: 84 | desc = exif['FileDescription'] 85 | response += Phrase(desc) 86 | except: 87 | #no file description 88 | pass 89 | try: 90 | copy = exif['LegalCopyright'] 91 | response += Phrase(copy) 92 | except: 93 | #no copyright data 94 | pass 95 | try: 96 | entry = exif['EntryPoint'] 97 | response += Phrase(entry) 98 | except: 99 | #no entry point 100 | pass 101 | try: 102 | ver1 = exif['FileVersionNumber'] 103 | response += Phrase(ver1) 104 | except: 105 | #no File Version Number 106 | pass 107 | try: 108 | ver2 = exif['ProductVersion'] 109 | response += Phrase(ver2) 110 | except: 111 | #no Product Version 112 | pass 113 | except: 114 | response += UIMessage(data['verbose_msg']) 115 | 116 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_priv_hash2netactivity.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure 5 | from common.entities import Hash, UserAgent, HTTPRequest 6 | from canari.maltego.entities import Domain, IPv4Address, URL, Port 7 | from canari.maltego.message import UIMessage 8 | from common.vt import getbehavior 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='Hash to Network Information - VirusTotal [Private]', 26 | description='Returns network details from a behavioural report on VT', 27 | uuids=[ 'malformity.v1.VT_Priv_Hash2NetActivity' ], 28 | inputs=[ ( 'VirusTotal', Hash ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | data = getbehavior(request.value) 34 | 35 | try: 36 | try: 37 | network = data['network'] 38 | except: 39 | #no network data 40 | pass 41 | try: 42 | for result in network['dns']: 43 | dom = result['hostname'] 44 | ip = result['ip'] 45 | response += Domain(dom) 46 | response += IPv4Address['ip'] 47 | except: 48 | #no dns data 49 | pass 50 | try: 51 | for request in network['http']: 52 | uri = URL(request['uri']) 53 | uri.url = request['uri'] 54 | 55 | ua = UserAgent(request['user-agent']) 56 | #req = HTTPRequest(request['data']) 57 | port = Port(request['port']) 58 | 59 | response += uri 60 | response += ua 61 | #response += req 62 | response += port 63 | except: 64 | #no http data 65 | pass 66 | try: 67 | for entry in network['tcp']: 68 | e = entry['dst'] 69 | if e.startswith('10.'): 70 | pass 71 | else: 72 | conn = IPv4Address(e) 73 | response += conn 74 | except: 75 | #no tcp data 76 | pass 77 | except: 78 | response += UIMessage(data['verbose_msg']) 79 | 80 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_priv_hash2pesig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure 5 | from common.entities import Hash, Filename 6 | from canari.maltego.entities import Phrase 7 | from canari.maltego.message import UIMessage 8 | from common.vt import getreport 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='Hash to PE Signature - VirusTotal [Private]', 26 | description='Returns SigCheck details from a PESig section of a report on VT', 27 | uuids=[ 'malformity.v1.VT_Priv_Hash2PESig' ], 28 | inputs=[ ( 'VirusTotal', Hash ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | data = getreport(request.value) 34 | 35 | try: 36 | try: 37 | addinfo = data['additional_info'] 38 | except: 39 | #no additional info 40 | pass 41 | try: 42 | pub = addinfo['sigcheck']['publisher'] 43 | response += Phrase(pub) 44 | except: 45 | #no dns data 46 | pass 47 | try: 48 | prod = addinfo['sigcheck']['product'] 49 | response += Phrase(prod) 50 | except: 51 | #no product data 52 | pass 53 | try: 54 | desc = addinfo['sigcheck']['description'] 55 | response += Phrase(desc) 56 | except: 57 | #no description data 58 | pass 59 | try: 60 | orig = addinfo['sigcheck']['original name'] 61 | response += Filename(orig) 62 | except: 63 | #no original name 64 | pass 65 | try: 66 | sign = addinfo['sigcheck']['signers'] 67 | response += Phrase(sign) 68 | except: 69 | #no signers 70 | pass 71 | try: 72 | intern = addinfo['sigcheck']['internal name'] 73 | response += Phrase(intern) 74 | except: 75 | #no internal name 76 | pass 77 | except: 78 | response += UIMessage(data['verbose_msg']) 79 | 80 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_priv_ip2hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure 5 | from common.entities import Hash 6 | from canari.maltego.entities import IPv4Address 7 | from common.vt import bsearch 8 | from canari.maltego.message import UIMessage 9 | 10 | __author__ = 'Keith Gilbert - @digital4rensics' 11 | __copyright__ = 'Copyright 2013, Malformity Project' 12 | __credits__ = [] 13 | 14 | __license__ = 'GPL' 15 | __version__ = '0.1' 16 | __maintainer__ = 'Keith Gilbert - @digital4rensics' 17 | __email__ = 'Keith@digital4rensics.com' 18 | __status__ = 'Development' 19 | 20 | __all__ = [ 21 | 'dotransform', 22 | ] 23 | 24 | @configure( 25 | label='IP Search - VirusTotal [Private]', 26 | description='Searches VirusTotal for samples based on an IP', 27 | uuids=[ 'malformity.v1.VT_Priv_IP2Hash' ], 28 | inputs=[ ( 'VirusTotal', IPv4Address ) ], 29 | debug=True 30 | ) 31 | 32 | def dotransform(request, response): 33 | data = bsearch(request.value) 34 | try: 35 | if data['response_code'] == 1: 36 | results = data['hashes'] 37 | for result in results: 38 | response += Hash(result) 39 | except: 40 | response += UIMessage(data['verbose_msg']) 41 | 42 | return response -------------------------------------------------------------------------------- /src/Malformity/transforms/vt_url2engine.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from canari.maltego.utils import debug, progress 4 | from canari.framework import configure #, superuser 5 | from canari.config import config 6 | from canari.framework import configure 7 | from canari.maltego.message import Label 8 | from canari.maltego.utils import debug 9 | from canari.maltego.entities import Phrase, URL 10 | from common.entities import Hash 11 | from json import loads 12 | from urllib import urlopen, urlencode 13 | 14 | __author__ = 'Kyle Maxwell' 15 | __copyright__ = 'Copyright 2012, Kyle Maxwell' 16 | __credits__ = [] 17 | 18 | __license__ = 'GPL' 19 | __version__ = '0.1' 20 | __maintainer__ = 'Kyle Maxwell' 21 | __email__ = '@kylemaxwell' 22 | __status__ = 'Development' 23 | 24 | __all__ = [ 25 | 'dotransform', 26 | ] 27 | 28 | 29 | @configure( 30 | label="To AV Engine [VT]", 31 | description="Returns names of AV engines that flagged the URL", 32 | uuids=['malformity.v1.VT_URL2Engine'], 33 | inputs=[('VirusTotal', URL)], 34 | debug=False 35 | ) 36 | 37 | def dotransform(request, response): 38 | 39 | debug('VT API key %s\n' % config['virustotal/apikey']) 40 | 41 | r = urlopen( 42 | "https://www.virustotal.com/vtapi/v2/url/report", 43 | urlencode({ 44 | "resource": request.value, 45 | "apikey": config['virustotal/apikey'] 46 | }) 47 | ) 48 | 49 | if r.code == 200: 50 | d = loads(r.read()) 51 | debug('VT output: %s\n' % d) 52 | 53 | if d['response_code'] == 1: 54 | for engine in d['scans'].iteritems(): 55 | if engine[1]['detected']: 56 | e = Phrase(engine[0]) 57 | e += Label("VirusTotal Report", d['permalink']) 58 | response += e 59 | 60 | return response 61 | --------------------------------------------------------------------------------