Cryptography for IoT Hackers - Part 5
Series Index
| Part | Title | Status |
|---|---|---|
| 1 | What TLS Actually Does (And Why Your IoT Device Needs It) | |
| 2 | Certificates From Scratch The Trust Chain Nobody Explains | |
| 3 | Setting Up Your Own CA and Issuing Certs with OpenSSL | |
| 4 | ESP32 + TLS: Your First Secure MQTT Connection | |
| 5 - You are here | What the TLS Handshake Looks Like on the Wire (Wireshark Lab) | |
| 6 | Mutual TLS (mTLS) Explained: When the Server Also Verifies the Client | |
| 7 | MITM Attack on a TLS IoT Device | |
| 8 | Cert Pinning The Fix, and How Attackers Bypass It | |
| 9 | Embedded Crypto Pitfalls: Hardcoded Keys and Weak RNG | |
| 10 | Breaking mTLS: Stolen Certs and Certificate Confusion | |
| 11 | Secure Provisioning How to Get Certs Onto Devices Safely | |
| 12 | Building a Hardened ESP32 TLS Client Checklist and Final Lab | |
| 13 | Secure OTA Updates Why Your Update Channel Is an Attack Surface |
Before You Read This
This is Part 5. You need to have completed Parts 1 through 4 before reading this.
In Part 4 we got the ESP32 talking to a Mosquitto broker over TLS on port 8883. The messages arrived encrypted. We could see them in mosquitto_sub but only because we were the subscriber with the right setup.
In this part we are going to open Wireshark, sit on the wire like an attacker, and see exactly what is visible and what is not. And more importantly we are going to watch the TLS handshake happen live, packet by packet.
I am going to be honest when I first opened Wireshark for this, I had no idea what I was looking at. A wall of packets, random bytes, weird labels. This blog is me documenting exactly what I learned, question by question, confusion by confusion. If you are a beginner, you are in the right place.
What Are We Doing in This Part
We are going to:
- Set up Wireshark on Kali and capture traffic on the right interface
- Watch the TLS handshake happen live between ESP32 and the Mosquitto broker
- Look at the actual encrypted data on the wire and understand why it is unreadable
- Understand what cipher was selected and what each part of that cipher name means
- Understand how the session key is generated without ever being sent on the wire
What You Need
- Everything from Part 4 still working ESP32 publishing to Mosquitto over TLS
- Kali Linux with Wireshark installed
- Same network setup Kali on Bridged Adapter, ESP32 on WiFi, same subnet
Step 1 - Check Your Interface and Verify Wireshark is Installed
Before you open Wireshark, figure out which network interface to capture on.
Run this on Kali:
ifconfig
You are looking for the interface that has your Kali IP the one we set up in Part 4. In my case it was eth0 with IP 192.168.28.67. Yours might be different but it will be eth0 in most VirtualBox setups with Bridged Adapter.
Verify Wireshark is installed:
wireshark --version
You should see something like Wireshark 4.x.x. If you get command not found, install it:
sudo apt install wireshark -y
During installation it will ask if non-root users should be able to capture packets. Select Yes.
Step 2 - Run Wireshark with sudo
This is something that tripped me up. If you just run wireshark as a normal user, you might not see any local network interfaces in the list just a blank screen or only a loopback interface.
Run it with sudo:
sudo wireshark
Now you will see all interfaces including eth0. Select eth0 and you are ready.
Step 3 - Set Your Filter
Before you start capturing, set a filter so you only see the traffic you care about. Wireshark captures everything on the network without a filter you will be drowning in irrelevant packets.
In the filter bar at the top, type:
tcp.port == 8883
This shows only packets on port 8883 which is our TLS MQTT port. Everything else is hidden.
Step 4 - Capture the Full Handshake (Important Read This First)
Here is something I got wrong the first time. I started Wireshark after the ESP32 was already connected. So my capture started from the middle I missed the Client Hello and Server Hello entirely.
The TLS handshake only happens once at the moment of connection. If you start capturing after the ESP32 is already connected, you will only see Application Data packets and wonder where the handshake went.
The correct order:
- Start Wireshark capture first
- Then reset/reboot the ESP32
- Watch the handshake appear from the beginning
After rebooting the ESP32, you should see something like this at the top of your capture:
204 2.799 192.168.28.66 192.168.28.67 TCP SYN
205 2.799 192.168.28.67 192.168.28.66 TCP SYN, ACK
206 2.808 192.168.28.66 192.168.28.67 TCP ACK
207 2.811 192.168.28.66 192.168.28.67 TLSv1.2 Client Hello
208 2.811 192.168.28.67 192.168.28.66 TCP ACK
209 2.812 192.168.28.67 192.168.28.66 TLSv1.2 Server Hello, Certificate, Server Key Exchange, Server Hello Done
210 2.817 192.168.28.66 192.168.28.67 TCP ACK
228 3.314 192.168.28.66 192.168.28.67 TLSv1.2 Client Key Exchange
229 3.315 192.168.28.66 192.168.28.67 TLSv1.2 Change Cipher Spec
231 3.321 192.168.28.66 192.168.28.67 TLSv1.2 Encrypted Handshake Message
232 3.322 192.168.28.67 192.168.28.66 TLSv1.2 New Session Ticket, Change Cipher Spec, Encrypted Handshake Message
233 3.331 192.168.28.66 192.168.28.67 TLSv1.2 Application Data
That is the full TLS handshake right there, live on your screen.
What Each Packet Means - Plain Language
Let me walk through what is actually happening in each of those packets.
Packets 204, 205, 206 - TCP Handshake (SYN, SYN-ACK, ACK)
This is just TCP doing its thing before TLS even starts. The ESP32 and broker are establishing a basic network connection first. Think of it like picking up the phone and waiting for the other side to pick up. No TLS yet just "are you there?
Packet 207 - Client Hello
This is the ESP32 speaking first. It is saying:
“Hello. I am TLS 1.2 capable. Here is a list of all the encryption methods I support. You pick one. Also here is a random number I generated.”
If you click on this packet and expand it in Wireshark, you will see a long list called Cipher Suites. That is the ESP32’s full menu of encryption options it is offering to the broker.
Notice something important at this point, nothing is encrypted yet. The Client Hello is in plaintext. An attacker can see it. But that is fine there is nothing secret in it yet.
Packet 209 - Server Hello + Certificate + Server Key Exchange + Server Hello Done
This is the broker responding with four things packed into one packet:
Server Hello - the broker picked one cipher from the ESP32’s list and is announcing which one. More on this in a minute.
Certificate - this is your server.crt from Part 3 traveling on the wire. The broker is sending its identity card to the ESP32. The ESP32 will check: was this certificate signed by my Root CA? If yes I trust this broker.
Server Key Exchange - this is the broker sending its public part of the ECDHE key exchange. We will explain ECDHE properly below.
Server Hello Done - broker saying “I am done with my part of the hello, your turn.”
Packet 228 - Client Key Exchange
The ESP32 sends its public part of the ECDHE key exchange back to the broker.
At this point both sides have what they need to independently calculate the same session key. Nobody sent the session key. Both sides just did math and arrived at the same answer.
Packet 229 - Change Cipher Spec
ESP32 saying: “From this point on, everything I send will be encrypted.”
Packet 232 - Change Cipher Spec (from broker)
Broker saying the same thing back: “From this point on, everything I send will be encrypted.”
Packet 233 onwards - Application Data
Everything from here is encrypted. This is your actual MQTT messages “Hello from ESP32 TLS” but locked with AES-256. Wireshark can see the packets exist but cannot read what is inside.
What Does the Encrypted Data Look Like
If you click on any Application Data packet and look at the raw bytes at the bottom of Wireshark, you will see something like this:
0000 08 00 27 63 b0 05 88 57 21 b2 95 68 08 00 45 00
0010 00 5e 00 0a 00 00 40 06 c0 ba c0 a8 1c 42 c0 a8
0020 1c 43 f1 67 22 b3 9f 15 25 17 09 c8 8d a1 50 18
0030 14 54 e3 8c 00 00 17 03 03 00 31 00 00 00 00 00
0040 00 00 01 ec 3f 4d 2f a0 77 6b 6c c8 28 b5 61 b7
0050 c4 a6 10 66 7b c0 1f 92 7c 8d f5 ee db 8e 2f fe
0060 48 c5 ee a9 d2 3d 77 52 8c d5 67 73
That is “Hello from ESP32 TLS” completely unreadable. Random gibberish. There is no way to find your message text in there without the session key.
This is what encryption looks like on the wire. This is what you wanted when you set up TLS in Part 4. You proved it is working.
Which Cipher Was Selected
Click on packet 209 (Server Hello) in Wireshark and expand the TLS section. Look for Cipher Suite.
You will see:
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
That long name is actually telling you four things at once. Let me break it down:
TLS _ ECDHE _ RSA _ WITH _ AES_256_GCM _ SHA384
| | | |
| | | |
How the How the The actual How data
session broker encryption integrity
key was proved algorithm is verified
generated identity
- ECDHE - how the session key was generated (math trick, never sent on wire explained below)
- RSA - how the broker proved it is the real broker (using the RSA certificate we created in Part 3)
- AES_256_GCM - the actual encryption. This is what turned your message into that gibberish bytes
- SHA384 - a hashing function that makes sure nobody tampered with the data in transit
Why Can Wireshark See the Packet but Not the Message
This was my question when I first saw the Application Data packets. The packet is clearly there. Wireshark can count the bytes. But the content is unreadable.
The reason is simple. Wireshark is just a packet sniffer it captures whatever travels on the wire. It has no idea what the session key is. The session key was never on the wire.
Think of it like watching a sealed envelope pass by. You can see an envelope exists. You can see it is going from address A to address B. You can even see how thick it is. But you cannot read what is inside without opening it and you do not have the key.
Wireshark can see the envelope. It cannot open it.
The Certificate is Visible - But That is Fine
Something that confused me if you expand packet 209 in Wireshark, you can actually see the certificate in there. Wireshark even shows “Certificates (2076 bytes)”.
Does that mean the certificate is leaking sensitive data?
No. The certificate is supposed to be public. That is the whole point of it. The certificate is the broker’s identity card it is designed to be shown to anyone who connects. The ESP32 reads it, the attacker can read it, Wireshark can read it. None of that is a problem.
What the attacker CANNOT get from the certificate is the private key (server.key). That never leaves the broker. And without the private key, they cannot impersonate the broker even if they have the certificate.
What the attacker also CANNOT get is the session key. That was generated using ECDHE and never traveled on the wire.
So:
- Certificate visible on wire = fine, it is public
- Session key visible on wire = impossible, it was never there
- MQTT message content visible = impossible, locked with AES-256
How the Session Key Was Generated Without Being Sent ECDHE Explained
This was the part that confused me the most. I kept thinking if both sides need the same key to encrypt and decrypt, how did they agree on it without sending it?
The answer is ECDHE. And here is the simplest way I can explain it.
Imagine you and your friend want to agree on a secret colour. But you are in a room full of people and you cannot whisper everyone can hear everything you say.
Here is what you do:
- You both publicly agree on a starting colour say yellow. Everyone in the room knows yellow. That is fine.
- You secretly pick red. You mix yellow + red and show the result orange to the room. Everyone can see orange. But nobody knows your secret red.
- Your friend secretly picks blue. They mix yellow + blue and show the result green to the room. Everyone can see green. But nobody knows their secret blue.
- Now you take their green and mix it with your secret red. You get brown.
- Your friend takes your orange and mixes it with their secret blue. They also get brown.
You both have brown now. That is your session key. And the entire room only ever saw yellow, orange, and green. Nobody can figure out brown from just those three.
That is ECDHE. The “colours” are big numbers and elliptic curve math instead of paint but the idea is exactly the same.
The session key was never sent. Both sides independently calculated the same value. An attacker who recorded every single packet in Wireshark still cannot get the session key from what they captured.
The Big Picture - What an Attacker Sees vs What You See
Let me put it all together. Here is what is visible and what is not:
| What | Visible to attacker on wire? | Why |
|---|---|---|
| That a connection exists | Yes | TCP packets are visible |
| Which IP connected to which IP | Yes | IP headers are plaintext |
| Which port (8883) | Yes | Port numbers are plaintext |
| The broker’s certificate | Yes | Certificates are public by design |
| Which cipher was selected | Yes | Server Hello is plaintext |
| The ECDHE public values | Yes | These are meant to be shared |
| The session key | No | Never sent on wire |
| The MQTT message content | No | Encrypted with AES-256 |
| The MQTT topic name | No | Encrypted with AES-256 |
An attacker on your WiFi can see that your ESP32 at 192.168.28.66 is talking to something at 192.168.28.67 on port 8883 using TLS 1.2 with AES-256-GCM. That is it. They cannot read a single MQTT message.
That is exactly what TLS is supposed to do. And you just proved it is working.
What You Should See - Screenshot Areas
Common Issues
Wireshark shows no interfaces
Run with sudo:
sudo wireshark
Without sudo, Wireshark cannot access the raw network interfaces on Kali.
I only see Application Data, no Client Hello or Server Hello
You started capturing after the ESP32 already connected. Stop the capture, reboot the ESP32 first, then start a fresh capture. The handshake only happens at connection time you have to catch it at the start.
I see too many packets, hard to find the TLS ones
Make sure your filter is set to tcp.port == 8883 before starting the capture. This filters out everything except your MQTT traffic.
My IP addresses are different from yours
That is normal. Use whatever IPs show up in your ifconfig output. The important thing is that one IP is your Kali machine and the other is your ESP32.
Quick Knowledge Check
Three questions. Answer these before moving to Part 6.
1. An attacker captures all your port 8883 traffic in Wireshark. What can they see and what can they not see?
They can see connection metadata who is talking to who, on what port, using what cipher. They cannot see the actual MQTT messages. Those are encrypted with AES-256 using a session key that was never transmitted.
2. The session key was never sent on the wire. So how do both sides have it?
ECDHE. Both sides exchange public values and independently do math to arrive at the same key. The private inputs never leave each side. The session key is calculated, not transmitted.
3. The certificate is visible in Wireshark is that a security problem?
No. The certificate is a public document. It is designed to be shared. The private key is what is sensitive and that never leaves the broker.
What is Coming in Part 6
In Part 6 we are going to set up mTLS mutual TLS. Right now only the broker proves its identity to the ESP32. In mTLS, the broker also checks the ESP32’s identity. The ESP32 needs its own certificate.
This is important in real IoT deployments you do not want just any device connecting to your broker. You want only your specific ESP32 units to be able to connect.





