このリポジトリは汎用的なエクスプロイト PoC リポジトリではありません。projectdiscovery/nuclei-templates へのコントリビューションを目的とした CVE-2026-45185 テンプレートの動作を再現・レビューするためのローカル検証ラボです。
The nuclei code template is not a version-only detector.
It directly controls STARTTLS, BDAT, TLS close_notify, and a following
SMTP plaintext byte on the same TCP connection.
This sequence matches in the local vulnerable Exim 4.99.2 GnuTLS lab and does
not match in the patched Exim 4.99.3 GnuTLS lab under the same conditions.
現在の検証シグナルは、リモート SMTP レスポンスオラクルであり、UAF 書き込み自体の直接的な観測ではありません。内部的には、この CVE は use-after-free であり、TLS シャットダウン後に改行バイト(\r/\n)が解放済みの GnuTLS 転送バッファに書き込まれる可能性があります。実際には、クライアントが SMTP レスポンスを通じて解放済みバッファへの書き込みを直接観測することは現実的には不可能です。したがって、この README とテンプレートは bdat_ungetc -> tls_ungetc の UAF 書き込みや RCE を直接証明するものではありません。代わりに、テンプレートはトリガーフロー中に現れる受信スタック/状態回復の差分を検出します。
脆弱性メカニズムのトレース中に、STARTTLS + BDAT 処理中の TLS close_notify 後に、古い tls_* 関数ポインタが BDAT 受信スタックの下位レイヤに残り、smtp_* 関数ポインタへ適切に復元されない場合があることを観察しました。この状態は、サーバーが次の SMTP コマンドを処理する方法に現れます。分割された BDAT が最初の完了に達した後、同じセッションで NOOP を送信すると、脆弱な Exim 4.99.2 GnuTLS ラボは 421 lost input connection を返しますが、パッチ適用済みの Exim 4.99.3 GnuTLS ラボは 250 OK で正常に処理します。この明確な脆弱/パッチ適用済みレスポンスの差分が、ローカルの許可された nuclei code テンプレートのマッチャーとして使用されます。
脆弱性フローのより詳細なウォークスルーについては、CVE-2026-45185-Technical-Analysis.md を参照してください。
共通の SMTP エンベロープ受信者(RCPT TO):
Docker ラボの lab_rcpt ACL はこのエンベロープ受信者を受け入れます。一般的な SMTP ターゲットでは、RCPT TO が拒否された場合、シーケンスが BDAT ボディパーサーに到達しない可能性があるため、テンプレートは受け入れられる受信者を必要とします。
この値は BDAT ボディ内の To: ヘッダーとは異なります。RCPT TO 受信者は、サーバーの受信者チェックを通過する必要がある SMTP エンベロープアドレスです。BDAT ボディ内の To: 値はメッセージヘッダーのテキストに過ぎず、サーバーにメールボックスとして存在するか受け入れられる必要はありません。
templates/CVE-2026-45185.yaml
テンプレート名:
Exim 4.97-4.99.2 GnuTLS STARTTLS BDAT - Same-Session Response Check
テンプレートは metadata.verified: true で記述され、code および intrusive タグを持ちます。
POC_2026_45185/ ディレクトリから以下のコマンドを実行します。
docker compose build
docker compose up -d
テンプレートの構文を検証します:
nuclei -duc -validate -code -t templates/CVE-2026-45185.yaml
実行前にローカルの code テンプレートへ署名します:
nuclei -duc -code -t templates/CVE-2026-45185.yaml -sign
脆弱なラボに対して実行します:
nuclei -code \
-t templates/CVE-2026-45185.yaml \
-u 127.0.0.1:2525 \
-var [email protected] \
-debug
期待される結果:
CVE-2026-45185: vulnerable response oracle matched
パッチ適用済みラボに対して実行します:
nuclei -code \
-t templates/CVE-2026-45185.yaml \
-u 127.0.0.1:2526 \
-var [email protected] \
-debug
期待される結果:
no match
NO-MATCH: patched-like response: NOOP succeeded after split trigger
nuclei の code プロトコルはデフォルトでは実行されないため、-code が必要です。また、nuclei は署名されていない code テンプレートをブロックします。ローカルの nuclei 秘密鍵がパスフレーズで保護されている場合は、対話型ターミナルで署名コマンドを実行し、そのパスフレーズを入力してください。ダイジェストがテンプレートの内容をカバーするため、テンプレートを変更するたびに再署名してください。
これらのスクリーンショットは、テンプレートが署名された後のローカルラボのレスポンスオラクル結果を示しています。これらは上記で説明した同一セッションのレスポンス差分の検証証拠であり、内部の UAF 書き込みの直接的なデバッガーや ASAN による証明ではありません。
127.0.0.1:2525 の脆弱な Exim 4.99.2 GnuTLS ラボ:

127.0.0.1:2526 のパッチ適用済み Exim 4.99.3 GnuTLS ラボ:

この CVE の核心は SMTP バナーやバージョンチェックではありません。テンプレートは、同じ TCP 接続上で以下のトランスポート状態遷移を作り出す必要があります:
plaintext SMTP EHLO
-> STARTTLS
-> TLS handshake on the same TCP connection
-> TLS EHLO / MAIL FROM / RCPT TO / BDAT 70 LAST
-> first 69 bytes of the BDAT body as TLS application data
-> TLS close_notify without closing the TCP socket
-> final body byte as plaintext on the same TCP connection
-> same-session plaintext NOOP response check
YAML テンプレート内の Python コードは、以下のすべての条件が満たされた場合にのみ固定マーカーを出力します。nuclei マッチャーはそのマーカーのみに一致します。
Exim identity is found
AND STARTTLS is advertised in plaintext EHLO
AND CHUNKING is advertised in plaintext EHLO
AND STARTTLS is accepted
AND CHUNKING is advertised in TLS EHLO
AND MAIL FROM is accepted
AND RCPT TO is accepted
AND the split close_notify BDAT reaches first completion
AND first completion contains "250 OK id="
AND the same-session plaintext NOOP response contains "421"
AND the same-session plaintext NOOP response contains "lost input connection"
テンプレートは以下のシグナルのみでは一致しません:
version-only
timeout-only
connection-drop-only
empty-response-only
recipient rejection
STARTTLS/CHUNKING advertisement only
両方のラボは分割された BDAT メッセージを最初の完了まで処理します。
250- 70 byte chunk, total 72
250 OK id=...
差分は、同じ SMTP セッションで次の SMTP 平文コマンドが送信されたときに現れます。
脆弱な 4.99.2:
NOOP -> 421 exim-lab.local lost input connection
QUIT -> 421 exim-lab.local lost input connection
RSET -> 421 exim-lab.local lost input connection
パッチ適用済み 4.99.3:
NOOP -> 250 OK
QUIT -> 221 exim-lab.local closing connection
RSET -> 250 Reset OK
解釈:
Observation:
Both labs reach split BDAT message completion.
Only the vulnerable lab fails to return cleanly to the next plaintext SMTP
command loop in the same session.
Evidence:
The vulnerable follow-up response is 421 lost input connection.
The patched follow-up response is 250 OK or 221 closing connection.
Inference:
This difference is consistent with the receive stack/state recovery difference
after STARTTLS close_notify.
テンプレートは BDAT ボディとして以下の 70 バイトのメッセージを使用します。
From: [email protected]\r\n
To: [email protected]\r\n
Subject: poc\r\n
\r\n
body
SMTP エンベロープ受信者はテンプレート変数 recipient を通じて個別に渡されます。ボディ内の To: ヘッダーはテキストであり、SMTP の RCPT TO が受け入れられるかどうかとは無関係です。そのため、サーバーに存在するか受け入れられる必要はありません。
分割形状:
BDAT 70 LAST
TLS body: first 69 bytes, ending with "bod"
TLS event: close_notify
Plaintext: final byte "y"
Follow-up: NOOP
両方のラボが Exim、STARTTLS、CHUNKING をアドバタイズしていることを手動で確認できます。
printf 'EHLO lab-client.local\r\nQUIT\r\n' | nc -w 3 127.0.0.1 2525
printf 'EHLO lab-client.local\r\nQUIT\r\n' | nc -w 3 127.0.0.1 2526
期待されるシグナル:
Exim
STARTTLS
CHUNKING
通常の STARTTLS パスも確認できます:
openssl s_client -starttls smtp -connect 127.0.0.1:2525 -crlf
openssl s_client -starttls smtp -connect 127.0.0.1:2526 -crlf
debugging/ と notes/source-walkthrough-progress.md の下で個別に追跡されています。POC_2026_45185/
compose.yaml
images/ local nuclei validation screenshots
vulnerable/ Exim 4.99.2 + GnuTLS debug build
patched/ Exim 4.99.3 + GnuTLS debug build
nuclei-templates/ submodule: local nuclei template workspace
| ターゲット | バージョン | TLS バックエンド | STARTTLS | CHUNKING | ポート | 期待される nuclei 結果 |
|---|
| vulnerable | Exim 4.99.2 | GnuTLS | yes | yes | 127.0.0.1:2525 | match |
| patched | Exim 4.99.3 | GnuTLS | yes | yes | 127.0.0.1:2526 | no match |