Consider the Website Entity: It has a static property called Ports with a default of 80. Maltego defines this as a list of integers, but it needs to be handled differently in TRX.
Let’s start a new Transform. We’ll call it ‘Mangle’ and register it on the TDS (using a website Entity).
Our Transform code looks like this:
def create_entities(cls, request, response): if (not request.Value.isdigit()): response.addUIMessage("Sorry but [" + request.Value + "] is not a whole number", UIM_TYPES["partial"]) else: isdiv = request.getTransformSetting('ISDIV') if (not isdiv.isdigit()): response.addUIMessage('Silly! We need a number',UIM_TYPES["fatal"]) else: howmany = int(request.Value) accum = 0 for i in range(1, howmany + 1): if (i % int(isdiv) == 0): Ent =response.addEntity('maltego.AS', str(i)) Ent.setWeight( howmany - 1 ) accum = accum + 1 if (accum >= request.Slider): break
We use the ‘getProperty’ method to get the property’s value. You will see that we do not return any Entities, which is correct, we simply write a message to the output with the Output screen. On a default website Entity the output looks like this:
If we add a port to the list…
...and run the Transform again we get:
The list is returned as a comma-delimited list.
Adding dynamic properties
We can write properties using the Maltego TRX Python Library. Each property has a:
Display Name: The name displayed in Maltego
Name: The unique name referenced in code
Value: The value of the property
Matching rule: Whether this property must be the same as for other Entities before merging
Let’s assume we want to create a Transform that runs on an IP address and generates a netblock. It will always assume a class C netblock (255 IPs) but it will add a dynamic property to the netblock to indicate if it’s a private netblock or not. We’ll do this with a dynamic property called ‘private’ and it will be set to ‘yes’ or ‘no’.
Create a new Transform code file and register the Transform on the TDS. We begin our Transform (without input validation) like this:
from maltego_trx.transform import DiscoverableTransform from IPy import IP from maltego_trx.entities import Netblock class NetblocksRUs(DiscoverableTransform): """ Transform returns a netblock for an IP address input. """ @classmethod def create_entities(cls, request, response): start = request.Value[0:request.Value.rfind('.')] netblock = start + ".0-" + start + ".255" Ent = response.addEntity('maltego.Netblock') Ent.setValue(netblock)
Note that at this point we haven’t added any dynamic properties to the netblock. We need to first have something that checks if an IP address is private or not. A quick search on the Internet finds this useful Python routine:
>>> from IPy import IP >>> ip = IP('10.0.0.1') >>> ip.iptype() 'PRIVATE'
This function relies on a Python module called IPy. On Ubuntu installing this is as simple as:
sudo apt-get install python-ipy
or use PIP install:
pip3 install IPy
We add a line importing this library into our Transform code file (NetblocksRUs.py) file:
from IPy import IP
The Transform now appears as follows:
class NetblocksRUs(DiscoverableTransform): """ Transform returns a netblock for an IP address input. """ @classmethod def create_entities(cls, request, response): start = request.Value[0:request.Value.rfind('.')] netblock = start + ".0-" + start + ".255" Ent = response.addEntity('maltego.Netblock') ip = IP(request.Value) if (ip.iptype() == 'PRIVATE'): Ent.addProperty('private','Private network','strict','yes') else: Ent.addProperty('private','Private network','strict','no') Ent.setValue(netblock)
Now running the Transform on two different IP addresses we get:
Yes, we can create a Transform that uses netblocks as input and simply outputs a phrase ‘public’ or ‘private’ (though not very useful, this does indicate how to use additional properties).
from maltego_trx.transform import DiscoverableTransform from maltego_trx.entities import Phrase class PublicPrivate(DiscoverableTransform): """ A transform that uses netblocks as input and simply outputs a phrase ‘public’ or ‘private’. """ @classmethod def create_entities(cls, request, response): Ent = response.addEntity('maltego.Phrase') if request.getProperty('private')=='yes': Ent.setValue('Private') else: Ent.setValue('Public')
The resultant graph (when populated with some IPs->Netblock->Public/Private) in a Bubble view block layout:
Developer reference for Maltego-TRX library can be found here: Maltego TRX Python Library