5月26日、ni5argaが「Exposing Critical Vulnerabilities in CBSE's On-Screen Marking Portal: From Authentication Bypass to Full Account Takeover」と題した記事を公開した。
JavaScriptファイルに採点者用のマスターパスワードが平文で記載され、誰でもダウンロードして数百万人の学生の成績を改ざんできる状態だった。発見されたのは、インド最大の教育委員会CBSEが運営するオンライン採点システムで、認証バイパスから完全なアカウント乗っ取りまで可能な5つの重大な脆弱性だ。
インド版「大学入試センター試験」のシステムがザル仕様
CBSE(Central Board of Secondary Education)は、インド政府管轄下で運営される同国最大の国家教育委員会だ。国内外の2万8000校以上が加盟し、毎年数百万人の学生がClass 10・12の国家試験を受験する。これらの試験結果は大学進学や就職に直結するため、インドの教育システムにおいて極めて重要な位置を占めている。
CBSEは従来の紙ベース採点からデジタル化を進めており、Class 12の試験でオンラインスクリーンマーキング(OSM)システムを導入した。Coempt EduTech Pvt Ltdが開発したこのシステムは、スキャンされた答案用紙を採点者がオンラインポータルで評価する仕組みで、複数の教育委員会で利用されている。
記事の著者であるni5argaは、今年Class 12の試験を終えたばかりのホビーセキュリティ研究者だ。OSMポータルのリンクが完全に公開されていることに気付き、好奇心から調査を開始した結果、驚愕の脆弱性を発見することになった。
最悪の脆弱性:フロントエンドにパスワード平文記載
著者はまず、ポータルのJavaScriptバンドルを分析した。このAngularアプリケーションは以下のURLで誰でもアクセス可能なJSファイルとして配信されている:
https://cbse.onmark.co.in/cbseevalweb/main.dc17c24606b3b008.js
このファイルを解析した結果、5つの重大な脆弱性が発見された。中でも最も深刻なのは、フロントエンドのJavaScriptバンドル内にマスターパスワードが平文で埋め込まれていたことだ。ハッシュ化されておらず、トークン参照でもない、文字通りのパスワード文字列がクライアントサイドのJavaScriptに直接記述されていた。
このマスターパスワードをログインフォームに入力すると、アプリケーションは自動的にOTPフィールドを埋め、通常の認証フローを完全にバイパスした。二要素認証も、サーバーサイドのチェックも存在しない。
攻撃者が特定の採点者としてログインするために必要なのは:
- ユーザーIDと学校コード(どちらも公開情報から入手可能)
- マスターパスワード(誰でもダウンロード可能なJSファイル内に記載)
たったこれだけで、著者は採点者として(OTP/2FAフローを完全にバイパスして)ログインし、評価ダッシュボードで成績の閲覧・編集が可能になった。
その他4つの脆弱性も基本原則を無視
脆弱性2: クライアントサイドでのOTP検証
OTP認証は完全に見せかけだった。認証をトリガーすると、サーバーがOTPを認証レスポンス内で返送し、ブラウザで実行されているJavaScriptがローカルで入力値と比較してからアクセスを許可していた。
攻撃者のマシンで実行されるセキュリティ制御は、制御とは言えない。ネットワークタブを確認すれば誰でもOTPを読み取れるし、クライアントサイドコードで比較が行われるため、フォームをスキップして単純にチェックが通過したとアプリに伝えることも可能だった。
脆弱性3: ルートガードの完全な欠如
Angularアプリケーションのルート設定には認可チェック機能(canActivateガード)が一切設定されていなかった。/dashboard、/profile、/evalscriptsviewなどの内部ページすべてに直接アクセス可能だった。
ブラウザストレージにいくつかの値を設定してルートに直接移動するだけで、任意のページにアクセスできた:
localStorage.setItem('jwtToken', 'dev-token-12345');
sessionStorage.setItem('role_id', '23');
window.location.href = '/cbseevalweb/#/dashboard';
このコードをブラウザコンソールに貼り付けるだけで、何も認証せずにダッシュボードにアクセスできた。
脆弱性4: パスワード変更時の現在パスワード未確認
「パスワード変更」機能は古いパスワードをユーザーから収集するが、実際のAPIリクエストでは現在のパスワードは一切検証されず、ペイロード内のValuatorIDで指定されたユーザーのパスワードが任意の値にリセットされる仕様だった。
脆弱性5: システム全体のIDOR脆弱性
アプリのほぼすべてのAPI呼び出しが、sessionStorage["eval"]から直接ValuatorID/user_idを読み取って動作ユーザーを特定していた。サーバーは認証されたセッションから派生させる代わりに、クライアントが送信するIDを信頼していた。
これはアーキテクチャレベルでの不適切な直接オブジェクト参照脆弱性だ。ブラウザのストレージ内のIDを変更するだけで、アプリは任意のユーザーとして動作する。
攻撃の全体像:成績改ざんが数クリックで可能
これらの脆弱性により以下が可能になった:
- フロントエンドに漏洩したマスターパスワードを使用した任意の採点者としてのログイン
- ブラウザで検証が行われるため、OTPの完全なバイパス
- 一切の認証なしでの内部ページへのアクセス
- 現在のパスワードを知ることなく任意の採点者のパスワードリセット
- システム的な脆弱性により任意のユーザーとしての行動、成績の編集、採点者詳細の変更、評価プロセスの改ざん
高度な攻撃技術は不要で、最も困難な部分はJavaScriptファイルを読んでDevToolsで数値を編集することだけだった。
責任ある開示と当局の対応
著者は公開前に**CERT-In(インドコンピュータ緊急対応チーム)**にすべての脆弱性を報告した。最初のメールでマスターパスワード漏洩とクライアントサイドOTP検証について報告し、CERT-Inから詳細と画面録画の要求があった。
著者は完全なウォークスルーと追加で発見した脆弱性も送信したが、定型的な確認メール以降、複数回のフォローアップにも返答がなかった。著者は以下のようにコメントしている:
報告した脆弱性のほとんどが長期間パッチされなかったのは正直面白い。これらが私の担当なら1〜2時間で修正していただろう。当局の無能さには呆れる。
セキュリティの基本原則を無視した設計
この事例から得られる教訓は、クライアントは絶対に信頼してはならないということだ。すべての脆弱性は同じ根本的な間違いに起因している:ユーザーのマシンで実行されるコードに機密情報とセキュリティ決定を置くことだ。
- 機密情報(パスワード、OTP、機密データ)はサーバーに保管し、JavaScriptバンドルに含めない
- 認証と認可はすべてのリクエストでサーバーサイドで強制する
- ユーザーの身元は認証されたセッションから取得し、DevToolsで編集可能な値からではない
- パスワード変更などの機密操作では、リクエスト者の権限と現在のパスワードを検証する
これらは高度な防御策ではなく**OWASP Top 10に記載されているWebアプリケーションセキュリティの基本事項だ。国家試験の完全性を託されたプラットフォームには、最低限この基本を期待すべき**である。
詳細はExposing Critical Vulnerabilities in CBSE's On-Screen Marking Portal: From Authentication Bypass to Full Account Takeoverを参照していただきたい。