2020年9月16日水曜日

Sinatra の Rack::Protection で有効になっているパストラバーサルの機能を無効にしてどのような影響があるのか確認してみた

概要

パストラバーサル は脆弱性の一つでリクエストに相対パスや絶対パスを入れることで意図しないファイルにアクセスされてしまう脆弱性です
Sinatra にもかつでパストラバーサルの脆弱性があり現在では対応されています
今回はあえてパストラバーサルの保護機能を無効化しどのような影響があるのか確認してみました

環境

  • macOS 10.15.6
  • Ruby 2.7.1p83
    • sinatra 2.0.7

Rack::Protection::PathTraversal の効果

試してみた感じ request.path_info を見て %2e のドットの URL エンコードした文字をデコードするかしないかくらいの効果しかなさそうです
以下で例を紹介します

パストラバーサルを無効にしたコード

とりあえず動作確認してみました
Sinatra でパストラバーサルを無効にする方法は set :protection, :except => :path_traversal を追記するだけです

  • vim config.ru
require './app'
run App
  • vim app.rb
require 'sinatra/base'

class App < Sinatra::Base
  set :protection, except: :path_traversal

  get '/test' do
    env['PATH_INFO']
  end
end

set の部分をコメントアウト/インして動作確認してみます

テストコード/動作確認

以下のような curl を実行するスクリプトを作成しました

curl "localhost:9292/test"
curl "localhost:9292/test/../test"
curl "localhost:9292/test/%2e%2e/test"

これを使ってパストラバーサルが有効なときと無効なときで動作確認してみました
結果は以下の通りでした

  • パストラバーサル有効・・・すべて 200 でアクセスできる
  • パストラバーサル無効・・・1, 2 番目が 200 でアクセスできる、3 番目は 404 になる

という感じでした
要するにパストラバーサルが無効になっている場合は %2e -> . に変換していないことがわかります
また . を直接指定した場合はパストラバーサルの有効/無効に関わらず畳み込みをしてくれるようです

そもそもパストラバーサルに脆弱なサンプルコード

ちょっと話は逸れますがそもそもパストラバーサルに脆弱なコードを紹介します
パストラバーサルを無効にし脆弱性のあるコードをあえて作成します
指定されたファイルを読み込んで返却するようなアプリケーションになっています

  • vim app.rb
require 'sinatra/base'

class App < Sinatra::Base
  set :protection, :except => :path_traversal

  get '/test' do
    File.read(params["path"])
  end
end
  • vim config.ru
require './app'
run App

脆弱性の確認

例えばアプリケーションのカレントディレクトリにある hoge.txt というファイルを読み込む場合には以下のようにリクエストすると思います

  • curl "localhost:9292/test?path=hoge.txt"

app.rb と同じディレクトリに hoge.txt があれば問題なく読み込みレスポンスとしてファイルの内容を返却します
ただこのコードには脆弱性がありフルパスなどを入れるとアプリケーションの上位のファイルも簡単に参照できてしまいます

  • curl "localhost:9292/test?path=/etc/hosts"
  • curl "localhost:9292/test/../open?path=../../../../../etc/hosts"

これで hosts ファイルの内容を簡単に確認できてしまいます
簡単なサンプルですがこれがパストラバーサルに脆弱なサンプルコードになります

Sinatra の Rack::Protection::PathTraversal では上記のようなコードは対処できない

もうここまでくればわかると思いますが params などのリクエストを使ってファイルなどを参照する場合は Rack::Protection::PathTraversal が使えないことがわかると思います
というか Rack::Protection::PathTraversal はほぼ何もしていない感じなのでパストラバーサル対策は自信のアプリケーション側でしっかり行う必要があります

ちなみに Sinatra の Rack::Protection::PathTraversal で対処できそうな脆弱なコード

こんな感じのコードをもし書いていたとすれば path_traversal を有効にするだけで対応はできそうです

require 'sinatra/base'

class App < Sinatra::Base
  set :protection, except: :path_traversal

  get '/*' do
    File.read(env['PATH_INFO'].gsub('%2e', '.'))
  end
end
  • curl "localhost:9292/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/hosts"

そもそもデフォルトの Webrick で動作させていると上記のリクエストは Bad Request で弾かれます
thin を使った場合は弾かれないので path_traversal を使うことが有効ですがそもそもこんなコードは書かないかなと思います

最後に

Siantra のパストラバーサル防御機能の動作確認をしてみました
デフォルトは有効なので気にする必要はないのですが Rack::Protection::PathTraversal だけではパストラバーサルの脆弱性を完全に防げているわけではないので注意が必要だと言うことがわかりました

参考サイト

0 件のコメント:

コメントを投稿