IoT/ICS Armageddon: hacking devices like there’s no tomorrow (part 1)

In one of my many previous lives, I worked as principal penetration tester/team leader in the OT area, verifying the full security of more than a dozen of IoT and ICS devices. Switching from IT to OT seemed to be an exciting step, but honestly I got bored pretty soon, and after one year and a half I retired. This is the story of the most ridiculous vulnerabilities I found and although the affected vendors cannot be mentioned due to NDA constraints, I believe the blog post can be still helpful, as it is still full of these crazy flaws out there.

Why boring?

The truth is that hacking OT devices wasn’t challenging enough. Today, like five years ago, the security in the area is running 10/15 years behind the traditional IT sector. In a few words:

  • Almost no data encryption at all…
  • Weak authorization mechanisms…
  • Service misconfigurations everywhere.

I can’t remember a single project in which I was unable to achieve remote code execution, without considering the rest: a whole boat of all kinds of bugs and vulnerabilities. I saw literally no evolution of my skills/career if I were to continue on that professional path.

I must admit it! Meanwhile some people have made their fortunes by selling ICS/IoT vulnerabilities to 0day programs and if I had today to give an advice, I would certainly suggest aspiring and novice bug bounty hunters to focus on this area. However, I continue to prefer targets more difficult to hack. This is a personal choice of course, not a universal truth. Somebody else can very well have fun with OT security.

RCE everywhere

RCE everywhere, I said. One of the many devices I tested, fallen into the so-called category of “data concentrator”. Imagine the place where you live. Probably the electricity you consume is measured by a smart meter installed at your home. The same is for your neighbours. But how does the company sending the bill each month knows how much their customer must pay? Well, your smart meter communicates current consumption and other information to a data concentrator, normally via powerline communication (PLC) or some wireless system. As opposed to smart meters, a data concentrator is located outside of the user domain, usually into a cabin down the street where you live or under a bridge. This device collects the data received and transmits it (via GPRS or more modern units) to a central system in the operator’s data center, where other steps, for example, traffic monitoring or billing, take place.

As data concentrators are a bit more sophisticated than smart meters, these devices come with the necessary hardware to run a complete operating system (quite often Linux). It means some kind of configuration web interface is of course exposed, along with other network services.

One day, me and a colleague were engaged to test one of these devices. We found that an undocumented guest user with default guest password could authenticate to the web admin interface (port 80) with read-only access rights. The presence of this undocumented user (of which there was no trace neither in the official documentation, nor somewhere else) proved to be enough to totally compromise the device itself.

It was a classic old-school RCE. In the ‘change password’ page we just targeted a parameter (password_text) and placed our shell command after a single quote and a semicolon character (see screenshot below).

Specifically we changed the password of the admin user because it was allowed to ssh into the device. While we analyzed more in depth the web interface of this data concentrator, it was noticed that the issue was systemic. To put it simply, every field where the attacker could insert their own input (regardless if GET or POST parameter) seemed injectable. So we decided to dig more in order to establish the root cause for this bug, which brought us to determine that the flaw was tied to an underlying sanitization function that failed to properly filter the user-supplied input

Basically, in whatever place the application took user input, a function (partially-masked snippet below) inside a CGI script, was called first to process that input:

The function tried to delimitate the user input between two single quotes. If the URL-encoded representation of one or more single quote characters was present in the user input, the function tried to escape them. But as you know an attacker can bypass the browser and force the submission of single quote characters that are not URL-encoded. This allowed us to break the input string (along with the possibility to use a semicolon “;”) and inject characters interpreted as operating system commands. But there was another level of craziness in the function itself. The eval() instruction was invoked before the validation of the HTTP parameter’s content occurred, which meant an attacker could remotely execute shell commands by providing whatever name as HTTP parameter 😀

Exploiting command injections like these is not only something seen with IoT devices. Any web application can be vulnerable to this. We’ll teach you how to find (and exploit) these bugs in modern web applications in our BlackHat course.

It was at that point we realized there was not even the need to authenticate as guest user to exploit this vulnerability. Just an EPIC FAIL of the vendor!

An embarassing file disclosure bug

Arbitrary file download is another class of vulnerabilities that web interfaces of data concentrators are commonly affected by. I remember a different device in which the web technology adopted was PHP. It was quite a weird and funny case. There was a function named SanitizeCmdLine() intended to remove evil characters from a user-supplied string before being executed. For example the pipe “|” character and the dot-dot “..” sequence were stripped out of the user input, if present, but a single dot “.” was not.

In simple terms, inserting a pipe char in the middle of two dots (like this “.|.”) would have had the effect to produce, after sanitization, the sequence dot-dot “..”

But the function SanitizeCmdLine() was not recursive! So, there was not a second round of sanitization on the resulting dot-dot sequence. Therefore a string like this:


would have been transformed like this, after being “sanitized”:


For example, the effect of submitting the request below…

…produced a server’s reply that contained the full content of /etc/passwd:

Absolutely one of the most inventive and original ways to sanitize malicious input I have ever seen!

The “unhackable” device

After a series of successes in hacking IoT/ICS devices, my boss came to me and said the next assignment would have been a tough one: the device to test (another data concentrator) was never hacked in the previous security checks the other companies had performed, and the vendor was of course very happy about that. Their products had the fame to be very secure in the market.

The first bug I spotted was a simple arbitrary file delete vulnerability. Nothing exceptional yes, but it immediately gave me the feeling that the fame of this device was undeserved.

Soon I discovered the action=delete string in the screenshot above could be turned to action=download, which gave me a vanilla arbitrary file download primitive.

The web console of the data concentrator implemented a feature that allowed a user to get a copy of log files for analysis and troubleshooting purposes, compressed in a zip archive. The archive itself replicated the same internal structure of the data concentrator’s filesystem, which revealed the exact location where sensible resources were stored, like encryption keys, system logs, confidential database files containing electricity consumes with other user details, etc…

I could grab all these files with my vanilla arbitrary file download bug. Most importantly, inside a system log file, I spotted something like this:


201x-0x-2x_11:16:45.11087 file:/usr/lib/_scape/jars/BorderRouter.jar (id#23)

201x-0x-2x_11:16:45.13019 file:/usr/lib/_scape/jars/CellularModemControl.jar


Now that I knew the location of the JAR files that implemented the web application logic, the consequential step was to get all of them (power of the file download bug found) and perform a quick internal code review. By previously walking over the web panel, I had noticed a function through which to configure a PPP tunnel with a remote destination. I decided to investigate the JAR related to that functionality.

Basically, when a certain web form was filled up, the StartPppd() method of the class PppConnection() was invoked with some arbitrary input taken from the form itself, mainly a username and a password. The StartPppd() method was responsible to build the command string for the system binary pppd, something like this:

pppd /dev/ttyS0 connect “chat -v -s -E -f /etc/ppp/chat-isp” debug logfile /tmp/pppd.log […] user someuser password somepassword

The command string was subsequently executed to prepare and establish the PPP connection. You can see how the issue is evident here. As an attacker we are totally in control of “user” and “password” parameters. We also know quotation marks are allowed in the user-supplied input.

Additionally, there is a little trick. The option “connect” can execute shell commands specified between quotation marks. If that option is repeated twice on “pppd” command line, the shell command the binary executes is the one related to the last instance found of the “connect” option. So, in the specific case, it was enough to submit in the web form:

  • as “user” parameter the string: whatever
  • as “password” parameter the string: s connect “sudo /bin/touch /tmp/hacked.txt”

After the form submission, the following “pppd” command was constructed:

pppd /dev/ttyS0 connect “chat -v -s -E -f /etc/ppp/chat-isp” debug logfile /tmp/pppd.log […] user whatever password s connect “sudo /bin/touch /tmp/hacked.txt”

When the string is finally passed to the shell interpreter, the command sudo /bin/touch /tmp/hacked.txt is executed!

$ ls -al /tmp


-rw-r—–    hacked.txt root    root       0 Jun 17 14:12


Well, it was the first RCE I spotted by doing code review of the collected JAR files. Potentially there were many more bugs of the same class, but the time I was assigned to for the investigation (1 week) was too short to bring up to the surface other issues. In any case, this assessment marked the end of the “unbeatability” of a device considered unhackable, until that moment.


There is nothing more left for today, although we have many other stories related to hacking of IoT/ICS devices that we would like to tell. So probably this will be just one of a series of blog posts about it, and we will see more from Red Timmy in the near future. In the meantime, don’t forget to check out our BlackHat course coming up, we’ve got still some spots left!