Aqutras Members' Blog

株式会社アキュトラスのメンバーが、技術情報などを楽しく書いています。

brakemanの検査をすり抜けたコードと,その理由の調査

こんにちは.mbuchiです. 弊社ではRailsを使ったシステムを幾つか開発しておりますが,そのセキュリティ面をチェックする方法の1つにbrakemanを利用しています.

Brakeman - Rails Security Scanner

brakemanの使い方については,上の公式サイトと,導入については以下のサイトが参考になりました. 警告を無視する方法とかHTMLでの出力とか書かれているのが助かります.

wonderwall.hatenablog.com

先日,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となり,file1.jpgを削除することになってしまいます.

攻撃する場合は,ファイル名にコマンドをつけます. 特にLinuxやMacではファイル名に/\0以外すべて使えますので,攻撃しやすいです.

たとえば,

hoge; `echo  "Y3AgL2V0Yy9ob3N0cyAvdmFyL3d3dy8uCg==" | base64 -d`;#

というファイル名で送られてきた場合,/etc/hostsを/var/www/ 中にコピーするコマンドが実行されます.

余談ですが,Windowsではファイル名に\ / ? : * " > < |が使えないため,windowsから攻撃しようとすると難易度が上がります.

ファイル名とファイル名の拡張子: よく寄せられる質問 - Windows ヘルプ

ちなみに,以下の様なコードではきちんと警告を出してくれます.

脆弱で,brakemanが警告を出すコード

user = params[:user]
`mkdir #{user}`

原因を探った

コードを読みました.

が,わかりませんでした.m(_ _)m

github.com

読んでいくと, https://github.com/presidentbeef/brakeman/blob/966581d21614c8e7d06f22fd3af4c37f060a1a8d/lib/brakeman/checks/check_execute.rb#L23 のcheck_for_backticksで検査してるっぽいのですが,実際に動かしてみると,````で囲まれた部分が検査されていないという状態でした.

もう少し調査してテスト内容を追加するPRを出せたらと思います.