Developer: Local Transforms

What are Local transforms?

Local transforms are pieces of code that run on the same machine which the client application is. These are very useful for integrating in machine specific tasks (such as running an application thats locally on the machine- like nmap OR a task that is dependent on a setup on the machine such as accessing data over a VPN). These transforms can be written in any language (yes, *any* language) and merely rely on output to be sent via STDOUT (think a command line application).

Specification / Guide

The Maltego local transform specification explains in detail how to go about creating local transforms and the XML associated with these. It is a fantastic guide to extending Maltego.


As it stands there are 4 libraries to help with the development of local transforms. If you have one please feel free to send it in and we will add it to the list!

Name Language Description Author Download
Maltego Transform-py Python Very Basic Python library Andrew MacPherson (Paterva)
Maltego Transform-php PHP Very Basic PHP library Andrew MacPherson (Paterva)
PyMaltego Python PyMaltego is a python module which provides facilities for creating and interacting with Maltego Transforms. The Grugq
Sploitegp Python Sploitego is a rapid local transform development framework for Maltego written in Python. Nadeem Douba

Transform Overview

Transforms should be thought of as tiny pieces of code that take one type of information to another. It is very important to write transforms in such a way that they are extensible (transforms can add on to others) and get the smallest pieces of information out rather than large blocks at a time. The reason we emphasize small pieces of information is that it means we can harness the power of Maltego's link analysis. Take the two images below for example (they merely show IP addresses as well as ports and banners):

The graph on the left has a whole layer less, whilst showing the same information. However using the graph on the right allows the analyst to quickly look at things like all services running on port 80. Doing the same on the graph on the left would however mean you would have to traverse up the tree to the IP addresses and then down again to the services giving you other services that are not running on port 80.

How Local transforms work

Local transforms are called from the command line and interacted with via STDIN and STDOUT. When you right click on an entity and execute a transform it sends through the following to the executable (your transform):
  • Entity Value (what is displayed on the graph) -- this is the first argument.
  • Entity Fields (the fields contained in the entity), these are seperated by #'s and each field is seperated - name and value by an '=' sign.
For example, if you had a person entity of 'Andrew MacPherson' (as displayed on the graph), it would have the fields:

Display Name (in details) Variable Name Value
Full Name person.fullname Andrew MacPherson
First Names person.firstnames Andrew
Surname person.lastname MacPherson

(these fields can all be found by clicking on Manage entities under the Manage tab, finding the entity in question and click on the (...) next to its name and navigating to the Additional Properties tab)

The execution of a transform on the above entity would be as follows (if i was running a python script called '' in /home/andrew/localTransforms):

andrew@devBox3: /home/andrew/localTransforms/# /usr/bin/python "Andrew MacPherson" person.fullname=Andrew MacPherson#person.firstnames=Andrew#person.lastname=MacPherson

At a minimum a transform needs to simply return valid XML (this is all covered in the Specification above) via STDOUT, something like: <MaltegoMessage> <MaltegoTransformResponseMessage> <Entities> <Entity Type="maltego.Phrase"> <Value>Hello Transform World</Value> </Entity> </Entities> </MaltegoTransformResponseMessage> </MaltegoMessage>
In the above you can see that we are returning just a single entity which is a Phrase and has a value of 'Hello Transform World'. If I had specified it to run on a domain and executed it I would have got the following within the client:

Local transforms are really *that* simple, just return valid XML and you can do anything with them from running external applications to integrating with APIs.

Adding a new transform

Step1: Transforms can be added within the client by click on the manage tab and then Local Transform.

Step2: Fill in the first screen of the dialog (the transform meta data), the fields are described below:

  • Display Name - This is the name the end user will see in the client when right clicking on an entity.
  • Description - Description of the transform.
  • Transform ID - *NOTE* This setting is very important and cannot be changed after the transform is added. It should be in the format of category.transform, eg. AndrewsNmapTransforms.nmapVersionScan
  • Author - The author of the transform.
  • Input Entity Type - This is the entity type that the user will right click on to view this transform, transforms are specific to the type of entity they run on (ie, if this field is set to a Domain entity you will not see the transform when you right click on a Website entity).
  • Transform Set - If you would like this transform within a set you can set this here.

Step3: Fill in the second screen of the dialog (the transform settings), the fields are described below:

  • Command - This is the application that will be executed. If you are using a scripting language this will be the script interpreter.
  • Parameters - The command line parameters. If you are using a scripting language (like Python/PHP/Ruby) this will most likely be the actual script to run.
  • Working Directory - *NOTE* This is the directory that the command with parameters will be executed

You should test your transforms by going to the working directory and running the script as seen in the bottom window ( Command line to be executed (in working directory): )

Code Examples / Snippets:

These are a few code snippets from using the basic Maltego Python library:

Hello World

This transform merely returns "hello world" as a phrase, it doesn't depend on the input entity at all: from MaltegoTransform import * me = MaltegoTransform() me.addEntity("maltego.Phrase","hello world"); me.returnOutput()
Reading Input

This is simple transform to show reading input from an entity and returning it to the graph (in this case working with a domain and returning a phrase with that domain in it): from MaltegoTransform import * import sys domain = sys.argv[1] me = MaltegoTransform() me.addEntity("maltego.Phrase","hello " + domain) me.returnOutput()
Reading Entity Properties

This example simply illustrates using the library to read the properties of an entity and printing them out. Note this is just a snippet, not a transform!
from MaltegoTransform import * import sys me = MaltegoTransform() me.parseArguments(sys.argv); longitude = me.getVar("longitude") latitude = me.getVar("latitude") print longitude print latitude
Returning a complex entity

This transform example shows reading an entity as well as setting properties, additional fields, a UI message and the weight of the entity (run on a domain):
from MaltegoTransform import * import sys me = MaltegoTransform() domain = sys.argv[1] thisent = me.addEntity("maltego.Domain","hello " + domain) thisent.setType("maltego.Domain") thisent.setValue("Complex." + domain) thisent.setWeight(200) thisent.setDisplayInformation("<h3>Heading</h3><p>content here about" + domain + "!</p>"); thisent.addAdditionalFields("variable","Display Value",True,domain) me.addUIMessage("completed!") me.returnOutput()