やられアプリ BadTodo - 26 レースコンディション

前回:やられアプリ BadTodo - 25 TOCTOU競合 - demandosigno

競合状態 (race condition)
情報処理における競合状態は「イベントタイミングへの予期せぬ依存が引き起こす異常な振る舞い」である。特に複数のプロセスやスレッドが通信しながら動作する場合(並行計算)に発生するが、単一スレッドで動作している場合であっても、シグナルによる割り込みが原因で発生することもある。
競合状態 - Wikipedia

TOCTOUも競合状態の一種と考えて良いようです。

システム開発のセキュリティにおいてレースコンディションと TOCTOU は、しばしば混同して使われることがありますが、それぞれの違いについて用語の整理から確認していきましょう。
レースコンディション(Race Condition)とは、複数の処理が同じデータに対してアクセスしたときに、競合状態になることで想定外の処理が引き起こされる問題です。
対して TOCTOU(Time Of Check To Time Of Use)とは、あるデータの検証時点と使用時点での状態の差異によって想定外の処理が引き起こされる問題です。
つまりレースコンディションは、さまざまな競合状態の問題を表す包括的な脆弱性なのに対し、TOCTOU はより実装の状況を限定した具体的な脆弱性であることが分かります。
TOCTOU/レースコンディション | WebApp Testing

BadTodoでの例

Todoの添付ファイル機能でファイル名の競合が起きます。

今、userA, userBというアカウントがいて、1件Todoを作成済みです。非公開としていますのでお互いには見えていません。

そして一方をブラウザのシークレットモードで開いて、二人平行して操作していきます。
Todo編集画面に入り、添付ファイルを1件追加します。
ファイル名は同一にしますが (test.txt) 内容はそれぞれのものです。

それぞれ横に並べて「更新」ボタンを続けてクリックして登録してみます。

ファイル名にマウスを乗せ確認してみます。さすがにそのままのファイル名ではなく、頭に別の文字列が付与されていますが 6589a3e5-test.txt、6589a3e6-test.txt のように1だけしか差がありません。

Burpの送信結果を見ると1秒差で送信されていることが分かります。

もっと同時に送信してみる

一旦添付ファイルを削除します。
1秒で1差ということはそれほど厳密に分けられてはなさそうです。であればシェルから&で繋げてリクエストする程度でいけるかもと考えcurlで試すことにしました。 他のコンテナからリクエストを送ってもよいですが今回はBadTodoにcurlをインストールしました。

# apt install curl

一つ分のPOSTリクエストが下記です。
# curl --cookie "TODOSESSID=7afb65ad5ab2c8a1c00c4343f7261a0d" https://todo.example.jp/editdone.php -x http://host.docker.internal:8080/ -F todotoken=89cf61981938e3235a7b0c199e2cd7e8 -F item=4 -F todo=TestA -F c_date=2023-12-29 -F attachment=@/var/www/materials/a/test.txt -k
TODOSESSIDとtodotoken、item番号はブラウザやBurpSuiteから適宜取得して置き換えてください。-x オプションでBurpProxyを通しています。
添付ファイルは /var/www/materials/ 辺りに/a/ /b/とフォルダ分けして置いておきます。

そしてAとB二つ分のリクエストを&で繋いで送信用意(添付ファイルのディレクトリを変更し忘れないように)。送信。
# curl --cookie "TODOSESSID=7afb65ad5ab2c8a1c00c4343f7261a0d" https://todo.example.jp/editdone.php -x http://host.docker.internal:8080/ -F todotoken=89cf61981938e3235a7b0c199e2cd7e8 -F item=4 -F todo=TestA -F c_date=2023-12-29 -F attachment=@/var/www/materials/a/test.txt -k & curl --cookie "TODOSESSID=c240286adc0891c0e2a82f54619d8b93" https://todo.example.jp/editdone.php -x http://host.docker.internal:8080/ -F todotoken=d9d2d93c78500173d6d71bd5a2fef27e -F item=5 -F todo=TestB -F c_date=2023-12-29 -F attachment=@/var/www/materials/b/test.txt -k

二つのPOSTリクエストが1秒未満の間隔で送受信されました。

ファイル名を確認すると6595a3e9-test.txtまったく同じになってしまっていることが分かります。

ファイルを右クリックし「新しいタブで開く」から中身を確認すると、testBユーザにtestAユーザの内容が表示されます。またtestBユーザの元のファイルが消えてしまったことも問題です。

BurpSuite の Intercept を使う方法

上の例ではcurlを使ってリクエストを送信しましたが、BurpSuiteの Intercept機能を使えばまとめて送信することができました。こちらの方が簡単です。

Todo編集画面を横に並べて「更新」ボタンをクリックする前に、BurpSuiteの Interceptを「ON」にしておきます。

その後で「更新」を双方のんびりクリック。

リクエストがBurpで止められているので「Intercept is on」ボタンを再度クリックして全部のリクエストを流します。

同じファイル名になりました。

今回のように1秒も猶予があるようなシステムはそうないのでは?と思っていたのですが

川崎市様における証明書誤交付ついて : 富士通Japan株式会社
本事象の原因は、2か所のコンビニで、2名の住民の方が同一タイミング(時間間隔1秒以内)で証明書の交付申請を行った

のような事例がありました。

他の部分にも幾つか存在するようですので引き続き探します。

次回:BadTodo - 27 キャッシュからの情報漏洩 - demandosigno

/* -----codeの行番号----- */