Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
shiro — CVE-2026-49268 — LDAPインジェクション認証バイパス脆弱性の分析と修復 | Kitploit
ツール/GitHubGitHub/sassoftware/shiro
静的コード分析 (SAST)脆弱性分析コード分析ウェブセキュリティ認証学習と教育
GitHubsassoftware/shiro

shiro

CVE-2026-49268 — LDAPインジェクション認証バイパス脆弱性の分析と修復

リポジトリを見る
22926日前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

すべてのツールを見る →
共有

CVE-2026-49268 — LDAPインジェクション認証バイパス脆弱性の分析と修復

ブランチ1.13-CVE-2026-49268
作者Jinwoo Hwang (https://JinwooHwang.com)

このブランチ(1.13-CVE-2026-49268)には、Apache Shiro 1.13リリースにおけるLDAPインジェクション認証バイパス脆弱性に対する包括的なセキュリティ修復が含まれています。

NVD公式説明

リモート攻撃者は、DefaultLdapRealmクラスのDistinguished Name(DN)構築にLDAP特殊文字を インジェクションすることができます。ユーザーが指定したユーザー名入力は、RFC 2253特殊文字の エスケープ処理なしに、LDAP DNテンプレートに直接連結されます。これにより、攻撃者はLDAPバインド 認証に使用されるDN構造を操作し、認証をバイパスしたり、他のユーザーになりすましたりする 可能性があります。この問題は、DefaultLdapRealmを使用している場合、Apache Shiroの 2.2.0までのすべてのバージョン、および3.0.0-alpha-1に影響します。


1. 脆弱性の概要

フィールド値
CVECVE-2026-49268 — Apache Shiro: DefaultLdapRealmにおけるLDAP DNインジェクション
CWE IDCWE-90 — LDAPクエリで使用される特殊要素の不適切な中和(「LDAPインジェクション」)
CVSS v4.08.8 HIGH — CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:H/VA:N/SC:N/SI:N/SA:N/S:P/AU:Y/R:A/RE:L/U:Red
CVSS v3.19.1 CRITICAL — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N
影響を受けるバージョンorg.apache.shiro:shiro-core 0から2.2.0まで(両端を含む)、3.0.0-alpha-0から3.0.0-alpha-1まで(両端を含む)
アップストリームでの修正バージョン2.2.1および3.0.0-alpha-2
参照https://lists.apache.org/thread/svszql3od8td7hn6conyj2oq70v53b5s

2. エグゼクティブサマリー

Apache Shiroは、LDAPディレクトリに対してユーザーを認証できます。そのために、送信された ユーザー名をDistinguished Name(そのユーザーエントリのディレクトリアドレス)に変換します。 これは、ユーザー名を設定済みのテンプレート(例えば uid={0},ou=users,dc=mycompany,dc=com)に埋め込むことで行います。

影響を受けるバージョンでは、ユーザー名は生のテキストとしてそのテンプレートに貼り付けられます。 いくつかの句読点文字 — 最も重要なのはカンマ — は、ディレクトリサーバーにとって通常のテキストでは ありません。それらは、アドレスのある部分を次の部分から区切る構文です。したがって、これらの文字を 含むユーザー名は、アドレス内の値として振る舞うことをやめ、アドレス自体の一部として振る舞い始めます。

実際的な結果として、ログインする人物が、単に自分の名前を提供するだけでなく、Shiroがどの ディレクトリエントリに対して認証を試みるかに影響を与えることができます。デプロイメントが意図した コンテナ内で検索される代わりに、検索はディレクトリ内の別の場所にリダイレクトされる可能性があります。 ディレクトリの構成方法や許可内容によっては、これが誤ったIDとしての認証につながったり、本来成功 すべきでない認証が成功したりする可能性があります。

リスクプロファイル。 リスクを高める要因:事前のアクセスや認証情報は不要です — 入力はログイン 境界に到達し、アプリケーションに到達できる誰もがアクセスできます。また、影響を受けるクラスは、 ShiroをLDAPに接続するための標準的で文書化された方法であるため、これは特殊な設定ではありません。 リスクを低減する要因:デプロイメントが実際にDefaultLdapRealm(またはJndiLdapRealm)を 設定済みのDNテンプレートとともに使用している必要があります。他の手段で認証するデプロイメント、 または完全なDNや証明書などの非テキスト認証情報を渡すデプロイメントは影響を受けません。リダイレクト された検索が使用可能な認証をもたらすかどうかは、対象ディレクトリ自体の構成とアクセスルールにも 依存し、これはサイトごとに異なります。

リリース計画のために注目すべき、セキュリティ以外の二次的な結果もあります。正当なユーザー名に バックスラッシュが含まれる、または#で始まるユーザーは、現在まったくログインできません。 なぜなら、それらのユーザー用に構築されたアドレスが整形式の名前ではなく、即座に拒否されるからです。 他の句読点は即座に失敗することはありません — それはアドレスが参照するエントリを暗黙的に変更し、 これが上記のセキュリティ問題です。同じ修正が両方を解決します。


3. 根本原因分析

3.1 欠陥

core/src/main/java/org/apache/shiro/realm/ldap/DefaultLdapRealm.java、getUserDn(String)、 未修正のベースラインでは227〜250行目:```java protected String getUserDn(String principal) throws IllegalArgumentException, IllegalStateException { if (!StringUtils.hasText(principal)) { throw new IllegalArgumentException("User principal cannot be null or empty for User DN construction."); } String prefix = getUserDnPrefix(); String suffix = getUserDnSuffix(); if (prefix == null && suffix == null) { log.debug("userDnTemplate property has not been configured, indicating the submitted " + "AuthenticationToken's principal is the same as the User DN. Returning the method argument " + "as is."); return principal; }

int prefixLength = prefix != null ? prefix.length() : 0;
int suffixLength = suffix != null ? suffix.length() : 0;
StringBuilder sb = new StringBuilder(prefixLength + principal.length() + suffixLength);
if (prefixLength > 0) {
    sb.append(prefix);
}
sb.append(principal);            // <-- inserted verbatim
if (suffixLength > 0) {
    sb.append(suffix);
}
return sb.toString();

}

テンプレートは設定時に一度だけ `{0}` トークンの周囲で分割され(`setUserDnTemplate`、181~200行目)、`prefix` と `suffix` になります。認証時には、プリンシパルがそれらの間に連結されます。**どの時点でもエンコーディングは適用されません。** `org/apache/shiro/realm/ldap/` のどこにもエスケープ用のヘルパーは存在しません。

### 3.2 想定されていたが決して強制されなかった不変条件

周囲のコードは `getUserDn` の結果を整形式の識別名(Distinguished Name)として扱います — それはそのまま `LdapContextFactory.getLdapContext(...)` に渡され、そこから JNDI へバインド DN として渡されます。これが妥当であるのは、置換されるプリンシパルが*単一の属性値*である場合に限られます。

文字列連結ではそれを強制できません。RFC 2253(および RFC 4514)は、`,` `+` `"` `\` `<` `>` `;` `=`、先頭の `#`、および先頭/末尾の空白を DN 内の構造構文として予約しています。これらのいずれかがプリンシパルに現れると、パーサーはそれらを内容ではなく構造として読み取ります。不変条件 — *「プリンシパルは正確に1つの RDN 値を占める」* — は、すべての下流のコンシューマーによって想定されていましたが、誰によっても強制されていませんでした。

### 3.3 実行フロー、エントリポイントから欠陥まで```
  submitted credentials (username, password)
        │
        ▼
  DefaultLdapRealm.doGetAuthenticationInfo(AuthenticationToken)        [line 292]
        │
        ▼
  DefaultLdapRealm.getLdapPrincipal(AuthenticationToken)               [line 338]
        │   principal instanceof String ?
        │       ├── no  ──► return principal unchanged   ── NOT AFFECTED (e.g. X.509)
        │       └── yes ──┐
        ▼                 │
  DefaultLdapRealm.getUserDn(String)                                   [line 227]
        │   prefix == null && suffix == null ?
        │       ├── yes ──► return principal unchanged   ── NOT AFFECTED ("principal IS the DN")
        │       └── no  ──┐
        ▼                 │
  prefix + principal + suffix          ◄── DEFECT: unencoded concatenation  [line 246]
        │
        ▼
  LdapContextFactory.getLdapContext(userDn, credentials)
        │
        ▼
  JNDI bind against the directory using the constructed DN

3.4 実証された影響

テンプレート uid={0},ou=users,dc=mycompany,dc=com、プリンシパル jsmith,ou=admins:

構築された DN解析された RDN
意図されたものuid=jsmith\,ou\=admins,ou=users,dc=mycompany,dc=com4
ベースライン(未修正)uid=jsmith,ou=admins,ou=users,dc=mycompany,dc=com5

名前がコンポーネントを獲得する。ou=users はもはや対象とされているコンテナではない — ou=admins が挿入される。これは javax.naming.ldap.LdapName による解析で検証されており、 これはいかなるエスケープ実装からも独立している。

予約セット全体にわたるベースラインの測定された挙動(JDK 8、LdapName 解析):

プリンシパルベースライン結果影響
jsmith,ou=admins解析成功、5 RDN構造が改変 — コンテナが挿入される
jsmith;ou=admins解析成功、5 RDN構造が改変 — RFC 1779 では ; は RDN 区切り文字
jsmith+uid=admin解析成功、4 RDN多値 RDN になり、uid が2つ目の値を獲得する
jsmith=admin解析成功、4 RDN値が破損
quo"te、angle<br>ackets、 leadingSpace、trailingSpace 解析成功、4 RDN値が破損
back\slashIllegalArgumentException不正形式 — バインドを試行できない
#leadingNumberSignIllegalArgumentException不正形式 — バインドを試行できない

2つの文字が名前の内容だけでなく構造を改変する:カンマ、そしてセミコロン — 後者は RFC 1779 が代替の RDN 区切り文字として受け入れる。+ は同じ RDN に2つ目の属性値を導入する。\ と先頭の # のみが名前を解析不能にする。

3.5 正しい隣接コードとその理由 — 影響範囲

  • userDnTemplate 未設定。 getUserDn はプリンシパルをそのまま返す。これは文書化された「送信されたプリンシパルが そのまま DN である」モードであり、呼び出し側が完全な DN を提供し、その正確性に責任を持つ。影響なし。
  • 非 String プリンシパル。 getLdapPrincipal は String プリンシパルのみを getUserDn にルーティングし、それ以外(X.509 証明書、カスタムトークン)は通過する。影響なし。
  • setUserDnTemplate の検証(181–200行目)は、null、空白、または {0} を含まないテンプレートを正しく拒否する。これは オペレータが提供する テンプレートを検証しており、それは信頼できない入力ではなかった — したがって、この欠陥に対処していないだけの正しいコードである。
  • JndiLdapRealm は DefaultLdapRealm を継承し、getUserDn をオーバーライドしないため、この欠陥を継承する。テスト(§6.1)で確認済み。対象範囲内であり、同じ変更で修正される。

3.6 関連パス — 評価済み、影響なし

AbstractLdapRealm.searchFilter(89行目)は2つ目の {0} 置換を持ち、デフォルトは (&(objectClass=*)(userPrincipalName={0})) で、認可パスで使用される。これは影響を受けない。

ツールをダウンロード