技術備忘録

環境構築によるトラブルの解決方法、知った技術のまとめなどを自分のためにも書き連ねていきます。あわよくば誰かの参考になればと思います。

脆弱性のあるWebアプリを直すイベントに参加した

先日リクルートが開催する 脆弱性を直して学ぶ!Webセキュリティハンズオン に参加しました。 コロナという事情もありオンラインで開催していたので、地方の自分としては嬉しかったです。

このイベントでは、事前課題として脆弱性のあるWEBアプリを直すというものが渡され当日はその解説を行うというものでした。

この脆弱性のあるアプリは、昨年の新人研修で行ったWebセキュリティの研修で使ったらしいです。

直していくアプリケーションはコードが公開されておりこちらです→GitHub - ommadawn46/badsns2019: Bad SNS 2019 Web Application Hardening (Boot Camp 2019) - Speaker Deck

今回せっかく学んだことを忘れないためにもこのブログに残したいと思います。

ただ、脆弱性が20個もあり全てを書くととても長くなるので、一部のみ書いていこうと思います。

今回書くこと

今回は以下の3点について書いていこうと思います。

パストラバーサル

今回のアプリケーションではパストラバーサルが発生するような状況になっていました。

このアプリはユーザ登録時にアイコンが設定できるようになっています。

また、アプリは以下の仕様を持っています。

  • 新規登録時にアイコンは非同期でアップロードを行い、アイコンが保存できればファイル名を返す

  • ファイル名は任意にファイル名をパラメータとして送ることが出来る

  • イコン画像の取得のAPI(/users/:id/icon )にアクセスするとファイルがダウンロードされる

攻撃シナリオ

  1. 新規登録時にファイルをアップロード(APIからファイル名 A.png が返ってくる)

  2. 攻撃者はファイル名を ../../../../../../../etc/passwd などに変更

  3. /users/:id/icon にアクセスするとサーバ上の/etc/passwdが取得できる

修正が必要な箇所は、アイコン画像取得のAPIで修正前のコードはこちらです。 badsns2019/users_controller.rb at master · ommadawn46/badsns2019 · GitHub

良くない修正例

アイコンのファイル名に対して以下のようなバリデーションを新規登録時にかけることによって、不正なファイル名を防ぐようにしました。

files/sns/app/model/user.rb

before_save :verify_valid_user

def verify_valid_user
  if self.icon_file_name != sanitize_filename(self.icon_file_name)
    errors.add(:base, 'アイコン名が不正です')
  end
  return false if errors.any?
end

def sanitize_filename(filename)
  return unless filename
  filename.gsub! /^.*(\\|\/)/, ''
  filename.gsub! /[^A-Za-z0-9\.\-]/, '_'
end

../ などの文字をフィルターで変換して防御するパターンは、攻撃不能か確認するのが難しく完璧に防ごうとするとロジックが複雑になるという欠点を持っています。

なので、このようなパストラバーサルに対しての修正は、カノニカルパス(RealPath)を使用した検証を推奨というアドバイスをいただきました。

より良い修正例

Rubyでは、realpathを返してくれるメソッドFile.realpath (Ruby 2.7.0 リファレンスマニュアル)があるのでそちらを使って実装します。

What is directory traversal, and how to prevent it? | Web Security Academy を参考に実装しました。

Below is an example of some simple Java code to validate the canonical path of a file based on user input:

File file = new File(BASE_DIRECTORY, userInput);

if (file.getCanonicalPath().startsWith(BASE_DIRECTORY)) { // process file }

files/sns/app/controllers/users_controller.rb

def icon
  user = User.find_by id: params[:id]
  send_data File.read "#{Rails.root}/public/images/default.png", disposition: 'inline' and return if user.nil?
  begin
    # 追加
    base_dir = "#{Rails.root}/public/icons/"
    raise unless File.realpath(user[:icon_file_name], base_dir).start_with?(base_dir)
    
    send_data File.read "#{Rails.root}/public/icons/#{user[:icon_file_name]}", disposition: 'inline'
  rescue
    presets = Dir["#{Rails.root}/public/icons/presets/*"].sort
    send_data File.read presets[user.id % presets.length], disposition: 'inline'
  end
end

加えたのは、こちらの2行です。

base_dir = "#{Rails.root}/public/icons/"
raise unless File.realpath(user[:icon_file_name], base_dir).start_with?(base_dir)

File.realpath(user[:icon_file_name], base_dir)絶対パスを取ることによってディレクトリを決定し、 その時のディレクトリがbase_dirから始まるものでなければ例外を発生させるという処理です。

このようにすることでパストラバーサルを回避することが出来ました。

SSRF

この脆弱性については聞いたことすらありませんでした。

アプリケーションサーバからOSコマンドインジェクションなどを行うことで、内部のネットワークのサーバに対してアクセス出来るという脆弱性だそうです。 今回の場合だとOpenGraphを取得してくる処理が問題で起きるようです。

該当コード: badsns2019/open_graph_controller.rb at master · ommadawn46/badsns2019 · GitHub

ユーザからの投稿したURLからOGタグを取得するのですが、こちらから内部のftpサーバにアクセスも出来るようでそこを突いた脆弱性でした。 (当日のイベントではSSRF自体聞いたことなく、メモを取る暇がなかったのでコードの修正は割愛させていただきます🙇‍♂️)

1, 2年前にEC2やGCEからcredentialsが取得できると話題になった脆弱性らしいです。

SSRF脆弱性を利用したGCE/GKEインスタンスへの攻撃例 | “>はい

SSRF(Server Side Request Forgery)徹底入門 | 徳丸浩の日記

暗号利用モード

該当コード: badsns2019/password_reset_controller.rb at master · ommadawn46/badsns2019 · GitHub

この OpenSSL::Cipher.new(‘aes-256-ecb’) が問題のコードです。 class OpenSSL::Cipher (Ruby 2.7.0 リファレンスマニュアル) によるとブロック暗号の方式は

  • CBC

  • “CFB”

  • “ECB”

  • “OFB”

の4パターンが利用できるようですが、今回のこのアプリケーションでは、ECBモードが採用されていました。

このECBモードは、同じ平文ブロックに対しては、同じ暗号ブロックに変換するという仕様で暗号化は出来ているものの(他の暗号モードと比べ)見破りやすくなっています。

暗号を使う時には公式のドキュメントを見て、正しく暗号化のモードを理解しなければいけないなと思った脆弱性でした。

まとめ

今回紹介した脆弱性以外にも、SQLインジェクションXSSなどなど…様々な脆弱性を解説していただきました。 大変勉強になりました、ありがとうございました!

今回のイベントで、セキュリティについての興味を持ち勉強する良いきっかけになりました。 次回似たようなイベントが開催された時には、全部解けるぐらいの知識をつけられるよう勉強していきたいと思います。

Burp Suite - Cybersecurity Software from PortSwigger (このツールは便利そうだったので、使ってみたい…)