- TP-Link Omada システムは、中小企業向けのソフトウェア定義型ネットワークソリューションです。クラウド管理デバイスと、すべての Omada デバイスのローカル管理が訴求ポイントとなっています
- このエコシステムでサポートされるデバイスは多岐にわたりますが、ワイヤレスアクセスポイント、ルータ、スイッチ、VPN デバイス、Omada ソフトウェア用のハードウェアコントローラなどがあります。
- Cisco Talos の研究者は Omada システムに複数の脆弱性を発見し、そのパッチ適用を支援しました。特に重点を置いたのは、EAP 115 および EAP 225 ワイヤレスアクセスポイント、ER7206 ギガビット VPN ルータ、Omada ソフトウェアコントローラですが、これらは利用可能なデバイスのごく一部です。
- 12 件の固有の脆弱性が特定され、シスコの責任ある開示ポリシーに従ってベンダーに報告されました。
Talos ID | CVE |
TALOS-2023-1888 | CVE-2023-49906-CVE-2023-49913 |
TALOS-2023-1864 | CVE-2023-48724 |
TALOS-2023-1862 | CVE-2023-49133-CVE-2023-49134 |
TALOS-2023-1861 | CVE-2023-49074 |
TALOS-2023-1859 | CVE-2023-47618 |
TALOS-2023-1858 | CVE-2023-47617 |
TALOS-2023-1857 | CVE-2023-46683 |
TALOS-2023-1856 | CVE-2023-42664 |
TALOS-2023-1855 | CVE-2023-47167 |
TALOS-2023-1854 | CVE-2023-47209 |
TALOS-2023-1853 | CVE-2023-36498 |
TALOS-2023-1850 | CVE-2023-43482 |
脆弱性の概要
TALOS-2023-1888
TP-Link AC1350 ワイヤレス MU-MIMO ギガビットアクセスポイント(EAP225 V3)v5.1.0(ビルド 20220926)の Web インターフェイス無線スケジューリング機能には、スタックベースのバッファオーバーフローの脆弱性が存在します。細工された一連の HTTP リクエストにより、リモートコード実行につながる可能性があります。
TALOS-2023-1864
TP-Link AC1350 ワイヤレス MU-MIMO ギガビットアクセスポイント(EAP225 V3)v5.1.0(ビルド 20220926)の Web インターフェイス機能には、メモリ破損の脆弱性が存在します。細工された HTTP POST リクエストにより、デバイスの Web インターフェイスのサービス拒否が引き起こされる可能性があります。
TALOS-2023-1862
TP-Link AC1350 ワイヤレス MU-MIMO ギガビットアクセスポイント(EAP225 V3)v5.1.0(ビルド 20220926)および TP-Link N300 ワイヤレスアクセスポイント(EAP115 V4)v5.0.4(ビルド 20220216)の tddpd enable_test_mode 機能には、コマンド実行の脆弱性が存在します。細工された一連のネットワークリクエストにより、任意のコードの実行につながる可能性があります。この脆弱性は、一連の未認証のパケットの送信によりエクスプロイトされる可能性があります。
TALOS-2023-1861
TP-Link AC1350 ワイヤレス MU-MIMO ギガビットアクセスポイント(EAP225 V3)v5.1.0(ビルド 20220926)の TDDP 機能には、サービス拒否の脆弱性が存在します。細工された一連のネットワークリクエストにより、攻撃者がデバイスを工場出荷時の設定にリセットできる可能性があります。この脆弱性は、一連の未認証のパケットの送信によりエクスプロイトされる可能性があります。
TALOS-2023-1859
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)の Web フィルタリング機能には、認証後のコマンド実行の脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドの実行につながる可能性があります。
TALOS-2023-1858
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)の Web グループメンバーを構成する際に、認証後のコマンドインジェクションの脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドインジェクションにつながる可能性があります。
TALOS-2023-1857
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)の WireGuard VPN 機能を設定する際に、認証後のコマンドインジェクションの脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドインジェクションにつながる可能性があります。
TALOS-2023-1856
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)の PPTP グローバル設定を行う際に、認証後のコマンドインジェクションの脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドインジェクションにつながる可能性があります。
TALOS-2023-1855
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)の GRE ポリシー機能には、認証後のコマンドインジェクションの脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドインジェクションにつながる可能性があります。
TALOS-2023-1854
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)の IPSec ポリシー機能には、認証後のコマンドインジェクションの脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドインジェクションにつながる可能性があります。
TALOS-2023-1853
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)の PPTP クライアント機能には、認証後のコマンドインジェクションの脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドインジェクションが実行され、攻撃者が制限のないシェルにアクセスできるようになる可能性があります。
TALOS-2023-1850
TP-Link ER7206 Omada ギガビット VPN ルータ 1.3.0(ビルド 20230322 Rel.70591)のゲストリソース機能には、コマンド実行の脆弱性が存在します。細工された HTTP リクエストにより、任意のコマンドの実行につながる可能性があります。
脆弱性のハイライト
ワイヤレスアクセスポイントの TDDP
TDDP は、多くの TP-Link デバイスで利用できる TP-Link Device Debug Protocol です。このサービスは UDP 1040 で実行され、デバイスのランタイムの最初の 15 分間のみ開かれます。これは実質的に、ユーザーがリモートでデバイスのサービスを受けられるようにするメカニズムであり、サービスを手動で有効または無効にする必要はありません。デバイスが再起動するたびにサービスが 15 分間公開されます。この時間内に、デバイスのさまざまな機能が公開されます。これらの機能についてはこの記事の後半で説明します。ほとんどは、工場出荷時のテストに直接関連した機能のようです。
リクエストの作成
TDDP リクエストメッセージは、サイズが 0x1C のヘッダーと、それに続く選択コマンドでのみ使用されるデータフィールドで構成されています。通常、このヘッダーの構造は以下のようになっています。
バージョン
現在、分析対象のデバイスに実装されていると思われる TDDP サービスのバージョンは 0x01 と 0x02 の 2 つのみです。このうちバージョン 0x02 にだけ、注目すべき機能が含まれています。
00407778 int32_t tddpPktInterfaceFunction(int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4) ... 00407878 if (arg1 != 0 && arg1 != 0) 0040791c memset(0x42f780, 0, 0x14000) 0040797c uint32_t $tddp_version = zx.d(*arg1) 00407994 int32_t len 00407994 if ($tddp_version == 1) 00407b1c len = tddp_versionOneOpt(arg1, 0x42f780) ... 004079a8 if ($tddp_version == 2) 004079bc if (arg4 s< 0x1c) 004079e0 len_1 = printf("[TDDP_ERROR]<error>[%s:%d] inval…", "tddpPktInterfaceFunction", 0x292) 00407a18 else 00407a18 inet_ntop(2, &arg_8, &var_24, 0x10) 00407a38 if (g_some_string_copying_routine(&var_24) == 0) 00407af4 len = tddp_versionTwoOpt(ggg_tppd_req_buf_p: arg1, &data_42f780, arg4) 00407a48 else ... 00407d04 return len_1
対象デバイスでは、バージョン 0x01 でサポートされていたのは tddp_sysInit リクエストだけでした。このリクエストは実行中のデバイスにほとんど影響を与えないと思われます。
0040849c int32_t tddp_versionOneOpt(void* arg1, int32_t arg2) … 004084b8 int32_t var_14 = 0 004084bc int32_t var_18 = 0 004084d8 int32_t var_10 004084d8 if (arg1 == 0 || (arg1 != 0 && arg2 == 0)) 004084fc printf("[TDDP_ERROR]<error>[%s:%d] Invla…", "tddp_versionOneOpt", 0x35f) 0040850c var_10 = 0xffffffff 004084d8 if (arg1 != 0 && arg2 != 0) 00408548 if (arg1 == 0 || (arg1 != 0 && arg2 == 0)) 0040856c printf("[TDDP_ERROR]<error>[%s:%d] pTddp…", "tddp_versionOneOpt", 0x367) 0040857c var_10 = 0xffffffff 00408548 if (arg1 != 0 && arg2 != 0) 0040859c memcpy(arg2, arg1, 0xc) 004085c0 if (zx.d(*(arg1 + 1)) != 0xc) 00408698 printf("[TDDP_ERROR]<error>[%s:%d] Recei…", "tddp_versionOneOpt", 0x3cf) 004086a8 var_10 = 0xffffffff 004085e4 else 004085e4 printf("[TDDP_DEBUG]<debug>[%s:%d] Recei…", "tddp_versionOneOpt", 0x370) 00408600 tddp_sysInit(arg1, arg2) 0040863c uint32_t $v1_3 = zx.d(printf("[TDDP_DEBUG]<debug>[%s:%d] Send …", "tddp_versionOneOpt", 0x372)) 00408670 var_10 = ntohl(*(arg2 + 7) | (0xffff0000 & (*(arg2 + 4) << 0x10 | $v1_3))) + 0xc 004086b8 return var_10
一方、バージョン 0x02 では、この記事の後半で説明するさまざまなリクエストがサポートされています。
004086c0 int32_t tddp_versionTwoOpt(int32_t arg1, void* arg2, int32_t arg3) ... 00408868 memset(arg1, 0, 0x14000) 00408888 memcpy(arg1, arg2, 0x1c) 0040889c uint32_t $v0_11 = zx.d(*(arg1 + 1)) 004088b4 if ($v0_11 == 3) 004088f4 printf("[TDDP_DEBUG]<debug>[%s:%d] Speci…", "tddp_versionTwoOpt", 0x407) 00408910 specialCmdOpt(arg2, arg1) 00408938 printf("[TDDP_DEBUG]<debug>[%s:%d] Speci…", "tddp_versionTwoOpt", 0x409) 004088c8 if ($v0_11 == 7) 0040895c puts("TDDP: enc_cmd. \r") 00408978 encCmdOpt(arg2, arg1) 00408994 puts("TDDP: enc_cmd over. \r") ... 004088c8 if ($v0_11 != 3 && $v0_11 != 7) 004089c4 printf("[TDDP_ERROR]<error>[%s:%d] Reciv…", "tddp_versionTwoOpt", 0x413) 004089d4 var_c = 0xffffffff 00408a04 return var_c
これらの type 値のいずれかを選択した場合は、対応する sub_type 値(以下に記載)を指定する必要があります。
ペイロードの長さ
pay_len サブタイプフィールドには、ペイロードを構成するバイト数が格納されます。この値が計算されるのは、必要なパディング(データの埋め込み)がすべて適用された後、かつペイロードが暗号化される前です。
サブタイプ
使用される sub_type は、直前に選択された type の値に依存します。サポートされている各 type に対する sub_type のブレークアウトは、この記事の後半に記載しています。これらのマッピングは対象デバイスに固有であり、デバイスごとに異なる場合があります。
sub_type は、2 つの主要な type リクエスト間で異なる方法で処理されます。SPECIAL_CMD_OPT は、このフィールドの sub_type 値をリクエストします。ENC_CMD_OPT リクエストでは sub_type フィールドが無視され、代わりに、ペイロードのバイトオフセット 0x0A(リクエスト全体のオフセット 0x26)に sub_type 値が指定されることが想定されています。
00408a0c int32_t encCmdOpt(void* arg1, int32_t arg2) ... 00408b54 uint32_t $v0_12 = zx.d(*(arg1 + 0x26)) 00408b6c if ($v0_12 == 0x47) 00408d58 printf("[TDDP_DEBUG]<debug>[%s:%d] get s…", "encCmdOpt", 0x457) 00408d88 uint32_t $v1_11 = zx.d(tddp_getSoftVer(arg1 + 0x1c, arg2)) 00408dc8 *(arg2 + 4) = htonl((*(arg2 + 7) | (0xffff0000 & (*(arg2 + 4) << 0x10 | $v1_11))) + 0xc) 00408dec $v0_2 = printf("[TDDP_DEBUG]<debug>[%s:%d] get s…", "encCmdOpt", 0x45a) 00408bb0 else 00408bb0 if ($v0_12 == 0x48) 00408e1c printf("[TDDP_DEBUG]<debug>[%s:%d] get m…", "encCmdOpt", 0x45e) 00408e4c uint32_t $v1_14 = zx.d(tddp_getModelName(arg1 + 0x1c, arg2)) 00408e8c *(arg2 + 4) = htonl((*(arg2 + 7) | (0xffff0000 & (*(arg2 + 4) << 0x10 | $v1_14))) + 0xc) 00408eb0 $v0_2 = printf("[TDDP_DEBUG]<debug>[%s:%d] get m…", "encCmdOpt", 0x461) 00408bc4 if ($v0_12 == 0x49) 00408bdc puts("TDDP: resetting. \r") 00408c0c uint32_t $v1_5 = zx.d(tddp_resetFactory(arg1 + 0x1c, arg2)) 00408c4c *(arg2 + 4) = htonl((*(arg2 + 7) | (0xffff0000 & (*(arg2 + 4) << 0x10 | $v1_5))) + 0xc) 00408c64 $v0_2 = puts("TDDP: reset over. \r") 00408b94 if ($v0_12 == 0x46) 00408c94 printf("[TDDP_DEBUG]<debug>[%s:%d] get h…", "encCmdOpt", 0x450) 00408cc4 uint32_t $v1_8 = zx.d(tddp_getHardVer(arg1 + 0x1c, arg2)) 00408d04 *(arg2 + 4) = htonl((*(arg2 + 7) | (0xffff0000 & (*(arg2 + 4) << 0x10 | $v1_8))) + 0xc) 00408d28 $v0_2 = printf("[TDDP_DEBUG]<debug>[%s:%d] get h…", "encCmdOpt", 0x453) 00408bc4 if (($v0_12 s< 0x48 && $v0_12 != 0x46) || ($v0_12 s>= 0x48 && $v0_12 != 0x48 && $v0_12 != 0x49)) 00408ed4 $v0_2 = puts("TDDP: Recive unknow enc_cmd, no …") 00408ee8 return $v0_2
ダイジェスト
すべての TDDP リクエストには、パディング後から暗号化されるまでのペイロードを含む、リクエスト全体の MD5 ダイジェストが含まれている必要があります。この値を計算する際、digest フィールドに 0x10 の Null バイトを入力する必要があります。以下にその例を示します。
ペイロード
一部のリクエストを正常に実行するにはペイロードが必要です。ペイロードの内容にかかわらず、まずは 8 バイト境界まで Null バイトでパディングする必要があります。パディング後は、DES でペイロードを暗号化する必要があります。以下にその例を示します。
未対応のフィールド
他にも、明示的に呼び出されていない code、direction、reserved、pkt_id というリクエストフィールドが存在します。これらのフィールドはリクエストを成功させるために必要ですが、今回のテスト中、フィールドの値はずっと一定でした。
脆弱性による影響
デバイスを工場出荷時の状態にリセット(TALOS-2023-1861)
TDDP は、デバイスの起動時に有効になっている間、デバイスを工場出荷時の状態にリセットするために使用できます。単一の ENC_CMD_OPT リクエストを送信し、ペイロードフィールド経由でサブタイプコード 0x49 を渡すことでデバイスがリセットされます。
通常のペイロードフィールドの使用方法とは異なり、このタイプのリクエストは送信前に DES で暗号化されていません。代わりに、サブタイプコードをオフセット 0x0A のペイロードフィールド内に配置し、それ以外のバイトをすべて Null のままにして、サブタイプコードを指定します。
適切にフォーマットされると、ペイロードフィールドの内容は b’\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x49\x00\x00\x00\x00\x00 になります。
このペイロードフィールドを残りの必須フィールドと組み合わせると、次の要素を含むリクエストが生成されます。
version | 0x02 |
type | 0x07 |
code | 0x01 |
direction | 0x00 |
pay_len | 0x10 |
pkt_id | 0x01 |
sub_type | <ignored> |
reserved | 0x00 |
digest | <dynamic> |
payload | 00 00 00 00 00 00 00 00 00 00 49 00 00 00 00 00 |
リクエストが適切に作成され、TDDP サービスがリッスンしている TP-Link EAP115 または EAP225 に送信されると、デバイスの設定が工場出荷時のデフォルトにリセットされ、デバイスが再起動してデフォルト設定が完全に有効になるまで異常動作が起きるようになります。
ルートアクセスを取得(TALOS-2023-1862)
TDDP は、公開されている TDDP コマンドの 1 つである enableTestMode を通じて、特定のデバイスで間接的にルートアクセスを取得するためにも使用できます。このコマンドの正確な目的は不明ですが、このテストモードを有効にすると、デバイスは定義済みのアドレス(192.168.0.100)に TFTP リクエストを送信して、「test_mode_tp.sh」という名前のファイルを検索します。その後、このファイルが実行されます。このシーケンスは、以下のコードスニペットで確認できます。
int32_t api_wlan_enableTestMode() {
struct stat buf;
memset(&buf, 0, 0x98);
int32_t i;
do {
i = execFormatCmd(“arping -I %s -c 1 192.168.0.100”, “br0”) // [1] Check for the existence of a system at 192.168.0.100
} while (i == 1);
execFormatCmd(“tftp -g 192.168.0.100 -r test_mode_tp.sh -l /tmp/test_mode_tp.sh”); // [2] TFTP Get a file named `test_mode_tp.sh` from 192.168.0.100
stat(“/tmp/test_mode_tp.sh”, &buf);
int32_t result = 1;
if (buf.st_size s> 0) { // [3] If the file was successfully fetched…
execFormatCmd(“chmod +x /tmp/test_mode_tp.sh”); // [4] Mark the file as executable
execFormatCmd(“/tmp/test_mode_tp.sh &”); // [5] and finally execute the shell script with root permissions
result = 0;
}
return result;
}
ホストにアドレス 192.168.0.100 を割り当て、そのホスト上で test_mode_tp.sh スクリプトを提供する TFTP サーバーを設定すると、enableTestMode TDDP リクエストが送信された直後に、デバイスにルートユーザーとして任意のコマンドを強制的に実行させることができます。
VPN ルータのコマンドインジェクションの脆弱性
ER7206 ギガビット VPN ルータの cgi-bin 機能は、コンパイルされた LUA スクリプトによって完全にサポートされています。これらのスクリプトには Lua 用の標準コンパイル形式が含まれていないため、リバースエンジニアリングが難しい場合があります。正確な逆コンパイルを実行するには、元のコンパイラのバージョンが必要です。これにより分析は複雑になりますが、コンパイルされたコードを調べることで実装の詳細に関するヒントが得られ、手動テストをさらに進めることができます。同様のソフトウェアに見られる一般的な脆弱性クラスは、サニタイズされていない入力によるコマンドインジェクションです。ユーザーインターフェイスの入力フィールドを徹底的にテストした結果、8 つの異なるコマンドインジェクションの脆弱性が見つかりましたが、そのほとんどは、VPN テクノロジー(PPTP、GRE、Wireguard、IPSec)の設定に関連するユーザーインターフェイスに存在します。こうした脆弱性の存在は、各脆弱性の悪用が成功した場合の副作用をテストすることで確認されました。このグループで特定されたすべての脆弱性は、エクスプロイト前に認証が必要なのでシビラティ(重大度)は低くなりますが、制限のないシェルアクセスを取得するために悪用される可能性があります。これにより攻撃経路が拡大し、デバイス上での永続性をさらに確立しやすくなります。
コマンドインジェクションの脆弱性のエクスプロイトは簡単です。次の例では、JSON データの「name」フィールドがコマンドインジェクションの対象になっています。この POST リクエストのデータの処理中に入力フィルタ処理は行われず、POST 本文に含まれるシェルメタ文字はすべて、認証されたコンテキスト内で任意のコマンドを実行するために使用できます。
POST /cgi-bin/luci/;stok=b53d9dc12fe8aa66f4fdc273e6eaa534/admin/freeStrategy?form=strategy_list HTTP/1.1
Host: 192.168.8.100
User-Agent: python-requests/2.31.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
X-Requested-With: XMLHttpRequest
Cookie: sysauth=8701fa9dc1908978bc804e7d08931706
Content-Length: 470
data={“method”:”add”,”params”:{“index”:0,”old”:”add”,”new”:{“name”:”DDDDL|`/usr/bin/id>/tmp/had`”,”strategy_type”:”five_tuple”,”src_ipset”:”/”,”dst_ipset”:”/”,”mac”:””,”sport”:”-“,”dport”:”-“,”service_type”:”TCP”,”zone”:”LAN1″,”comment”:””,”enable”:”on”},”key”:”add”}}
TDDP タイプ/サブタイプのマッピング
SPECIAL_CMD_OPT (0x03)
コマンド名 | 「sub_type」値 |
SYS_INIT | 0x0C |
GET_MAC_ADDR_1 | 0x37 |
GET_MAC_ADDR_2 | 0x40 |
GET_MAC_ADDR_3 | 0x66 |
SET_MAC_ADDR | 0x06 |
GET_REGION_1 | 0x20 |
GET_REGION_2 | 0x42 |
SET_REGION_1 | 0x1F |
SET_REGION_2 | 0x43 |
GET_UPLINK_PORT_RATE | 0x7A |
GET_DEVICE_ID_1 | 0x35 |
GET_DEVICE_ID_2 | 0x65 |
SET_DEVICE_ID_1 | 0x36 |
SET_DEVICE_ID_2 | 0x64 |
GET_OEM_ID | 0x3B |
GET_PRODUCT_ID | 0x0A |
GET_HARDWARE_ID | 0x39 |
GET_SIGNATURE | 0x05 |
SET_SIGNATURE | 0x0B |
ENABLE_TEST_MODE_1 | 0x4B |
ENABLE_TEST_MODE_2 | 0x4F |
CANCEL_TEST_MODE | 0x07 |
START_WLAN_CAL_APP | 0x12 |
ERASE_WLAN_CAL_DATA_1 | 0x11 |
ERASE_WLAN_CAL_DATA_2 | 0x63 |
DISABLE_PRE_CAC | 0x5A |
DISABLE_DFS | 0x5B |
DISABLE_TXBF | 0x79 |
SET_POE_OUT | 0x50 |
TEST_GPIO | 0x32 |
NO_WLAN_INIT | 0x7D |
SET_BANDWIDTH | 0x4C |
SET_CHANNEL | 0x4D |
ENC_CMD_OPT (0x07)
コマンド名 | 「sub_type」値 |
GET_HARDWARE_VERSION | 0x46 |
GET_SOFTWARE_VERSION | 0x47 |
GET_MODEL_NAME | 0x48 |
PERFORM_FACTORY_RESET | 0x49 |
本稿は 2024 年 06 月 26 日にTalos Group のブログに投稿された「Multiple vulnerabilities in TP-Link Omada system could lead to root access」の抄訳です。