本サイトは、快適にご利用いただくためにクッキー(Cookie)を使用しております。
Cookieの使用に同意いただける場合は「同意する」ボタンを押してください。
なお本サイトのCookie使用については、「個人情報保護方針」をご覧ください。
ある会社で開発したSNSのシステムにセキュリティ上の問題があると指摘されました。あなたのチームのミッションは、
「このシステムに潜む脆弱性を探し出せ!」
――はたして、参加者はこの会社の危機を救えたのでしょうか。
去る12月13日、三井物産本社の一室にて、専門学校に通う生徒を対象としたコンテストである、MBSD Cybersecurity Challengesの最終審査会が行われました。ここでは最終審査会での専門学校生の活躍と、とあるチームの攻撃デモを紹介したいと思います。
ちなみに私は審査用の課題とするSNSシステムの製作者として、また審査員としても本コンテストに関わっておりました。つまり課題用システム上の問題点(脆弱性)を指摘される側です。意図的に仕込んだとはいえ、自分で作ったシステムの脆弱性を5時間にわたって指摘され続けるのは中々つらかったです……。セキュアプログラミングをしようと心に誓いました。
本題に入る前に、まずはコンテストの概要と最終審査会に至るまでの審査について、簡単に説明します。
冒頭の記述の通り、課題はSNSシステムに潜む脆弱性の指摘でした。一次審査として脆弱性を指摘し再現方法やリスク、修正方法、更にどうやって見つけたか等の工夫についてレポートにまとめて頂きました。そして、一次審査の上位10チームが最終選考としてプレゼンを行い、レポートとプレゼンの審査結果の上位3チームに賞品が授与される、というものでした。詳しくはビーアライブ社のページをご覧ください。
出題したSNSにはMBSD Blog読者の皆さんおなじみのクロスサイトスクリプティングやSQLインジェクションといったテクニカル系の脆弱性から、強制的に友達になる、日記を改ざんするなどのSNS特有のロジック系脆弱性まで幅広く埋め込まれていました。また、それを動かすサーバ側にも、HeartBleedやPOODLEといった著名な脆弱性や、MySQLに直接アクセス可能+rootアカウントのパスワードが設定されてないなど、色々な脆弱性が埋め込まれていました。この脆弱性てんこ盛りのサーバをVMにして配布したのですが、OSのrootアカウントのパスワードやSNSの管理者アカウント等は秘密としました。
皆さんならこのシステムをどうやって診断しますか?
私が参加者だったら、とりあえずディスクイメージを別のOSから読み込み、rootで入れるように編集してから診断作業を始めると思います。実際この手法でrootをとって内側から診断しているチームもありました。単純な脆弱性の指摘にしてしまっては軒並み同じレポートが出てきて面白くないので、少しひねって工夫する余地を出してみたのですが、結果としては想定通り各チーム工夫していて面白いレポートになったと思います。
肝心の脆弱性の指摘に関しても面白い違いが見られました。例えばSQLインジェクションはかなりのチームが発見していたのですが、単に「この機能にあります」、とだけ報告しているチームも居れば、sqlmapでDBのダンプを取得する手順を示すチーム、コードレベルでの修正提案を行ったチームなどもあり、読み応えのあるものとなりました。ちなみにこのサイトのほとんどの箇所にはSQLインジェクションの脆弱性があったのですが、幾つかの機能では単純には攻撃できないため、その機能に関しては報告が漏れている、あるいは説明不足なチームが多々ありました。専門学校生向けにCTFを開催する機会があれば、この盲点を突く問題を作ってみようと思います。
そんな難関を潜り抜け一次審査を突破した上位10チームが、最終審査会に参加しました。
最終審査会では一次審査のレポートの中からこれぞ!という脆弱性を任意に選んで発表する方式だったため、どの脆弱性を選ぶか、という所からチームの色が出るプレゼンとなりました。
例えばあるチームは「MySQLのrootパスワードが設定されていない上に外部からアクセスが可能」という脆弱性に絞って、最大限悪用した場合に何ができるかを示していました。
事象としては、パスワードの設定が無い上に接続制限が成されていないという単純な問題ながら、Webアプリを利用しているユーザのパスワードを書き換えて不正ログインするデモや、LOAD_FILE関数を用いてサーバ上のmysqldの権限で読める全てのファイルを取得し他の穴が無いか探すデモなど攻撃的な内容のものを行っており、非常に分かりやすくリスクが示せていました。
この脆弱性を選んだ根拠としても「Webセキュリティが堅牢でもサーバセキュリティがダメだとこうなる。まずはサーバセキュリティの確認を」という理由を示しており、他チームが複雑な脆弱性の説明をする中、ひときわ目立つプレゼンとなっていました。
他にも、「最大の脆弱性は開発者が新しい情報を仕入れていないことである」と指摘したチームもありました。今回の問題サーバは2011年に公表されたとある脆弱性を抱えており、そこから「開発者は最新の情報を仕入れていない」と推測したそうです。学生ならではの非常にユニークな視点であり、課題製作者としては予想外の指摘でした。
脆弱なサイトを作ってしまった側として(そうは言っても……と思いつつも)対策として提示された最新の情報を仕入れるために見るべきサイトを見ながら日々勉強します。
こういったユニークなプレゼンを10チーム分聴いたのちに、レポートとプレゼン双方の評価を勘案し、上位3チームを決定しました。
本コンテストは賞品付きのコンテストであり、勝ち抜いた上位3チームには賞品が渡されました。
最優秀賞(1チーム) |
|
---|---|
第2位(1チーム) |
|
第3位(1チーム) |
|
中でもオリジナルステッカーはこの大会のために作られたものであり、参加者にしか配られておりません。選ばれし10チームの証です。
巷で見かけた際には、ぜひともコンテストでの奮闘ぶりを聞いてみて下さい。
左から順に、1位(金)、2位(銀)、3位(銅)、最終審査参加賞のステッカー
懇親会ではセキュリティに興味のある学生同士、親交を深めていました
それではお待ちかね、最終審査会の場で示された攻撃デモの一つをご紹介いたします。なおあくまでその手法の紹介であって、審査会でのプレゼンとは異なります。プレゼンはあの場にいた人だけの特権ということでご了承ください。
起点となるのはWebアプリケーションです。
出題サーバ上ではSNSが稼働しており、他のユーザと友達になる、メールを送る、日記を書くなどの機能があります。
メールを送る機能にはファイルを添付する機能があるのですが、ここにはWebサーバの権限で任意のコードが実行可能な脆弱性が隠れています。
原因となったコードは以下のものです。
$prefix = md5(time() . $user->id);
$tname = $prefix . basename($_FILES["file"]["name"]);
if (move_uploaded_file($_FILES['file']['tmp_name'], "./tmp/".$tname) && preg_match("/^[^.]+\.jpg$/",$tname)) {
上記コードはファイルをアップロードし、拡張子がJPGであれば{ランダムな文字列+元ファイル名}としてtmp
フォルダに保存する、というものを意図して書かれています。
ですが、このコードでは先にアップロードしてファイルを保存してから拡張子チェックを行っており、さらにエラーが起きた際にもファイルを削除していないため、画面上ではアップロードに失敗したように見えても、実際にはアップロードしたファイルが./tmp
に作成されてしまいます。ちなみにbasename
関数を使ってファイル名を組み立てる場合は別途注意が必要ですが、本題と外れるので割愛します。
失敗しているのにアップロードされているphpファイル
ファイルが保存されているtmp
フォルダはユーザから直接アクセス可能なところに設置されています。さらに、ファイル名のprefixはユーザ毎に見た時、time
関数に依存しているため1秒毎にしか変化しません。このため1秒以内にアップロードされると共通のprefixを持つファイルが生成されます。なお、そもそもtime()
も$user->id
も予測可能なので、手元でもファイル名を組み立てられます。
結果として、PHPファイルをアップロードし、ファイル名を推測してブラウザからアップロードしたファイルに直接アクセスすることで、該当のPHPを実行できてしまいます。
それだけでは満足せず、かのチームはアップロードしたPHPを用いて、Webサーバを動かしているapache権限からOSのroot権限を奪取したのです!
これにはDirty COWが用いられました。この脆弱性は簡単に言えば、Copy-On-Writeという機能にレースコンディションが発生する問題があり、本来権限を持たないファイルにも書き込めてしまうという脆弱性です。実はこの脆弱性は、発表されたのがコンテスト開催期間中だったため問題となるVMイメージの作成時には存在が確認されていませんでした。そのため、意図して仕込まれたわけではない純粋な脆弱性だったのです。これにはさすがに苦笑い。
こうして/usr/bin/passwd
にroot権限で動かしたい任意のコードを書き込み、これをPHPから呼び出すことで任意のコードをroot権限で実行できるようになりました。
<?php
//Dirty COWの脆弱性を利用しpasswdコマンドをidコマンドに変える
chmod("349e8260764c40b896c2a9f9edc09e3adirty",0755);
system("./349e8260764c40b896c2a9f9edc09e3adirty");
<?php
//書き換わった/usr/bin/passwdを実行し結果を出力
print `/usr/bin/passwd`;
uid=0(root)
今回の攻撃手順をまとめると、以下の通りです。
- PHPファイル及びDirtyCOW用のバイナリをアップロードする
- アップロードしたPHPファイルのファイル名を割り出し、ブラウザから直接アクセスする
- PHPがDirtyCOWを呼び出し
/usr/bin/passwd
を任意のコードに改変する /usr/bin/passwd
を実行するとroot権限で任意のコードが実行される
このシナリオは、能動的に行える非常に危険で現実的なものであり、脆弱性なサイトを作ってしまった情報に疎い開発者の私でもすぐに修正すべきだと分かるものでした。
今回のコンテストでは、専門学校生が持つ技術力や学ぶ意欲が良く表れていたと思います。
教科書通りではなく、自分で考え、経験を基にレポートやデモを組み立てるその能力には目を見張るものがありました。参加していた方々には、是非ともこれを機会に色々な勉強会やカンファレンス等に参加して、スキルを磨いて頂けたらなと思います。
ちなみに弊社でも勉強会を開催しているので、この記事を見て興味を持った学生も社会人の方も、ぜひ一度ご参加ください。
廣田一貴
おすすめ記事