
TP-Link Tapo c200 IPカメラのuhttpdバイナリに見つかったコマンドインジェクション脆弱性に対するエクスプロイト
CVE-2021-4045 は、TP-Link Tapo c200 IPカメラにおいてリモートコード実行を可能にするコマンドインジェクションの脆弱性です。デバイスの主要なバイナリの1つである uhttpd におけるユーザー入力のチェック不足により、1.1.16 Build 211209 Rel. 37726N より前のすべてのファームウェアバージョンに影響します。詳細な解説はこちらにあります。
これは、CryptoParty Madrid 2022 で脆弱性を示すために作成された PoC の拡張版です。2つのモードがあります:
shell: ターゲット上でルートシェルを起動します

rtsp: RTSP経由でライブビデオストリームにアクセスできるようにします

関数 exec_and_read_json は popen を使用してコマンドを実行します:

exec_and_read_json は、私が set_language と wifi_connect と名付けた2つの無名関数によって使用されます。これらはそれぞれ言語設定とWiFi設定を処理します(当然ですが)。wifi_connect はシングルクォート(')をパースしているように見えますが、set_language はパースしていません。つまり、set_language 関数への入力を制御できれば、独自のコマンドを正常にインジェクションできるということです。

関数 set_language は、先ほど言及した関数 uh_slp_proto_request によって使用され、ユーザーから受信した解析済みデータを入力として渡します。

uh_slp_proto_request はユーザーデータを解析するために、まずそれが有効な JSON オブジェクトであるかをチェックします。次に、キー "method" で識別される文字列値と、"params" で識別される辞書値を取得します(少なくとも私はそう考えています。関数呼び出しは Ghidra では解決できませんでしたが、このように動作するように見えました)。選択されたメソッドに応じて、uh_slp_proto_request は呼び出される関数を選択します。
つまり、{"method": "setLanguage", "params":{}} を送信することで、set_language 関数を正常に呼び出し、language_json パラメータとして {} を渡すことができます。その後、set_language 内で language_json オブジェクトは文字列に変換され、実行される "ubus call system_state_audio set_language \'%s\'" に直接挿入されます。
{"method": "setLanguage", "params": {"payload": "'; touch poc;'"}} を送信すると、ubus call system_state_audio set_language '{"payload": "'; touch poc;'"}' が実行されます。これは実際には3つのコマンドを含んでいます:ubus call system_state_audio set_language '{"payload": "'、touch poc、そして '"}' です。2つ目のコマンドによって完全なコード実行が可能になります。
次に、uh_slp_proto_request は、すべてのリクエストを管理する別の無名関数によって使用されます。私はこの関数を main_server_function と名付けました。リクエストが有効である場合(最大長を超えていない、サーバー設定に応じて http または https を使用しているなど)、main_server_function は URL に /cgi-bin/luci または /web-static が含まれているかをチェックします。含まれていない場合、uh_slp_proto_request が呼び出されます。

推測とカメラへのいくつかのリクエスト送信により、uh_slp_proto_request が使用するデータが通常の POST データであることを確認できます。したがって、前述のペイロードを / に POST リクエストとして送信すると、uh_slp_proto_request がこのデータを処理し、set_language を呼び出し、exec_and_get_result によって実行されるコマンドにペイロードが注入されます。
ご覧のとおり、私は認証については何も言及していません。setLanguage メソッドはログインなしで呼び出すことができるからです。これにより、任意のユーザーが認証されていない1つのリクエストだけでカメラを完全に制御できるようになります。