brakemanの検査をすり抜けたコードと,その理由の調査
こんにちは.mbuchiです.
弊社ではRailsを使ったシステムを幾つか開発しておりますが,そのセキュリティ面をチェックする方法の1つにbrakeman
を利用しています.
Brakeman - Rails Security Scanner
brakemanの使い方については,上の公式サイトと,導入については以下のサイトが参考になりました. 警告を無視する方法とかHTMLでの出力とか書かれているのが助かります.
先日,brakeman
では引っかからなかった部分に,わりとシンプルなコマンドインジェクションが見つかりました.せっかくなのでその理由を調査してみました.
brakeman
をすり抜けたコード
ざっくりと以下の様な感じでした.
file = params[:file] file_path = Rails.root + '/' + file.original_filename File.open("#{file_path}", 'wb') do |f| f.write content end `rm '#{file_path}'` # ここが問題
どう問題なのか
ファイル名がエスケープされていないため,想定したとおりにファイル名が展開されません.
例えばファイル名がfile 1.jpg
だった場合は,スペースはエスケープが必要なため,問題の行はrm file\ 1.jpg
と
ならなければいけませんが,rm file 1.jpg
となり,file
と1.jpg
を削除することになってしまいます.
攻撃する場合は,ファイル名にコマンドをつけます.
特にLinuxやMacではファイル名に/
と\0
以外すべて使えますので,攻撃しやすいです.
たとえば,
hoge; `echo "Y3AgL2V0Yy9ob3N0cyAvdmFyL3d3dy8uCg==" | base64 -d`;#
というファイル名で送られてきた場合,/etc/hostsを/var/www/ 中にコピーするコマンドが実行されます.
余談ですが,Windowsではファイル名に\ / ? : * " > < |
が使えないため,windowsから攻撃しようとすると難易度が上がります.
ファイル名とファイル名の拡張子: よく寄せられる質問 - Windows ヘルプ
ちなみに,以下の様なコードではきちんと警告を出してくれます.
脆弱で,brakeman
が警告を出すコード
user = params[:user] `mkdir #{user}`
原因を探った
コードを読みました.
が,わかりませんでした.m(_ _)m
読んでいくと, https://github.com/presidentbeef/brakeman/blob/966581d21614c8e7d06f22fd3af4c37f060a1a8d/lib/brakeman/checks/check_execute.rb#L23 のcheck_for_backticksで検査してるっぽいのですが,実際に動かしてみると,````で囲まれた部分が検査されていないという状態でした.
もう少し調査してテスト内容を追加するPRを出せたらと思います.