Going beyond Wireshark: experiments in visualising network traffic

At NVISO Labs, we are constantly trying to find better ways of understanding the data our analysts are looking at. This ranges from our SOC analysts looking at millions of collected data points per day all the way to the malware analyst tearing apart a malware sample and trying to make sense of its behaviour.

In this context, our work often involves investigating raw network traffic logs. Analysing these often takes a lot of time: a 1MB network traffic capture (PCAP) can easily contain several hundred different packets (and most are much larger!). Going through these network events in traditional tools such as Wireshark is extremely valuable; however they are not always the best to quickly understand from a higher level what is actually going on.

In this blog post we want to perform a series of experiments to try and improve our understanding of captured network traffic as intuitively as possible, by exclusively using interactive visualisations.

Screen Shot 2018-02-15 at 00.07.26.png

A screen we are all familiar with – our beloved Wireshark! Unmatched capabilities to analyse even the most exotic protocols, but scrolling & filtering through events can be daunting if we want to quickly understand what is actually happening inside the PCAP. In the screenshot a 15Kb sample containing 112 packets.

For this blog post we will use this simple 112 packet PCAP to experiment with novel ways of visualising and understanding our network data. Let’s go!

Experiment 1 – Visualising network traffic using graph nodes
As a first step, we simply represent all IP packets in our PCAP as unconnected graph nodes. Each dot in the visualisation represents the source of a packet. A packet being sent from source A to destination B is visualised as the dot visually traveling from A to B. This simple principle is highlighted below. For our experiments, the time dimension is normalised: each packet traveling from A to B is visualised in the order they took place, but we don’t distinguish the duration between packets for now.


IP traffic illustrated as interactive nodes.

This visualisation already allows us to quickly see and understand a few things:

  • We quickly see which IP addresses are most actively communicating with each other ( and
  • It’s quickly visible which hosts account for the “bulk” of the traffic
  • We see how interactions between systems change as time moves on.

A few shortcomings of this first experiment include:

  • We have no clue on the actual content of the network communication (is this DNS? HTTP? Something else?)
  • IP addresses are made to be processed by a computer, not by a human; adding additional context to make them easier to classify by a human analyst would definitely help.

Experiment 2 – Adding context to IP address information
By using basic information to enrich the nodes in our graph, we can aggregate all LAN traffic into a single node. This lets us quickly see which external systems our LAN hosts are communicating with:


Tagging the LAN segment clearly shows which packets leaves the network.

By doing this, we have improved our understanding of the data in a few ways:

  • We can very quickly see which traffic is leaving our LAN, and which external (internet facing) systems are involved in the communication.
  • All the internal LAN traffic is now represented as 1 node in our graph; this can be interesting in case our analyst wants to quickly check which network segments are involved in the communication.

However, we still face a few shortcomings:

  • We still don’t really have a clue on the actual content of the network communication (is this DNS? HTTP? Something else?)
  • We don’t know much about the external systems that are being contacted.

Experiment 3 – Isolating specific types of traffic
By applying simple visual filters to our simulation (just like we do in tools like Wireshark), we can make a selection of the packets we want to investigate. The benefit of doing this is that we can easily focus on the type of traffic we want to investigate without being burdened with things we don’t care about at that point in time of the analysis.

In the example below, we have isolated DNS traffic; we quickly see that the PCAP contains communication between hosts in our LAN (remember, the LAN dot now represents traffic from multiple hosts!) and 2 different DNS servers.


When isolating DNS traffic in our graph, we clearly see communication with a non-corporate DNS server.

Once we notice that the rogue DNS server is being contacted by a LAN host, we can change our visualisation to see which domain name is being queried by which server.We also conveniently attached the context tag “Suspicious DNS server” to host (the result of our previous experiment). The result is illustrated below. It also shows that we are not only limited by showing relations between IP addresses; we can for example illustrate the link between the DNS server and the hosts they query.


We clearly see the suspicious DNS server making request to 2 different domain names. For each request made by the suspicious DNS server, we see an interaction from a host in the LAN.

Even with larger network captures, we can use this technique to quickly visualise connectivity to suspicious systems. In the example below, we can quickly see that the bulk of all DNS traffic is being sent to the trusted corporate DNS server, whereas a single hosts is interacting with the suspicious DNS server we identified before.


So what’s next?
Nothing keeps us from entirely changing the relation between two nodes; typically, we are used to visualising packets as going from IP address A to IP address B; however, more exotic visualisations as possible (think about the relations between user-agents and domains, query lengths and DNS requests, etc.); in addition, there is plenty of opportunity to add more context to our graph nodes (link an IP address to a geographical location, correlate domain names with Indicators of Compromise, use whitelists and blacklists to more quickly distinguish baseline vs. other traffic, etc.). These are topics we want to further explore.

Going forward, we plan on continuing to share our experiments and insights with the community around this topic! Depending on where this takes us, we plan on releasing part of a more complete toolset to the community, too.


Making our lab rats happy, 1 piece of cheese at a time!

Squeesh out! 🐀

About the author
Daan Raman is in charge of NVISO Labs, the research arm of NVISO. Together with the team, he drives initiatives around innovation to ensure we stay on top of our game; innovating the things we do, the technology we use and the way we work form an essential part of this. Daan doesn’t like to write about himself in third-person. You can contact him at draman@nviso.be or find Daan online on Twitter and LinkedIn.


Using a custom root CA with Burp for inspecting Android N traffic

TL;DR: Follow these steps to intercept traffic using Burp with a self made root CA on Android (or any browser)

The problem

In a previous blogpost, we presented a Magisk module that easily integrates user certificates into the system CA store in order to bypass Android N’s new hardened security model. For instrumenting applications, this works pretty well, and it has become a standard module on our pentest devices. The flow is really easy:

  1. Set up your WIFI to use Burp as your proxy
  2. Go to http://burp
  3. Download & install the certificate
  4. Reboot

However, if we now open Chrome on the Android device, we get the following error: NET::ERR_CERT_VALIDITY_TOO_LONG.

If we take a look at the specifics of the certificate, we see that the certificate expires on Jan 11, 2023. A quick google search tells us that Google has chosen only to allow leaf certificates that expire within 39 months. This seems like a reasonable requirement, and after searching Portswigger’s site, the recommendation was to reissue the Burp CA certificate. Unfortunately, the problem persisted after doing so.

Burp also allows us to import a self made certificate + private key to be used instead of the automatically generated one. This sounds like an easy solution, as we can decrease the lifetime of the root CA, so it’s the next obvious step. In practice, it turns out to be a lot more difficult to get the configuration right than you would think. The goal of this blog post isn’t about all my failed attempts and why they failed, but about sparing you the trouble and giving you a working step-by-step guide to get this to work.

As a side note, this problem does not occur with the normal setup, where Burp’s root CA is added as a trusted user certificate. Chrome is only picky about “real” CA, which are evidently installed in the system root CA store. However, as I would like to have one certificate setup to rule them all, I searched for a solution…

The solution – Creating custom CA and importing it into Burp suite

I order to successfully install our custom root CA in both Burp and Android, we need to create a CA that has the v3_ca extension. The following steps are executed on a clean 14.04 Ubuntu installation. Granted, there are only a few steps to the processes, but that’s only because I’m not listing all my failed attempts.

# Keep it clean
> mkdir certificates && cd certificates

# Install openssl
> sudo apt-get install openssl

# Borrow the default openssl.cnf (location may differ, see note)
> cp /usr/lib/ssl/openssl.cnf ./

# Create a private key. 
# It's important to have the v3_ca extension and to supply the openssl.cnf file
> openssl req -x509 -days 730 -nodes -newkey rsa:2048 -outform der -keyout server.key -out ca.der -extensions v3_ca -config openssl.cnf
Generating a 2048 bit RSA private key
writing new private key to 'server.key'
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
Country Name (2 letter code) [AU]:BE
State or Province Name (full name) [Some-State]:NVISO CA
Locality Name (eg, city) []:NVISO CA
Organization Name (eg, company) [Internet Widgits Pty Ltd]:NVISO CA
Organizational Unit Name (eg, section) []:NVISO CA
Common Name (e.g. server FQDN or YOUR name) []:NVISO CA
Email Address []:NVISO CA

# Convert to der format
> openssl rsa -in server.key -inform pem -out server.key.der -outform der
writing RSA key

# Convert key to pkcs8 format
> openssl pkcs8 -topk8 -in server.key.der -inform der -out server.key.pkcs8.der -outform der -nocrypt

Note: The openssl.cnf may be in a different place. Alternatively, you can download the default config from the openssl website.

Let’s take a quick look at the generated certificate:

> openssl x509 -in ca.der -inform der -noout -text
 Version: 3 (0x2)
 Serial Number: 17570736880079538514 (0xf3d7cc1942ff0952)
 Signature Algorithm: sha256WithRSAEncryption
 Not Before: Jan 11 16:23:19 2018 GMT
 Not After : Jan 11 16:23:19 2020 GMT
 Subject Public Key Info:
 Public Key Algorithm: rsaEncryption
 Public-Key: (2048 bit)
 Exponent: 65537 (0x10001)
 X509v3 extensions:
 X509v3 Subject Key Identifier: 
 X509v3 Authority Key Identifier: 

X509v3 Basic Constraints: 
 Signature Algorithm: sha256WithRSAEncryption

The generated certificate has the v3_ca extension enabled, so we can import it into Android. Using our magisk module, you can install this certificate through the normal certificate installation flow, and after rebooting your device, the CA should be listed in the system CA store.


The next step is importing these files into Burp. Go to the proxy settings page and choose “Import / Export CA Certificate” -> “Import” -> “Certificate and priate key in DER format”. The correct files to choose are `ca.der` and server.key.pkcs8.der:


After installing the certificate, restart Burp just to be sure.

If everything worked, you’ll now have your custom root CA as a system certificate, and you can intercept all chrome traffic.

It took quite some time to figure out the correct procedure, so I hope I’ve at least saved someone else from spending hours trying to figure it out.

And, in order to help anyone searching for the correct answer, here’s a short overview of the problems I encountered:

  • NET::ERR_CERT_VALIDITY_TOO_LONG (-> Make sure your certificate’s validity is not longer than 39 months)
  • Custom root CA won’t install correctly on Android (-> Make sure it has the v3_ca extension)
  • Burp import errors (-> Follow the steps above for correct setup)
    • Failed to import certificate: java.security.cert.CertificateParsingException: signed fields invalid
    • Failed to import certificate: java.security.cert.CertificateException: Unable to initialize, java.io.IOException: extra data given to DerValue constructor
  • OS X / MacOS openssl: Error Loading extension section v3_ca (-> Copy the openssl.cnf file and manually add it as an argument with -config )


About the author

Jeroen Beckers is a mobile security expert working in the NVISO Cyber Resilience team. He also loves to program, both on high and low level stuff, and deep diving into the Android internals doesn’t scare him. You can find Jeroen on LinkedIn.

Windows Credential Guard & Mimikatz

Here at NVISO, we are proud to have contributed to the new SANS course “SEC599: Defeating Advanced Adversaries – Implementing Kill Chain Defenses”.

This six-day training focuses on implementing effective security controls to prevent, detect and respond to cyber attacks.

One of the defenses covered in SEC599 is Credential Guard. Obtaining and using credentials and hashes from memory (for example with Mimikatz) is still a decisive tool in the arsenal of attackers, one that is not easy to defend against.
With Windows 10 and Windows Server 2016, Microsoft introduced a feature to mitigate attacks to obtain credentials and hashes: Credential Guard. With Credential Guard, secrets are stored in a hardened and isolated section of your computer, inaccessible from the normal operating system.

Credential Guard relies on a new technology introduced with Windows 10 and Windows Server 2016: Virtual Secure Mode (VSM). VSM is based on the virtualization features of modern CPUs to provide a separate memory space where secrets can be stored. This separate memory space is protected (via hardware) from read and write attempts from processes in the normal operating system’s memory space.

When Credential Guard is enabled, the Local Security Authority Subsystem Service (LSASS) consists of 2 processes: the normal LSA process and the isolated LSA process (which runs in VSM).

Credential Guard

SANS SEC599 day 4: Credential Guard

Tools that recover secrets from LSA, like Mimikatz, are not able to access the isolated LSA process. They cannot extract passwords or inject hashes for pass-the-hash attacks, for example. Hence, Credential Guard is an effective tool to protect credentials stored on Windows machines.

Despite Credential Guard, users with administrative access can still find ways to steal credentials entered on Windows machines. This can be done, for example, with Mimikatz own Security Support Provider. SSPs are packages that participate in the authentication of users: for example, installed SSPs will be called when a user logs on, and will receive the credentials of said user. Windows comes with several SSPs , and custom SSPs can be installed (of course, this requires administrative permissions).

Mimikatz memssp command (available since September 2014) installs a custom SSP in memory (so no DLL is written to disk), that will log all credentials it receives in a text file.

To achieve this, Mimikatz needs to be executed with administrative rights on the target machine and the debug privilege needs to be enabled to allow the LSA processes to be opened and patched:


Next, Mimikatz’s SSP is injected with the misc::memssp command:


Now the SSP is installed, Mimikatz can be closed. This SSP will remain in memory as long as Windows is not rebooted.

After a user has performed a log on, Mimikatz’s SSP log C:\Windows\System32\mimilsa.og file can be examined to retrieve the credentials processed by Mimikatz’s SSP:



Mimikatz can not extract credentials protected by Credential Guard, but it can intercept credentials entered in a Windows machine at log on time, for example. Although Credential Guard will protect credentials in isolated memory, credentials still need to be provided to a Windows machine (like for an interactive logon).

When these credentials are typed, they can still be intercepted and stolen, e.g. with a key logger or with with a custom SSP, as illustrated here. This is however only one of the steps in the attack chain, as this requires administrative rights, it is crucial to restrict and monitor administrative access to your Windows machines.

New year, new vulnerabilities: Spectre & Meltdown

Two new vulnerabilities “Spectre” and “Meltdown” were recently discovered, affecting millions of systems worldwide. Please find our security advisory below.

spectre                                                     meltdown 

Spectre and Meltdown are hardware vulnerabilities in the microprocessors (CPUs) that, when exploited, allow an attacker to read the content of memory he/she is not allowed to access. Some key things to know about these vulnerabilities:

  • Proof of concept code for Meltdown demonstrates that a low privilege user process can read all kernel memory from major operating systems on Intel CPUs;
  • Proof of concept code for Spectre demonstrates that a low privilege user process can read memory from other processes on all major operating systems on CPUs from all major vendors;
  • Spectre and Meltdown attacks can be used to break through security boundaries implemented by operating systems to steal confidential data, including passwords and secret keys;
  • Patches are already available for the mitigation of Meltdown;
  • Long-term solution will consist of redesigning the CPU infrastructure by the vendors.

How does it work?
Both vulnerabilities rely on exploiting side-effects of “out-of-order execution” and “speculative execution”.

  • Out-of-order execution is a performance feature of CPUs that allows for non-sequential execution of machine instructions. Instead of executing machine instructions step by step in the order specified by the program (like old fashioned CPUs do), CPUs nowadays speed up execution of programs by simultaneously executing several machine instructions of the program, but not necessarily in the order specified by the program (this is called out-of-order execution).
  • Speculative-execution takes this concept further, and executes instructions that may actually not have to be executed. The instructions are executed before it is known that they have to be executed (this is done to maximize the utilization of the CPU). The implication is that machine instructions are being executed that ultimately should not have been executed, for example because a conditional branch is taken. The results of these “unnecessary” machine instructions are discarded.

The Spectre and Meltdown vulnerabilities leverage these discarded results.

The Spectre vulnerability (CVE-2017-5715 and CVE-2017-5753) is actually a class of vulnerabilities in CPUs that implement speculative-execution, and more precisely branch-prediction (Meltdown is considered to be a particular case of Spectre). Branch-prediction is implemented by the CPU circuits that try to predict which branch of a conditional execution will be executed. The branch with the highest probability of execution is executed via out-of-order execution. Exploiting Spectre relies on the fact that the branch-prediction circuitry can be manipulated (by exploit code) to assign a higher probability on a chosen branch. Spectre exploits will search for branches that access memory that is outside of the security context of the running exploit (hence not allowed to be read), and then manipulate the branch-prediction algorithms to execute these branches out-of-order. But because the results of these instructions are discarded (the branches would not have been executed in a sequential execution), Spectre exploits have to use side-channels attacks to recover the discarded results. A side effect of out-of-order execution is that memory content is loaded into cache-lines. The side-channel attack relies on the timing of instructions to determine what data was loaded into the cache-lines: an instruction will execute faster if the data it requires is already in the cache-line.

The exploitation of the Meltdown vulnerability (CVE-2017-5754) relies on a privilege escalation vulnerability in Intel CPUs (this privilege escalation vulnerability exists in most Intel CPUs since 1995). An exploit for the Meltdown vulnerability will execute an instruction that causes a trap. Because of this trap, the results of instructions that were executed out-of-order are discarded. Next, the exploit will use an Intel privilege escalation vulnerability to access the results of the discarded instructions. In proof of concepts, the discarded instructions are used to read kernel memory. This should not be allowed by code running inside a user-land process, but this security decision is only taken after the out-of-order execution. Consequently, the combination of a trap and privilege escalation can be used to read memory that is normally not accessible to the code.

What is the impact?
Meltdown impacts workstations, laptops, servers (also cloud servers) running Linux, Windows or macOS.

Spectre impacts workstations, laptops, servers (also cloud servers), smartphones, tablets,… Virtually any device that runs on vulnerable CPUs from Intel, AMD and ARM.

What should we do?
At the time of writing this advisory, there are no patches available to mitigate the Spectre vulnerability.

Patches have been released for Windows, Linux and MacOS to mitigate the Meltdown vulnerability in Intel CPUs. These are patches for the kernel that implement Kernel Page-Table Isolation (KPTI, also known as KAISER). KPTI mitigates the Meltdown vulnerability by completely separating user-space and kernel-space page tables. Before this patch, user-space and kernel-space page tables were not separated for performance reasons. Reports exists that KPTI impacts performance, some speculating up to 30% loss in CPU performance.

We recommend to execute performance tests with these patches on high-load machines before deploying these patches in production.

NOTE: Microsoft published information that some anti-virus products are not compatible with their patches, and may cause a BSOD (Blue Screen Of Death). So before installing updates, check with your AV vendor first. (https://support.microsoft.com/en-us/help/4072699/important-information-regarding-the-windows-security-updates-released).

Exploiting the Spectre and Meltdown vulnerabilities requires code execution on vulnerable CPUs. Until these vulnerabilities have been completely addressed, strict control of code execution (like application whitelisting) can help mitigate attacks for these vulnerabilities. Be aware that proof of concepts are already available for Spectre and Meltdown, written in JavaScript. Control of code execution must not only address binary executables, but also scripting.

Ultimately, the Spectre and Meltdown vulnerabilities have to be addressed by redesigning CPU architectures. As a typical CPU release cycle takes 18 months, this implies that it will take several years before new CPUs are produced and widely deployed.

Update 05/01/2018:

There are now 2 tools available to check Windows systems for these vulnerabilities. Microsoft has released a PowerShell script (SpeculationControl) and Alex Ionescu has released a Windows executable (SpecuCheck).

Here is the output of Get-SpeculationControlSettings on an unpatched machine:

Here is the output of Get-SpeculationControlSettings on an patched machine (Windows patches):

As you can see, mitigation for the Meltdown vulnerability (CVE-2017-5754) is present in the OS and activated, and (partial) mitigation of the Spectre vulnerability (CVE-2017-5715) is present in the OS but not activated. It can only be activated when a required firmware updated has been installed. You will need to get this firmware update from your OEM (provided they plan to release a firmware update for your machines).

Update 09/01/2018:

Microsoft did not release microcode updates (to update your CPU) with their monthly patches. You will have to do this with a firmware update from your OEM (several OEMs have already released new firmware). Red Hat did release a microcode update for CVE-2017-5715.

More information?
NVISO analysts are still working on additional research and will update this blogpost with any results.

Should you require additional support, please don’t hesitate to contact our 24/7 hotline on +32 (0)2 588 43 80 or csirt@nviso.be.

If you are interested in receiving our advisories via our mailing list, you can subscribe by sending us an e-mail at csirt@nviso.be.

Other references:


Intercepting HTTPS Traffic from Apps on Android 7+ using Magisk & Burp

Intercepting HTTPS traffic is a necessity with any mobile security assessment. By adding a custom CA to Android, this can easily be done. As of Android Nougat, however, apps don’t trust client certificates anymore unless the app explicitly enables this. In this blogpost, we present a new Magisk module, that circumvents this requirement, by automatically adding client certificates to the system-wide trust store, which is by default trusted by all apps.

Basic HTTPS interception

Intercepting HTTPS on Android is a very straight-forward job, which only takes a few steps:

  1. Set Burp as your proxy
  2. Visit http://burp
  3. Install the Burp certificate as a user certificate
  4. Intercept

After following these steps, you can view all HTTPS traffic that is sent through the user’s browser. A more detailed explanation can be found on Portswigger’s website.

In the past, this approach would even work for app traffic as the application would trust all installed user certificate by default. One way to prevent app traffic from being intercepted, is by installing certificate pinning. Certificate pinning means that on each SSL connection the certificates presented by the server will be compared to a locally stored version. The connection will only succeed if the server can provide the correct identity. This is a great security feature, but can be tricky to implement.

Enter Android Nougat

Starting with Android Nougat, apps no longer trust user certificates by default. A developer can still choose to accept user certificates by configuring the networkSecurityConfig attribute in the app’s AndroidManifest.xml file, but by default, they are no longer trusted.

A first approach would be to decompile, modify and recompile the application, which are quite some steps to perform. If the app turns out to have protection against repackaging files, this would also be very difficult. An example of this technique can be found on warroom.securestate.com.

A different approach is adding the user certificate to the system store. The system store is located at /system/etc/security/cacerts and contains a file for each installed root certificate.

Screen Shot 2017-12-15 at 16.07.58A very simple solution would be copying the user installed file (found at /data/misc/user/0/cacerts-added) to this folder. This is only possible, however, if the system is mounted as r/w. Now, while it is possible to remount /system and perform the necessary actions, this is a rather dirty solution and some root-detection algorithms will detect this modification.

Using Magisk

Magisk is a “Universal Systemless Interface, to create an altered mask of the system without changing the system itself.” The fact that Magisk doesn’t modify the /system partition makes it a very nice solution for security assessments where the application has enhanced root detection. By activating “Magisk Hide” for the targeted application, Magisk becomes completely invisible.

Magisk also supports custom modules that are fairly easy to create. In order to have any user certificate recognized as system certificates, we made a simple Magisk module which can be found on our github. The logic of the module is very basic:

  1. Find installed user certificates
  2. Add them to the /system/etc/security/cacerts directory

When installed, the content of the Magisk module is mounted on /magisk/trustusercerts/. This folder contains multiple files, but the most important one is the system directory. This directory is automatically merged with the real /system directory, without actually touching the /system partition. As a result, all certificates in /magisk/trusteusercerts/etc/security/ will end up in /system/etc/security.

Using the module is easy:

  1. Install the module
  2. Install certificates through the normal flow
  3. Restart your device

After installation, the certificates will show up in your system wide trust store and will be trusted by applications:



Of course, if the application has implemented SSL Pinning, you still won’t be able to intercept HTTPS traffic, but this little module makes Android Nougat apps perform the same way as pre-Android Nougat apps.

If you have any suggestions on how to improve this module, or any ideas on how to add the ability to disable SSL Pinning on the Magisk level, let us know!

Download Magisk Module from Github

About the author

Jeroen Beckers is a mobile security expert working in the NVISO Cyber Resilience team. He also loves to program, both on high and low level stuff, and deep diving into the Android internals doesn’t scare him. You can find Jeroen on LinkedIn.

Hack Our Train

This year, in an effort to raise awareness about IoT security, we launched the Hack Our Train challenge. For over three weeks, a model train tirelessly chugged on its tracks inside our IoT village at Co.Station Brussels and then once more for two days at BruCON 2017. We provided it with an emergency brake system powered by IoT technologies and challenged people to hack it and stop the train! With every successful hack, the train stopped, creating a service disruption. A live-stream allowed hackers to monitor the effects of their attacks.

The Hack Our Train challenge was actually composed of two parts: a local one, situated close to the IoT village and then its online counterpart. The local challenge did not require any specific technical skills. It invited people to try and break the pin of the controller that activates the emergency brake mechanism. Check out this video of people having fun with the controller:

But, the online part is where things became really interesting! Over the course of the challenge, only a handful of people succeeded in figuring it out and remotely stopped the train… In this post, we’ll provide a walk-through of the challenge and focus on some of the vulnerabilities featured in it and, more importantly, on ways to fix them.

Hunt for the firmware

On the challenge website, we provided aspiring hackers with the following scenario: Bob, one of the IoT village’s railroad technicians, recently had to update the emergency brake panels. Unfortunately Bob left his USB flash drive laying around and Eve found it and made its content available online!

The first step is to analyze the USB’s contents. It is a zip archive containing two files: firmware.enc, which conveniently hints to the encrypted firmware and a binary file called firmware_updater. The firmware updater is used to decrypt the firmware and then upload it to the control panel via a serial connection.

If we execute it on a Linux machine, the firmware_updater asks us for a pin before decrypting the firmware. People who braved the challenge came up with all sorts of clever ways of cracking the firmware_updater binary and forcing it to decrypt the firmware.

For now, we will resist the temptation of breaking out our dissassemblers and debuggers and we will just look at the strings inside the updater. There are some really interesting parts:



If we think this out (of course, dissassembling would make this much easier), the firmware seems to be encrypted using AES. To perform the decryption ourselves, we would need the key and the initialization vector (IV). Luckily, these are hard-coded into the firmware (see image above).

So, we just need to turn those into their hexadecimal counterparts and we are set:

> openssl enc -aes-128-cbc -d -in firmware.enc -out firmware -iv 766563353667647639396e6e73647161 -K 686f746b3138313965663132676a7671

Vulnerability: use of hardcoded cryptographic keys.

Fix: if possible, avoid using schemes that require hardcoded keys. If using a hardcoded key is unavoidable, there are techniques that can be employed to make the key harder to recover. Ideally, decryption should be performed directly on the embedded device, which avoids the need to expose the key in the firmware updater.

One last word on the update procedure we just cracked: now that we have the keys, no one can stop us from modifying the decrypted firmware to add or remove some functionalities, encrypting it again and uploading it to the device. The emergency controller would have no means of knowing if the firmware has been tampered with.

Vulnerability: firmware not digitally signed.

Fix: Digitally sign the firmware so that the embedded device can verify its authenticity.

Inside the firmware

Phew, we have the firmware, now comes the hard part: we have to reverse engineer it and find a way of remotely trigger the emergency brake mechanism.

Using the file command on the firmware reveals it is in fact a Java archive. This is really good news: using a Java decompiler, we can easily recover the source code.

Vulnerability: code is easy to reverse engineer. Attackers have easy access to the internal workings of the application, which makes it easier for them to find exploits.

Fix: use a code obfuscation tool – there are many available online, both free and commercial. Once you have used the tool on your code, test your application to make sure that it is still functioning correctly. Remember that obfuscation is not a silver bullet but it can drastically increase the effort required for an attacker to break the system.

Before looking at the code, let’s try running the firmware. We are greeted with a status page containing a button to initiate an emergency brake, but we need a pin.


A quick look inside the source code reveals that it is simply “1234”. We have managed to unlock the button. Spoiler: it doesn’t work!

Vulnerability: use of hardcoded passwords.
In our scenario, the password was of no immediate use. Still, this would be harmful if we ever had access to a real emergency brake controller.

Fix: if the password must be stored inside the application, it should at least be stored using a strong one-way hash function. Before hashing, the password should be combined with a unique, cryptographically strong salt value.

In order to understand what is going on, we can simply look at the debug messages conveniently left behind in the console. Seems like the protocol used is MQTT and for some reason, we receive an authentication failure error when we try to perform an emergency brake.

Vulnerability: leftover debug messages containing useful information.

Fix: scan your code for forgotten prints (system.outs in our case) and remove them before release, or disable them at runtime.

Look below the hood

Before going further, let’s take a step back and have a closer look at the architecture of our system. This step was of course not needed to solve the challenge but we thought it complements nicely to this walk-through!

As we just discovered by looking at the source code, communication is based on the MQTT protocol, often found among IoT applications. MQTT works on top of TCP/IP and defines two kinds of entities: Subscribers and Publishers. Publishers send messages on communication channels called Topics. Subscribers can register and read messages on specific Topics. These messages are relayed with the help of a server (also called a Broker).


This is a look below the hood of the mountain (this was our beta setup, our final circuit was much cleaner!). Two elements steal the show: an Arduino and a Raspberry Pi. The Arduino is the muscle: it controls the transistor that stops the train. The Pi is the brains: when it receives an emergency brake message, it orders the Arduino to stop the train.

Both the emergency brake controller (where the firmware runs – it is not shown in the picture) and the Raspberry Pi (shown in the picture) are connected to the internet. They communicate with the MQTT Broker to exchange MQTT messages. The Pi publishes messages concerning the train’s speed but it is also subscribed to a topic waiting for emergency brake messages. The controller displays the train’s current speed and, when the emergency brake is activated, it publishes an emergency brake message that the Broker relays to the Pi.

Of course, not anyone can send an emergency brake message to the server. In our infrastructure, authentication is based on JWT tokens. These are issued by the server relaying the MQTT messages and they are signed using the server’s private key. When  clients try to authenticate using one of those tokens, the server can verify their authenticity using its public key.

To clear all this up, we have created an overview of the MQTT communications going on in the images below:



Tokens, tokens everywhere…

Back the authentication problem. Digging into the source code confirms that authentication is JWT token based. Maybe there is something wrong with the token? Another file inside the JAR that immediately draws our attention is notes.txt. A quick look reveals some notes of a developer that was worried about his JWT token expiring. We can easily verify the creation date of the token here. Seems like out token is really old and as we don’t have the authentication server’s private key, we cannot create a new one.

Vulnerability: old and unused left behind files containing sensitive information.

Fix: before publishing your product, make sure to remove every non-essential ressource.

Knowing how the authentication works, it is time to turn to our favorite search engine for more intelligence. Let’s try jwt token vulnerability. The top result states “Critical vulnerabilities in JSON Web Token libraries“: perfect!

The author does a great job of explaining the vulnerability and how it can be exploited, so we leave you in his hands. For the purposes of this post, the idea is that if we create a forged token using the authentication server’s public key as a HMAC secret key, we can fool the server into verifying it using HMAC instead of RSA, which results in the server accepting our token.


Having identified the vulnerability, it is time to perform our attack. For that, we need the server’s public certificate, which is kindly included in the JAR as well. As mentioned in the notes file, it has been converted to a format compatible with Java but the server is more likely using it in PEM format.

Luckily, converting it back is easy:

> keytool -importkeystore -srckeystore hot.ks -destkeystore temp.p12 -srcstoretype jks -deststoretype pkcs12
> openssl pkcs12 -in temp.p12 -out public.pem


Next, we have to create our malicious token. You can do this in the language of your choice. We used the jwt-simple node.js module.

With the malicious token crafted, we can finally perform the attack. The easiest way is to reuse the code included in the testMQTT.java file, conveniently forgotten inside the JAR. We just have to replace the token found in the code, compile the code and execute it from the terminal.

The select few who made it this far in the challenge saw the train stop on the live-stream and received the flag!

Vulnerability: using components with known vulnerabilities.

Fix: apply upgrades to components as they become available. For critical components (for example, those used for authentication), monitor security news outlets (databases, mailing lists etc.) and act upon new information to keep your project up to date.

Lessons learned

Our challenge involved a toy train but the IoT vulnerabilities demonstrated inside are the real deal. We added each one of them to the IoT challenge because we have come across them in the real world.

On a final note, we would like to congratulate those who were able to hack our train and we sincerely hope that all of you enjoyed this challenge!

Stalking a reporter – behind the scenes!

Around mid-October we got a call from a reporter working on an article covering online privacy and social media. Rather than writing about others, the reporter wanted to have his own story. So, he asked NVISO to research him on-line, and find out as much as possible about him! Of-course, after agreeing on some “ground rules” with the journalist, we were 100% up for it!

The ground rules that were put in place:

  • We would focus on mining only publicly available information, not make him a target of an attack.
  • We were not allowed to use social engineering tricks on him or his friends and family to get additional information.
  • In other words: we could use any information already available online, without actively asking for more.

The article that was recently published by the journalist can be found online (Dutch only, sorry!): http://www.nieuwsblad.be/cnt/dmf20171107_03174488. For anyone interested in the “behind the scenes” on how we approached this – keep on reading!

Let’s hunt!

The team that stalks together…

We assembled a small group of volunteers and got to the task. We created a repository to collectively track our findings, as all bits of information would help the other researchers to move further on their own search, or validate information pieces gathered from different sources. The starting point was obvious: We had the journalists’ name, the email address he used to propose the experiment and a phone number on his signature. Plenty of information to start from!

The first step was to find his Facebook profile. We quickly found out that the reporter does not use the combination name + last name as the profile name, making it more difficult to track down the profile (assuming that he actually has a Facebook profile 😊). But as it often happens, some friends had mentioned his full name on publicly tagged Facebook pictures. We knew his face now! After that, identifying his own profile was possible by looking at metadata in the pictures, including the tagged friends. From there on we started building our file. The privacy settings for the profile were (unfortunately for us) quite restrictive… luckily for us that was not the case for all his friends!

Screen Shot 2017-11-14 at 14.57.36

Facebook showing profile picture after you’ve entered a wrong password

We found his personal email account by guessing and trying to login with the email account to Facebook. Facebook shows you your profile picture when you say that you forgot your password. That is how we could link his personal email with Facebook. We correctly guessed that he also used this email for other social media and apps, and used the same method to see of he had an account. From there onwards, figuring which other services he was using was easy. From there we could gather additional interests, routines, professional activities, social relations…

Of course, this kind of research leads to many false positives. In our case, someone with the same name happens to live close by to our reporter, and some of our data actually referred to that person. That is where crossing data from different sources comes in handy. It allows to discard some of the bits that don’t really match the puzzle.

During our investigations, we also discovered details on the ex-girlfriend of the journalist – her online activity proved to be an excellent source of information! Prolific Instagrammer, her account gave us a lot of info about travels they did together, pictures, friends… Why do we know she was his ex? They are not friends on Facebook anymore! We got no juicy stuff about the breakup, though.

With the parents name (which we found in a cached document on Google), we could find their house, pets, and social media accounts with additional clues… We could assemble a fairly decent family tree. We were also able to find his home address.

With these results we got back to our reporter. He was quite surprised by the things we found out without directly approaching him or his friends! He found particularly scary what we found out about his family and his ex-girlfriend.  He was surprised, though, not seeing his birthdate on our data list.

One step further … go phishing
After our initial investigations, we mutually agreed to take it one step further. 

So what did we do ? We created a fake Facebook profile to trick him or his friends into sharing additional information, contacting his parent or just some good, old phishing to get his credentials and access his email account. We opted for the last option.

We crafted an email based on his interests (which we already identified during the first part of the research). We sent him a link that sounded very relevant for him, so he would definitely try to check it it. And it worked, even though he knew he was going to be targeted by us in this time window. He clicked, and he was directed to a google authentication page. Google? Well, actually NVISO-owned, Google-looking. That is how we got his password.

Once we gain access to his account, we stopped the game. We called him and showed him we were in by sending a mail via his own private inbox to his work email. The challenge was completed. We left nicely, whiteout reading his emails.


Emailing from within the inbox of the reporter to the reporter (yes, this is a dummy screenshot!)

In a meeting afterwards, we explained him how he was phished. Up till then he had no clue how he had given us his credential! But we have to confess: still, we didn’t get his birthdate.

Most people aren’t too surprised anymore about the wealth of information available on each of us online. What is interesting, though, is how often we believe we are fine, just because we have our privacy settings nicely set and reviewed for all our accounts (as was the case with the journalists’ Facebook profile for example). That old account you forgot you had, the friends that tagged you, the university bulletin, a legal document or a nice note in memoriam of a loved one can give most valuable information to anyone who is interested.

Entering the active reconnaissance part, phishing once again proved a very reliable method to get additional details from a target – in our case, it even gave us full access to the journalists’ mailbox.

We are all on-line. Most of our life is these days, and that is not necessarily a bad thing. But it is important to remember that, despite all privacy and security rules we want to enforce, humans are still the weakest link. Understanding how we share information online and the impact it has on us and others is key in an increasingly digitalised world – we are happy to have contributed to the article & hope to have raised some awareness with the readers!