Blog: How Tos
Hacking the Aldi IP CCTV Camera (part 2)
Here’s part 2 to an article I originally wrote in April (speedy heh?) about hacking a cheap and nasty IP camera I’d bought from Aldi.
I’d essentially had a quick look at the device, then went on to delve into the firmware and extract the default credentials. Not much exciting other than highlighting why unencrypted firmware is bad.
After this I sort of laid the device to one side (after getting nmap running on it, which is a story for another time) with only a brief cameo at our stand on InfoSec Europe.
Today I pulled the device out of my big box of IoT thingies to have a second look? Why? Because I read this blog post. Where somebody had found a command injection vulnerability in the FTP setup component of a similar device.
As it looked familiar, it was time to examine my own camera and see whether it had the same vulnerability. During this time I found something quite nasty about the way it works.
Command Injection Vulnerability
This is the flaw found by Z in the blog post I linked to earlier. A command injection is a form of attack whereby the information that has been passed by the user is passed directly to something that can execute a command; whether it is a bash shell, a PowerShell shell, or even a DOS shell.
These normally occur because of code hacks using a batch or shell script, and lack of filtering on the user input.
One of these was found in the FTP parameters script, which allowed certain commands to be passed in the username and password parameters using the bash command evaluation string $( ) (backticks would also be valid: `).
This is an evaluation that bash borrowed form ksh which runs the command in the brackets and returns the result in the context. It is an easy way of running shell commands and getting whatever is returned, e.g.:
We can run commands by setting the FTP user or password to $(command) and then clicking the “Test” button:
When the Test button is pressed, the command will be executed, but cannot return any output. Or can it?
Yes, it is possible, but we have to manufacture a situation where we can see the response. If we assume that the bash command evaluation is being expanded upon log in, if we can log the FTP login sequence we can see the result of the command.
Let’s do this in the easiest way: set up an ftp server on a virtual machine, switch on logging and tail the log as we mess around.
I’m using vsftpd as it is what I had installed, this isn’t ideal as it only normally logs the transfers, but you can switch on a debug mode which logs all FTP commands. This can be configured in the configuration file (/etc/vsftpd/vsftpd.conf on Fedora):
# Note that the default log file location is /var/log/xferlog in this case.
For some reason it didn’t work unless I set xferlog_std_format to NO. A quick restart of the service and all FTP commands are being written into /var/log/vsftpd.log. This will log all FTP commands, but we’re only interesting in the USER command. So we can now mess around changing the input and seeing the result in the log file with a well formed grep. A few commands later and we can see responses.
Command: $(cat etc/passwd)
So, basically we can get the last word of the output back. We could muck around a lot more, but as we’ve got the root entry we can just crack that password, which is “123456”.
Now for something scary
So, I was messing around with the camera and manage to access it from an external IP address. Huh? What! WTF! How on earth did that happen?
So I had a quick hunt around my router and discovered I had, for some reason, left UPnP enabled, and the device had poked a hole in my firewall allowing anybody with my IP address to access the device from the Internet:
Eek! That’s really bad and I’ll show you why in a second, once I’ve disabled UPnP on my router.
Right, you can gather a load of information from this device without credentials. The device itself allows multiple classes of users with a default user called “admin” and no password. You can find this out by visiting the URL /branding/branding.js which display the defaults:
So, if the person hasn’t changed their password, then we’re straight in. If they have we need to perform some bruteforcing on the web interface, which just uses Basic HTTP authentication.
When we took apart the firmware last time, a grep was performed for some “hidden” cgi files. These don’t show up in the web archive, but are built into the web server and can be run to find information:
There are a lot of these and most require authentication, but they are good targets for a CSRF attack (cross site request forgery).
Now, assume we can get access to the admin user, the interface itself won’t show us anything really juicy, unless we use one of these hidden cgi files, specifically get_params.cgi:
Oh look, it’s all in clear text, including the password, the wifi SSID, PSK and any other usernames and passwords provided when set up.
Conclusion, first the obvious stuff for users
- Double, double check that you have UPnP turned off, unless you know what you’re doing with it
- Change the default credentials on everything you buy
- Cheap often correlates with weak security. Be careful what you put on your network
…then for embedded device manufacturers
- Producing an IoT device to hit a low price point doesn’t mean that you can shirk your responsibilities for securing it!
- Don’t store sensitive customer data in plain text or with weak encryption on IoT devices. For example, the WPA PSK should not be easily recoverable.
- Retailers: Don’t just buy a cheap generic IoT device and rebrand it.
- UPnP can be very dangerous. IoT and router manufacturers: don’t poke holes in the users home network without asking their permission first.
- The root problem with UPnP is, IMO in the router manufacturer’s arena: UPnP should not be enabled by default – I would like to see them provide basic VLANing on consumer routers.
The irony of a security camera creating a security vulnerability on the customers network is not lost on us. Manufacturers: get a decent security review of the device done, save yourselves a lot of embarrassment!