S2 NetBox - Unauthenticated RCE in a Building Management System
2022-06-29 cybersec
“People are putting these things on the public internet?!”
One of those things you never seem to think about when you move offices is the security system. Hell, those little badge readers just configure themselves, right? That’s when I was introduced into the creepy, commonly-forgotten world of building management systems.
These things exist in a gray area, IT doesn’t wanna touch em’. So, they are commonly entrusted in the hands of facilities to manage and apply patches to… great idea!
Setting The Thing Up
The system that I had gotten my hands on was a S2 NetBox. Funny enough, the thing is managed from a web interface.

The NetBox refers to doors as “Portals” (?). From the web interface, you literally do everything. Opening doors, adding/removing users, system maintenance is all handed here.

The system also allows you to give certain users access to admin functionality, depending on what you want them to be able to do. Users can also be assigned a username/password to login to the web interface.
System Architecture
The S2 NetBox has a series of interesting internal design choices that seem to contribute to the impending chaos in this post. The platform has also already been well researched in the past. However, much has changed internally since this post.
The S2 NetBox runs Ubuntu under the hood. In addition to a wide range of bash scripts used, Python (CherryPy), Java (Tomcat and JSP), ASP are used as well. Binaries written in C are also exposed via cgi scripts. Everything is tied together by Apache. PostgreSQL is also now used instead of MySQL.

Extracting The Image
Getting my hands on the source code was easy enough. Being a Linux machine, the most difficult part is dumping the contents of the flash media and extracting the data on the partitions.

The contents of the mini-SATA were easy enough to extract. After dumping the /var partition, I was eager to discover an /var/install directory. Within here, the following files immediately spiked my attention:
s2admin_4.10.01.92170_i386.deb
s2netbox_4.10.01.92294_i386.deb ← the main .deb of focus
s2global_2.10.01.92170_amd64.deb Luckily, .deb files are essentially archive files, a simple ar -xv s2netbox_4.10.01.92294_i386.deb was sufficient to extract all the contents of the main installer deb. This way, instead of digging through the entire filesystem, I have a nice collection of the exact changes S2 Security made to the stock Ubuntu image. Most of the main S2 NetBox code sits within /var/usr/local/s2.
Bash Scripts Via cgi-bin
After glancing through most of main S2 NetBox code to understand what area I wanted to target, I made an easy choice: focus on the cgi bash scripts. Within /var/usr/local/s2/www/cgi-bin are numerous bash scripts (likely mostly used for debugging). For example, debug-sh-env.cgi will simply dump all the environmental variables as html. While this won’t help us achieve RCE, this is certainly a sign of bad things to come. Remember, this is in a production machine!
After tinkering around with these scripts, including disassembling the elf binary used to validate sessions, I moved on to the Python web server to investigate further.
The Python (CherryPy) Server… And Command Injection!
It appears that the CherryPy Web server is responsible for a large part of the functionality of the S2 NetBox. My first instinct was to check all routes that did not require authentication. The folks at S2 NetBox have written their own custom decorator called @expose to expose routes to CherryPy. This decorator Very helpful for checking with routes have authentication! Overall, 53 routes total have authentication disabled. One file instantly spiked my attention, s2daemon.py. This file is used internally to check the status of certain “S2 services” (they for some reason have build their own systemctl derivative). The s2daemon binary on the system is used to manage this.
Unfortunately, this Python script directly passes any URL arguments to the binary. Using a string like ; whoami, we can use command injection and get RCE. Just what we’ve been looking for. As for the spaces and special characters, URL encoding (supported by CherryPy) can be used to include spaces and any funky characters that might violate the HTTP spec.

Even with encoding, CherryPy has issues parsing characters such as / in URLs. To avoid this, we can encode our commands in base64 and pass them into the arguments, allowing us to run commands such as cat /etc/shadow, if needed.
Public Exposure
First things first, DO NOT EXPOSE THESE THINGS ON THE INTERNET! It’s always good practice assume all these “internet of things” devices are going to get a CVE at least once, and likely, you won’t patch it (if you even can). Of course, a quick search on Shodan reveals an unfortunate truth:

Unfortunately, many of these devices seem to be located in particularly sensitive industries as well.
In addition, S2 Security requires you to have a up-to-date license to receive security updates (license lasts ~2 years). The unfortunate nature of this means that, unfortunately, this vulnerability (and any others like it) will likely never be fixed.
Disclosure Notice: This vulnerability was reported to S2 Security through all available channels prior to the publication of this post on June 29, 2022. After approximately two months without meaningful progress or remediation, the decision was made to publish these findings.