Comprehensive Guide to Securing Amazon AWS IoT with MQTTS and Troubleshooting

Amazon AWS IoT utilizes MQTTS (MQTT over TLS) to enable direct communication between IoT devices and the cloud platform. For security reasons, it is recommended that each device is equipped with a certificate for authentication, while the device must also install Amazon’s root certificate. This way, when establishing a TLS connection using port 8883, the client SDK both verifies AWS and AWS IoT verifies the device’s certificate. As a result, this poses higher demands against man-in-the-middle attacks. Here’s a record of my recent troubleshooting experience.

Amazon AWS IoT Plan

The overall plan is similar to this: https://wiki.dequis.org/notes/facebook/

Use a Host-Only mode virtual box VM as the victim, employ iptables to enable internet access, and set up mitmproxy on the virtual network card vboxnet0 to sniff.

VBox VM (Install SDK)  ====> VBoxnet0 network interface (Set up mitmproxy) =====> eth0 (Public access to AWS)

Tools used:

Kali Linux

Virtual Box

mitmproxy

Wireshark

dnsmasq

iptables

openssl

“1. Register Amazon AWS IoT”

Registering AWS is quite cumbersome, and a credit card that can pay in USD is required. However, due to concerns about being charged excessively, I randomly filled one found by Baidu. Nevertheless, because a $1 USD charge was unsuccessful, the next step’s verification code could not be passed, so filling out a real credit card is more reliable. (Strangely, after leaving it idle for a day, it inexplicably went through; during which AWS sent an email stating that the account would be banned for false information, but I managed to pass the verification with some persuasion.) Thereafter, you follow AWS’s instructions to download and try the SDK. It is especially worth mentioning that it provides a wizard to directly register devices to generate certificates and the corresponding platform SDK. It is quite convenient. I chose the generated Linux Python SDK for experimentation.

2. Installing VirtualBox on Kali with Amazon AWS IoT Integration

Refer to other tutorials online. Specifically, make sure to apt-get update, apt-get upgrade, apt-get dist-upgrade to update to the latest, and reboot to install on the latest kernel version, otherwise, various issues due to mismatched Linux headers and kernel version may arise.

3. Use Host-Only mode for Virtual Box

https://www.virtualbox.org/manual/ch06.html#network_hostonly

Reference for Host-Only networking: https://unix.stackexchange.com/questions/383791/virtualbox-host-only-with-internet

Note, you must turn off the virtual machine when changing the network mode in Virtual Box! (For those used to VMware on Windows, take note)

Initially planned to use NAT directly, then set up a man-in-the-middle proxy mitmproxy on the host (host machine). However, for some reason, packets could not be captured consistently, and unlike VMware, the virtual network interface could not be seen, hence the use of host-only with iptables.

4. Set up iptables to use mitmproxy man-in-the-middle proxy

https://media.readthedocs.org/pdf/mitmproxy/latest/mitmproxy.pdf

iptables tutorial: http://www.cnblogs.com/haven/archive/2012/09/27/2705859.html

(Commonly use -t to specify a table, -S to show set rules, -F to delete rules for the table)

Enable IPv4 forwarding sysctl -w net.ipv4.ip_forward=1

The rules I set are: (eth0 is for external network connection, vboxnet0 is the virtual interface on the host)

Allow forwarding between the two network interfaces

iptables -A FORWARD -i eth0 -o vboxnet0 -j ACCEPTiptables -A FORWARD -i vboxnet0 -o eth0 -j ACCEPT

Set up man-in-the-middle proxy and NAT:

iptables -t nat -A PREROUTING -i vboxnet0 -p tcp -m tcp –dport 80 -j REDIRECT –to-ports 8080iptables -t nat -A PREROUTING -i vboxnet0 -p tcp -m tcp –dport 443 -j REDIRECT –to-ports 8080iptables -t nat -A PREROUTING -i vboxnet0 -p tcp -m tcp –dport 8883 -j REDIRECT –to-ports 8080        //port 8883 is for mqttsiptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE  //Set NAT to change original address on eth0

Note, here mitmproxy is built on vboxnet0, initially I chose to set it up on eth0, but for some reason, packets could not be captured consistently.

5. Set up SSL certificates

http://docs.mitmproxy.org/en/stable/certinstall.html#the-mitmproxy-certificate-authority

First, let the client SDK trust the mitmproxy certificate, AWS’s provided certificate and mitmproxy’s certificate differ in format, you cannot simply replace the certificate file, conversion is needed, replace it with mitmproxy’s certificate file using the -r parameter when executing the script.

openssl x509 -in mitmproxy-ca-cert.pem -inform PEM -out foo.crt   //Change certificate format

python aws-iot-device-sdk-python/samples/basicPubSub/basicPubSub.py -e axxxxxx9x.iot.us-east-2.amazonaws.com -r foo.crt -c 0000.cert.pem -k 0000.private.key

Client device’s certificate also needs conversion to be provided to mitmproxy, otherwise the server will disconnect.

Reference for format conversion: https://stackoverflow.com/questions/28712088/unable-to-load-certificate-6300error0906d06cpem-routinespem-read-biono-star

Use client certificate: http://docs.mitmproxy.org/en/stable/certinstall.html#using-a-client-side-certificate  (The documentation has a pitfall, it actually cannot simply specify the folder, best to specify the certificate file, official documentation is not updated promptly)

Fix pit: https://github.com/mitmproxy/mitmproxy/pull/494/commits/ff6bfba4a6a1c440018c4873d9edeb64da0f8e7f  (Here it explains how to use a client certificate, if specifying a folder requires the file name and access domain to match)

openssl rsa -in 0000.private.key -out unprotected.0000.private.key

cat unprotected.0000.private.key 0000.cert.pem > mitm_0000.cert.pem

Note particularly, for an unexplained reason the client SDK and mitmproxy detect domain name mismatches (security issue?), special handling is needed. For the SDK, I chose to comment out the problematic line/usr/local/lib/python2.7/dist-packages/AWSIoTPythonSDK/core/protocol/paho/client.py around line 800 the self._tls_match_hostname(); mitmproxy uses the –insecure parameter, which will show a warning but will not disconnect.

192.168.56.2:52369: Certificate Verification Error for 52.15.111.27:8883: hostname ‘no-hostname’ doesn’t match either of u’*.iot.us-east-2.amazonaws.com’, u’iot.us-east-2.amazonaws.com’

192.168.56.2:52369: Ignoring server verification error, continuing with connection.

6. Wireshark decrypt SSL

 http://docs.mitmproxy.org/en/stable/dev/sslkeylogfile.html

Set environment variable to let mitmproxy record the SSL key:

export SSLKEYLOGFILE=~/IoT/keylog      (Affects the browser, best to choose the environment variable below)

export MITMPROXY_SSLKEYLOGFILE=~/IoT/keylog

7. Finally

1) Run proxy:

mitmdump -T –insecure –client-certs ~/IoT/connect_device_package/mitm_0000.cert.pem –host –raw-tcp -w 11111 

-v can display detailed information.

Be sure to set –raw-tcp, otherwise the proxy will fail due to MQTT not being a standard HTTP protocol.

2) Open Wireshark and set the filter condition to ssl && tcp.port==8883

3) Run the SDK script:

python aws-iot-device-sdk-python/samples/basicPubSub/basicPubSub.py -e axxxxxx9x.iot.us-east-2.amazonaws.com -r foo.crt -c 0000.cert.pem -k 0000.private.key

4) Import the key into Wireshark to decrypt the MQTTS message:

Edit—Preferences—Protocols—SSL— (Pre)-Master-Secret log filename, choose the recorded key.