Twisted: 認証されていないリモートからのサービス拒否 (DoS) 脆弱性 - Twisted conch Telnet トランスポートにおける、制限のないサブネゴシエーションバッファの利用

## 概要

Twisted conch telnet トランスポートにおける、制限のないメモリ割り当ての脆弱性 (CWE-770) により、認証されていないリモートのクライアントが、単一の接続を通じてサーバーのメモリを使い果たす可能性があります。クライアントが telnet サブネゴシエーションを `IAC SB` で開始し、その後、`IAC SE` のターミネーターを送信することなくデータを送信し続けると、各バイトが、最大長のない、接続ごとのバッファに追加されます。このバッファは読み込み操作の間も保持され、攻撃者が `IAC SE` を送信しない限り解放されません。そのため、プロセスが終了するまで、バッファは無限に増加し続けます。

## 詳細

`Telnet.dataReceived` 内のオプションネゴシエーションの状態機械は、`IAC SB` を受信すると `subnegotiation` 状態に移行し、空のコマンドリストを設定します。この状態では、`IAC` 以外のすべてのバイトが、長さのチェックなしでリストに追加されます。

```python
# src/twisted/conch/telnet.py (Telnet.dataReceived)
elif self.state == "subnegotiation":
if b == IAC:
self.state = "subnegotiation-escaped"
else:
self.commands.append(b) # 制限なし: len(self.commands) のチェックなし
```

`self.commands` は、`dataReceived` の呼び出し間で保持されるインスタンス属性であり、`IAC SE` によってサブネゴシエーションが完了するまで削除されません。ネゴシエーションは認証の前に、トランスポート層で実行され、バイトはアプリケーションのコールバックの前に `dataReceived` 内で消費されるため、アプリケーションは制限を設けることができません。Twisted は、他のパーサーバッファ (例: `NetstringReceiver.MAX_LENGTH`) に対しては制限を設けていますが、このバッファには制限がありません。

影響を受ける製品: Twisted, `twisted.conch.telnet` トランスポート
影響を受けるバージョン: 26.4.0 で確認済み

## PoC

Twistedのtelnetプロトコルを使用するエンドポイント、例えばTwisted manhole telnetサービスにおいて、一つの接続を開き、2バイトのデータ `IAC SB` (`0xFF 0xFA`) を送信します。その後、`0xFF` 以外のバイトを連続的に送信し、`IAC SE` のターミネータ (`0xFF 0xF0`) は絶対に送信しないでください。認証情報は不要です。なぜなら、オプションのネゴシエーションは認証の前に実行されるからです。

各バイトは、接続ごとのサブネゴシエーションバッファに制限なく追加され、このバッファは攻撃者がターミネータを送信しない限り解放されません。そのため、接続の存続期間中、バッファは増加し続けます。各バイトが個別の要素として保持されるため、消費されるメモリは送信されたデータ量よりもはるかに多くなります。そのため、帯域幅の限られたクライアント、またはそのような接続が複数ある場合、プロセスはメモリの枯渇を引き起こします。

## 影響

これは、メモリの枯渇による認証なしのリモートDoS攻撃(CWE-770、CWE-400)です。単一の接続が、送信されたバイト量に比例したコストで、制限なくメモリバッファを増加させ、最終的にオペレーティングシステムがサーバーを停止し、サーバーがホストするすべてのサービスも停止します。機密性や完全性への影響はなく、コードの実行もありません。影響を受けるのは、Twisted telnetまたはmanholeプロトコルを信頼できないクライアントに公開しているシステムです。

影響を受けるパッケージ:
- pip (Python) Twisted: 影響を受けるバージョンは 26.4.0 以前、修正されたバージョンは 26.10.0rc1