Unfortunate Encounters: Hardcoded RSA Keys

2024-09-16

Recently I spend some nights in a very cool AirBnb, and like (hopefully) many of you I started to scan the network at some point to see if there were any security cameras. Indeed there was a security camera in place, luckily for us this was placed on the outside and by no means one of those sneaky snuff cameras that some AirBnb owners seem to install...

Too curious to not look into the firmware I downloaded a copy of the vendor website and started to analyze it, to the annoyance of my significant other, after which I decided to continue looking at it at some later time.

Fast forward 1 month and I've been in contact with the vendor in question as there was a hardcoded RSA key and an insecure Nginx configuration, allowing anyone (hypothetically speaking) to downgrade the TLS cipher suites in the ClientHello and decrypt the traffic. The vendor simply waved off my report as "this is not enabled anymore" and "customers can change the certificate", to which I'd normally say "haha, you're right, silly me". Except we don't live in a world where customers are actively changing insecure defaults, and at the time of writing this there are at least 4432 devices on the internet using that hardcoded RSA certificate and key for their TLS connections.

Now why would I blog about something this uninteresting? Because it rubs me the wrong way that such a simple thing to fix is waved away by a vendor, especially one that is producing security camera's sold over the world...

"Investigation"

As you've maybe noticed I put the title in between quotes as this can hardly be called an investigation when all I did was running some binwalk over the firmware images and using a quick find and grep for strings and filenames you'd expect for these certificates.

I won't name the vendor in this post, but I've since looked at 3 other firmware images of different vendors of security camera's and almost all of them had hardcoded RSA certificates and keys (1 had a secure webserver configuration that wouldn't allow downgrading, so props to you, I guess...). But what exactly is the problem next to these hardcoded keys?

Problem

Hardcoded RSA certificates and keys are a problem, most people know this, but why do they become a problem? Let's take a look at the following Nginx configuration snippet:

server
{
    listen 443 ssl;
    root /usr/share/nginx/html/;
    index index.html;
    
    ssl_protocols     TLSv1.2;
    ssl_certificate /usr/share/nginx/ipcamera_nginx_self_cert.crt;
    ssl_certificate_key /usr/share/nginx/ipcamera_nginx_self_key.key;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!TLS_RSA_WITH_3DES_EDE_CBC_SHA';
}

In the above configuration excerpt we see a setting (ssl_ciphers) where a set of SSL cipher suites is displayed, most of these are secure, but insecure cipher suites are also explicitly set as an allowed field like AES256-SHA256 for example...

Imagine we're connecting to the security camera (or streaming from the security camera). In a normal scenario this would look (overly simplified) something like this:

Client - Secure CipherSuite -> | Internet | - Secure CipherSuite -> | ISP | - Secure CipherSuite -> | User Home IP Camera

Client <- Secure CipherSuite - | Internet | <- Secure CipherSuite - | ISP | <- Secure CipherSuite - | User Home IP Camera

In this scenario, assuming the client is a normal user that uses a modern OS that is configured to use secure defaults for setting up TLS connections, everything would be fine and encrypted by secure TLS cipher suites. But what happens if we purposefully downgrade the TLS cipher suites that we as a client support?

The simplest way of testing this cipher suite downgrade is by setting up a Nginx server using an insecure configuration and performing a simple curl request using the insecure cipher suite:

curl -k --ciphers AES256-SHA256 --tlsv1.2 -v https://ip.camera

With the RSA key loaded into Wireshark we can now simply decrypt the traffic:

Now let's take the above scenario, except this time one of the endpoints in the ISP is compromised allowing a threat actor to effectively sniff all the network traffic, and if certain addresses are found (the ones identified as being cameras connected to the internet they have a hardcoded certificate key for as an example), downgrade the TLS cipher suites in the ClientHello request. This will make the server connect with the client using an insecure cipher suite which in turn will allow the threat actor to decrypt the TLS traffic.

Client - Secure CipherSuite ->   | Internet | - Secure CipherSuite ->   | ISP | - Insecure CipherSuite -> | User Home IP Camera

Client <- Insecure CipherSuite - | Internet | <- Insecure CipherSuite - | ISP | <- Insecure CipherSuite - | User Home IP Camera

The above can quite easily be done using a little Python script and nfqueue with some iptables settings as a PoC, but isn't that much harder to do with kernel level access and a nifty tool able to intercept the packets at the kernel level. Sure you'd need to account for TCP desyncing and such, but assuming the threat actor is already willing to do the changing of traffic on the fly in the first place makes me think that wouldn't stop them from doing so.

Why (I think) this is a problem

Sure, a threat actor snooping on some cameras attached to the internet is bad for your privacy, but unless you're a high value target to a nation state or crime syndicate with the right people on payroll there shouldn't be too much risk. But this is why I think this is a problem. There are enough of these bad actors willing to go the extra mile for targeted surveillance of individuals, and with more and more camera's (and IoT devices that have camera's) connected to the internet that have insecure defaults this is becoming a bigger problem.

To me it's insane that vendors are even allowed to sell devices that have issues like these that are objectively easy to fix. This is not a bug introduced by the new intern writing his first "hello world" program's bytecode into the bootloader checksum sequence, these are insecure defaults that are easy to identify and mitigate and should thus not be present in devices sold on the market.

Conclusion

If you're working for a company creating devices that are likely to be connected to the internet, please do us all a favor and do not use hardcoded certificate and keys, even when the customer can change these after initial setup. Generate these on first initialization to ensure that one key doesn't hold the keys to half the kingdom that didn't bother to change these.

Even if for some unholy reason this hardcoded certificate can't be changed, make sure that the Nginx configuration does not allow insecure cipher suites, meaning support for Diffie-Helmann or bust.

Last updated