Author Archives: nvisoblog

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:

bash 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 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!

Don’t be lazy with P4ssw0rd$

Three challenges to making passwords user-friendly

Following the interview of Bill Burr, author of NIST’s 2003 paper on Electronic Authentication, in which he announced that he regrets much of what he wrote, we stop and think.

Why was the standard putting users at risk? Paraphrasing History: “Tout pour le peuple; rien par le peuple”. Perfectly correct from a theoretical point of view, the standard failed to acknowledge that users are indeed people, and when asked to follow too complex rules they will find “tricks” to help themselves to remember their current nightmarish password. Of course, said tricks are fairly easy to guess by any decent hacker, let alone an educated computer.

Nothing new here, the user is often and unfairly considered as the problem. But since there is no easy way to fix the user, it is up to us, as security and IT professionals, to design and build our systems to make them more resilient to human mistakes, and maybe some laziness.

Screen Shot 2017-08-28 at 09.36.42

Difficult for you, easy for a computer : passwords haven’t been what they should.


Ah, those funny stories on predictable passwords

The problem with the previous standard wasn’t that it was advising people to make easy to crack passwords, but that too complex rules steered users towards the path of least resistance: very complex and very predictable passwords.

I remember working in a team where, by knowing how long one of your colleagues had been around, you could easily guess their password, applying the simple rule of Company_nn, where nn was the number of the rotation of the password.

So, what now ?
Three challenges to making passwords user friendly

The new NIST 800-63 special publication, and previous publications such as GCHQ’s NSCS guidance, turns the approach upside down: make your password policy user friendly and you’ll get better security. A simple idea: put the burden as much as possible on the verifier, not the user. With one dream: create security that works no matter what the people do. Is it all that easy ? Let’s look at three recurrent challenges we’ve encountered at our clients:

1. Make it hard to guess with blacklist check

What is this about?
Forget complexity and just make sure you don’t use a word from the dictionary, a known first or last name, or a commonly used password (based on public lists of breached passwords). Now, this is easier than done.

Why is it a challenge?
While quality password blacklists can be found online, neither the blacklist validation mechanism nor the integration with frequently updated blacklists is proposed in most systems and applications on the market. Azure AD, for example, has offered this functionality for only a year, and its scope remains limited. And then, most organizations use a local AD. Or something else that doesn’t have such a native password validation check.

So what ?
There are workarounds of course, but they’re not always robust and imply manual maintenance of a blacklist – an effort many organizations are reluctant to commit to. It will be interesting to see how the market catches up on this one. Until then, well, most system admin prefer to keep some complexity requirements on.

2. Make it easy to remember by promoting the use of passphrases

What is this about?
Lengthy passwords, such as passphrases, are much more likely to integrate human randomness: easy to remember, yet almost impossible for an automated system to make sense of when properly done. As usual, xkcd got it right.

Why is it a challenge ?
While passphrases are a simplification on paper, especially if complexity requirements are dropped, they’re also a new paradigm for most end-user. Let’s face it: 24 characters password sound scary and users are clearly reluctant to commit to this. We’ve tested this on a few friends: after some enthusiastic explanation from our part, they agreed to switch.
For the first few days, our names were accompanied with words that weren’t exactly kind. After a week, the cursing had disappeared and they got used to typing long passwords, often several times to get it right. With locked out increasingly replaced by password throttling, frustration was luckily enough not turned into user being locked out.
But only a few passwords were changed: replacing all passwords in use meant inventing tens of completely new password, based on a completely new reasoning.

So what ?
This tells us that Awareness and communication is needed to make mentality evolve. Maybe re-using some of the good Belgian material of our friends at Even like that, you may wish to focus your effort on one specific password – typically, their Windows password.
But this also tells us that users should only have to remember 4 or 5 passwords: the rest should be in a password vault. Here too, it’s about changing users habit. And again, this works fine until you want to connect from another device than the one hosting the vault. Who said Cloud? But that’s another debate.

3. If it’s still a secret, why change it?

What is this about ?
NIST has gone bold on the advice: only change password if you think (or know) it’s compromised. Don’t have them recurrently expire, this is exactly how passwords become predictable. Of course, this only works if other NIST recommendations are implemented, especially increased length and blacklist check.

What’s the challenge ?
It’s like Perfect Information of consumers in economics: in theory, we should all know everything. But look around and you’ll see it may take months or years to find out your users’ passwords were stolen – not to mention they might have been using that password all over the internet.

So what ?
The best friend of “no expiration” is “second factor”, making sure the memorized secret alone won’t let them in. Of course, with cost of these things and their inherent complexity, you’ll probably select risk-based on which layers and Apps you want to implement it – or even better, go for a common authentication portal that supports adaptive authentication.

What does this all tell us, then ?

That the world is moving to user-friendly security, at last. And the best part is: it’s doing it because old security didn’t work. But it also tells us that these things will be complex to implement, because systems are not ready, implementation will prove complex, and users have to unlearn what we’ve spent the last 20 years pushing into their brains.

This is essentially what our colleague Benoit said on TV a few weeks ago, in case you missed it, you can watch it here.



NVISO at Hack Belgium

Last week, a few of us attended the first edition of Hack Belgium. Describing what Hack Belgium is turns out to be a bit difficult: is it a conference? A hackaton? A hands-on workshop? A technology fair? A pitch? In my view, it’s all of those combined – and that made the event so interesting!

2017-05-04 16.55.56.jpg

9AM – Daan, Jeroen, Kris & Kurt looking sharp at Hack Belgium ( … and ready for some ☕️!).

Hack Belgium offers its attendees 14 crucial challenges around topics that keep our world busy: from healthcare to mobility and building intelligent cities. Over the course of 3 days, all attendees put their heads together to come up with a bright solution to these challenges. With the help of more than 300 experts, it’s certainly a great experience and exercise in idea generation! The objective is to pitch your idea on Saturday and to walk out of Hack Belgium with a blueprint to start working on your project.

2017-05-05 12.19.15.jpg

Our CEO Kurt ready to escape reality 🕶.

OK, I have to confess – we did not stay until Saturday for our pitch, however we did have a lot of fun and interesting moments on Thursday and Friday! We worked on a concept for the media to bring news in a more balanced format, we did a workshop on designing connected projects, we attended an expert session on the state of Virtual Reality (VR) and Augmented Reality (AR), and we had fun playing around with IBM Watson and other upcoming technologies.


Kris showing off his drawing skills 🐁.

Pulling off this type of event at this scale takes a lot of preparation (and guts!) – we want to congratulate  the Hack Belgium staff and all the volunteers involved! You truly made this into an interesting & worthwhile event.

We hope to be present for Hack Belgium 2018 and beyond (… and we will stay for the pitch, promise 🐀!).

A few more impressions after the break!


Proud to say we didn’t lose any fingers playing around with these beasts! 🖐


Beep Boop Beep Boop

2017-05-05 15.43.58.jpg

Playing around with creative ways to design connected products during a workshop. My drawing skills are inferior to the one from Kris, so no close-up 😃!

CSCBE Challenge Write-up – Sufbo

The Sufbo challenge was tackled during the Cyber Security Challenge qualifiers and proved to be very difficult to solve. This write-up gives you a possible way of solving it!


All challenges of the Cyber Security Challenge are created by security professionals from many different organisations. The Sufbo challenge in particular was created by Adriaan Dens, one of our distinguished challenge contributors, from Proximus. Adriaan & Proximus have contributed multiple challenges over the years and they tend to be pretty hard to solve ;).

The challenge

And you thought Assembly was hard to read? Try this!

The solution

The challenge consists out of a heavily obfuscated piece of perl code. We can start by cleaning up the code which improves the readability by a small bit:

print"Flag: ";
die if y///c!=32;

while($,=substr$_,8*$-,8) {
    ($@,$*,$#,$x,$y,$z,$!,$.,$,) = (unpack("N*",$/.$,),0,2**31*(sqrt(5)-1),(1<<32)-1);
    map {
    die if$"ne pack"H*",$_[$-];
print "OK\n"


This code might still not mean a lot to the average non-perl-speaking-person. Let’s take a look at the same code, but with some inline comments:

print"Flag: "; # Prints "Flag: " to STDIN
chomp($_=<>); # Reads in the input into the variable $_
$[=0; # Changes the starting index of an array to 0 (It's a useless command actually)
die if y///c!=32; # y///c is a Perl golfing idiom that is similar to length($_), so the length of your input has to be a string of length 32.
chomp(@_=<DATA>); # Store the data below (under __DATA__) in the array @_
$/=join'',map{chr(ord$_^$=)}split//,pack"H*",shift(@_).shift(@_); # Shift the first two elements of @_, "unhexify" the strings, split them per character, XOR with $= (default value is 60), and join the characters back in the variable $/.
while($,=substr$_,8*$-,8) { # While there are 8 characters left in the input do:
($@,$*,$#,$x,$y,$z,$!,$.,$,) = (unpack("N*",$/.$,),0,2**31*(sqrt(5)-1),(1<<32)-1); # Convert the variable $/ (unknown) and $, (our input) to unsigned numbers, assign 0 to $!, assign 2**31*(sqrt(5)-1) to $/ and assign (1<<32)-1 to $,.
map { # Use map to loop 32 times (see below)
$!+=$.; # Add $. to $!
$!&=$,; # Bitwise AND $! with $,
$y+=((((($z<<4)&$,)+$@)&$,)^(($z+$!)&$,)^((($z>>5)+$*)&$,)); # Some bitwise operations added to $y
$y&=$,; # Bitwise AND $y with $,
$z+=((((($y<<4)&$,)+$#)&$,)^(($y+$!)&$,)^((($y>>5)+$x)&$,)); # Some bitwise operations added to $z
$z&=$,; # Bitwise AND $z with $,
$"=pack("N*",$y,$z); # Convert the unsigned numbers back to string representation
$/=$"x2 # Set $/ to two times $"
}0..31; # Use map to loop 32 times
die if$"ne pack"H*",$_[$-]; # Die if $" is not equal to the "unhexified" element ($- contains the index) in @_
$-++; # Increase the variable $-
} #
print "OK\n" # Printed if you have the key
__DATA__ # Starting the DATA block (kinda like a here document)
6c594e50630d4f63 # This part was used for $/ in line 6.
7d515d4655525b1d # This part was used for $/ in line 6.
7872575285c742da # This part was used to compare with the input on line 20
15c670798094a00b # This part was used to compare with the input on line 20
54f08c6b937ed1f2 # This part was used to compare with the input on line 20
6810afed7372cd76 # This part was used to compare with the input on line 20

So now we more or less know what each line does but we still miss context on a higher level (what it is doing). As always in reverse engineering, you try to find some “known parts” which allow you to understand the code a lot faster. These parts are usually strings, metadata, fixed numbers or familiar code blocks.

In our case, we have 2 fixed numbers: 2**31*(sqrt(5)-1) and (1<<32)-1. In this representation they don’t mean much but if we convert them to hex numbers we get 0x9e3779b9 and 0xffffffff respectively.

Let’s see if our old friend Google knows more about this.

Screen Shot 2017-04-04 at 09.55.02

Hmm, interesting! Seems like we’ve got a Perl implementation of Tiny Encryption Algorithm (TEA) on our hands here!

More specifically, the while loop block in the code is the actual TEA implementation, which decrypts the second half of the __DATA__ section using the first half as the key.

Retrieving the key can be done using the following perl one-liner:

perl -E 'say join"",map{chr(ord$_^$=)}split//,pack"H*","6c594e50630d4f637d515d4655525b1d"

Which yields us “Perl_1s_Amazing!” as the key.

So now we have they key and the data to be decrypted. Let’s be lazy and copy the reference code listed on the wikipedia page we found earlier.


void decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */
    uint32_t delta=0x9e3779b9; /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
    for (i=0; i&lt;32; i++) { /* basic cycle start */
        v1 -= ((v0&lt;&lt;4) + k2) ^ (v0 + sum) ^ ((v0&gt;&gt;5) + k3);
        v0 -= ((v1&lt;&lt;4) + k0) ^ (v1 + sum) ^ ((v1&gt;&gt;5) + k1);
        sum -= delta;
    } /* end cycle */
    v[0]=v0; v[1]=v1;
    printf("%x%x", v0, v1);

void main() {
    /* Our cipher chunks, found in the __DATA__ block of the Perl code */
    uint32_t c0[] = { 0x78725752, 0x85c742da };
    uint32_t c1[] = { 0x15c67079, 0x8094a00b };
    uint32_t c2[] = { 0x54f08c6b, 0x937ed1f2 };
    uint32_t c3[] = { 0x6810afed, 0x7372cd76 };

    /* The used keys for encrypting */
    uint32_t k[] = { 0x5065726c, 0x5f31735f, 0x416d617a, 0x696e6721 }; /* Original key: Perl_1s_Amazing! */
    uint32_t k0[] = { 0x78725752, 0x85c742da, 0x78725752, 0x85c742da }; /* c0 . c0 */
    uint32_t k1[] = { 0x15c67079, 0x8094a00b, 0x15c67079, 0x8094a00b }; /* c1 . c1 */
    uint32_t k2[] = { 0x54f08c6b, 0x937ed1f2, 0x54f08c6b, 0x937ed1f2 }; /* c2 . c2 */

    /* Decrypting the chunks */
$ gcc --std=c99 solution.c
$ ./a.out
$ ./a.out | perl -nle 'print pack("H*", $_)'
&gt;&gt;&gt; CSCBE{Perl1sWr1te0nceRe4dn3veRr}

There we go! CSCBE{Perl1sWr1te0nceRe4dn3veRr} was the flag.

Testimonial of Stefaan Truijen

Hi, I’m Stefaan Truijen and in 2014-2015 I did my master thesis at the department of computer science at KULeuven. I assessed the susceptibility of modern web browsers to RAM scrapers in collaboration with NVISO. Security had always been one of my passions, so I was excited to get started.

Writing a thesis is an intensive process. Happily, I was able to rely on both Arne (NVISO) and Raoul (KULeuven) throughout the entire year for advice/brainstorming.

First, I needed to get an overview of prior research on memory scraping. Arne supplied me with a couple of initial research documents and references, and I reviewed any new material I found with Arne and Raoul almost weekly.

After some preliminary tests, I had to determine how I would continue and I wanted to contribute at least a little bit to fighting memory scrapers. I was able to bounce a few ideas off Arne and Raoul. In the end we decided that, since I was unable to find any prior research that had already assessed the size of the problem – i.e. memory scraping web browsers – measuring the degree of susceptibility of each of the three most commonly used web browsers (Chrome, Firefox, IE) was the most interesting angle.

In order to get a sufficient amount of data to form a solid conclusion, I ran thousands of experiments. Of course, running thousands of experiments manually is not very efficient and it affects reproducibility of the results. Therefore I learned how to work with new tools. Most relevant were Selenium’s automated testing framework for web browsers and the Windows API. Whenever I had questions, Arne and Raoul gladly answered them.

Now that the dust has settled, I can say that I have acquired a deeper understanding of low level security, more specifically memory scraping, and the consequences of relatively relaxed memory and API access policies that I did not have before. I am very satisfied with the result of my thesis and NVISO played an important role in realizing it!

Testimonial of Nick Van Haver

Hi, I’m Nick Van Haver and I want to reflect briefly on my master thesis which I have worked out in cooperation with NVISO and the Ghent University. NVISO helped me in many ways while providing me with a lot of freedom to choose the course of my thesis. They showed me a lot of trust and respect, which I truly appreciate.

The topic of my thesis research was “The Detection of Client-side Vulnerabilities in Web Applications through the Browser”. This topic is deeply rooted in the field of web application security, and thus lead me far beyond its basics. At first I had quite some experience with the development of web applications, but far less with relation to their security aspects.

When looking into a new field or topic, it is hard to find the right sources and high quality references. The right resources can turn a week’s worth of work into a single day. NVISO provided me with these resources and handed me tools, enabling me to educate myself in the web application security field and to make the most out of my thesis. Thanks to NVISO, I had contact with some of the big names in the industry such as Google, Minded Security, Portswigger and many others. Furthermore they assisted me with their expertise in security during meetings.

In the end, my research resulted in a fairly high score of 16 out of 20. Because of these grades I graduated magna cum laude as a Civil Engineer in Computer Sciences. At the beginning of my thesis my knowledge on web application security was rather limited. Now I feel accomplished in this field of security and I now know where to find the most correct information when dealing with web application vulnerabilities. I now also feel more confident when contacting external parties.

I can highly recommend working with NVISO. Choosing to work together with them for your master thesis ensures you that the topic will be both challenging and interesting. You will receive the support and resources you need to achieve your goal. It really is a worthwhile experience! Once the results of my thesis are public, they will be shared with the community!

Cyber Security Challenge Belgium 2015 – Solving the NVISO Lottery challenge

This is the fourth and final blog post in the Cyber Security Challenge Belgium 2015 (CSCBE) solutions series. This time, we’re taking a look at one of the more programming oriented challenges: The NVISO Lottery.

The NVISO Lottery

The students were given the following info:

Come and throw away your money at the NViso Lottery!

They also received the IP address for the NVISO Lottery service.

Gathering information

Once again we take out our trusty pocket knife named netcat.
We have to guess the correct number from a set of 1000 possibilities. If we guess the right number, we get $75, but each guess costs us $10. If we want to win the prize, we have to earn $1337. This means we have to guess correctly at least 20 times without making too many mistakes. Let’s try!
We weren’t able to guess the correct number. We do get an ID, which we can use to get feedback from the NVISO casino. The ID looks completely random, but the last character (=) is a typical tell-tale for Base64 encoding. The equals sign is used as extra padding when the amount of bytes to encode is not dividable by 8. Decoding this using the Base64 algorithm gives the following:
The decoded string doesn’t give us the answer to the random number, but the content does appear to be structured and further decoding may be necessary.
As was explained at the beginning of this write up, this challenge is programming oriented. If you’ve worked with the Python language a lot, you may already recognize the decoded string as being a specific python file format.
In Python, you can use the Pickle module to serialize data objects. Serializing (or marshaling) objects is the processes of converting arbitrary data to a byte stream. This byte stream can then safely be transported over a network, or stored in a file.
Serializing is a reversible process. That means we can deserialize (or ‘unpickle’) the data we got from the Base64 decode:
 This is very promising. The unpickled value consists of a nested list with three random numbers.

Random number generators

Lets take a look at how random numbers are usually generated. Algorithms can not generate truly random numbers. An algorithm will always perform the exact same steps given the same input. Many software implementations therefore rely on Pseudo-Random Number Generators (PRNGs). These algorithms do not generate true random numbers, but they do share many properties with true random numbers. For example, a good PRNG will make it extremely difficult to determine the next random number based on the random number that was just received.
An example of a PRNG is a Linear Congruential Generator (LCG). The most simple LCG needs three numbers to calculate a random number sequence. These three numbers are called the seed of the LCG. Given these numbers (a, c, m), the LCG will calculate the sequence as follows:
The next number in the sequence is calculated by multiplying the current number by a, adding the result to c and taking the remainder of division by m.
From a programming point of view, PRNGs are very useful as they can be reverted to a certain state. If the application suddenly crashes based on a specific random input, it would be very hard to debug the application if the same random input can not be generated. For security critical implementations, of course, a PRNG should not be used.
Since we have to guess a random number, it may be a good guess to say that the decoded value is the seed for a PRNG.

Exploiting the vulnerability

Python allows the programmer to set the state of the random number generator. To confirm we’re on the right track, let’s print out the current state of the default random number generator:
Unfortunately, this seed appears to be a lot bigger than the seed we recovered from the lottery service. Python’s random module actually uses the Mersene Twister algorithm, which is not an LCG,
But there is good news, the output of the getstate() command is very similar to our decoded value. Python has a few other random libraries: random.SystemRandom() and random.WichmannHill(). According to the documentation, SystemRandom() doesn’t have a getstate() method. WichmannHill() does:
This is exactly what we were looking for. By using setstate() with our decoded lottery ID, we should be able to predict the number that will be generated:
Great! That was the solution we were looking for. Because we get the ticket ID before we have to enter our guess, we can predict the value that the server will expect and get our prize!
We could do this manually since there’s no timeout for our answer, but we can just as easily create a python script that does this for us:
We got the flag, which is “I’m_going_to_be_a_professional_gambler!


We had many different connections to the server, so a lot of teams tried to solve the challenge. Most teams told us they managed to decipher the Base64 encoding, and some teams also found the Python pickle format. In the end, only four teams were able to completely solve this challenge: HacknamStyle Jr, ISW, Turla Tech Support and Vrije Universiteit Leuven. All of these teams made it to the finals.

Final thoughts

This challenge was partly aimed at testing the student’s programming skills. Although Python is a very popular programming language, some students may have never used it before, making this challenge a little bit harder. Even so, a security researcher will often encounter unknown file formats or protocols, and finding out what the data means or how to use it may be critical to a successful security audit or forensics investigation. Being able to automate custom tasks can often save lots of time or solve problems that would be impossible to do manually. Having some experience with any programming language is an invaluable tool in every security expert’s toolkit!