open-uriってちゃんと実装しないとなにかと危険な香りがしますな、という話。
Ruby 2.4.0 リファレンスマニュアル module OpenURI
例えば外部のAPIを叩く必要があって
require "open-uri"
として使っていたとする。
フォームから受け取ったパラメータを入れてopen(なんやら)とする場合、そのままなんでもopen()の中に入れるとかなり危険。
例えばこれはフォームに入れたURLにしたがって、そのウェブサイトに行ってなんか取ってくる例。
コードで言うとこんな感じ。
require "open-air"
class PagesController < ApplicationController
def search
@page = open(search_params[:url])
end
private
def search_params
params.permit(:url)
end
end
おそらくこんなセキュリティー開きっぱなしな実装はしないと思うが、これをハックしてみるとこうなる。
Rubyの場合、パイプを渡せばそのまま外部コマンドが実行できる。
| ls
結果がこれ
ちゃんとlsコマンドの結果としてGemfileやらが見えてますな。ハッカー達がlsコマンドの結果を見ただけで立ち去る、なんてお行儀がいい訳ない。コマンドが実行できると分かればアレもこれもやられことは想像に難くない。
そこで対策としてparamsをチェックしましょう、と。でもそれが単に「正規表現とかでhttpを含んでいる場合だけopenを実行」だと突破はカンタン
このように||をつければOk
| cat /etc/passwd || http://son_of_a_bxxxh
A || B の意味はAを実行してエラーが出た場合にだけBを実行しなさい、という意味。言うまでもなくコマンドの意図はhttp....は単なるURL風の見せかけで/etc/passwdを見せなさい、と。
その結果がこれ。
見事に/etc/passwdが見えたりして香ばしい。
別にopen-uriがダメなライブラリと言いたい訳ではない。要はどんなライブラリでもその使い次第ということで十分気をつけましょう、と。
以前にこういうハッカー的なテクニックを使ったパズルを作ろうと考えていて、結果的にできたパズルがこれ。
ほとんどのエンジニアには解けるが、下位10%のダメなエンジニアにだけ解けないパズル?
このパズルにご登録いただいた解答者数がやっと5300を超えたあたりか。。。もっと伸ばす方法ないのかなー。