きっかけ

"x: 100, y: 200, z: 300" のような文字列を
{x: 100, y: 200, z: 300}のようなハッシュに変換する方法
 :

パターン2 eval使う

超簡単(ruby怖っ)

def to_hash(str)
  eval("{#{str}}")
end

Ruby 文字列をハッシュに変換 - Qiita

を読んで、ふと
eval 族を使うのは怖いけど、 BasicObject#instance_eval であれば strに何らかのメソッドを使われたとしても NoMethodError になるのではなかろうか。リテラルは使えるし、これって eval でのセキュリティ対策に使えるかも?」
と思いました。

Rubyist の共通見解として「eval 族と method_missing は最終兵器」というのがあるかと思いますが、 BasicObject#instance_eval を使うと少し気楽に eval できるかも、と考えました(速度などは考慮してません)。

具体的にみてみる

上記例を実行

$ pry
[1] pry(main)> str = "x: 100, y: 200, z: 300"
=> "x: 100, y: 200, z: 300"
[2] pry(main)> BasicObject.new.instance_eval("{#{str}}")
=> {:x=>100, :y=>200, :z=>300}

問題なくハッシュを生成できました。

インジェクションしてみる1:メソッド

[3] pry(main)> str = "};puts 'hello!';{"
=> "};puts 'hello!';{"
[4] pry(main)> BasicObject.new.instance_eval("{#{str}}")
NoMethodError: undefined method `puts' for #<BasicObject:0x007fa980ca39c0>
from (pry):4:in `instance_eval'

無事に NoMethodError になりました。

インジェクションしてみる2:コマンド出力

[5] pry(main)> str = "};`echo hello`;{"
=> "};`echo hello`;{"
[6] pry(main)> `echo hello`
=> "hello\n"
[7] pry(main)> BasicObject.new.instance_eval("{#{str}}")
NoMethodError: undefined method ``' for #<BasicObject:0x007fa9814fe0e8>
from (pry):7:in `instance_eval'

str = "};%x[echo hello];{" でも同じく NoMethodError でした。

定数設定

[8] pry(main)> ARY
NameError: uninitialized constant ARY
from (pry):8:in `__pry__'
[9] pry(main)> str = '};::ARY = %w[a b c];{'
=> "};::ARY = %w[a b c];{"
[10] pry(main)> BasicObject.new.instance_eval("{#{str}}")
=> {}
[11] pry(main)> ARY
=> ["a", "b", "c"]

設定されてしまいました。

グローバル変数設定

[12] pry(main)> $ary
=> nil
[13] pry(main)> str = '};$ary = %w[a b c];{'
=> "};$ary = %w[a b c];{"
[14] pry(main)> BasicObject.new.instance_eval("{#{str}}")
=> {}
[15] pry(main)> $ary
=> ["a", "b", "c"]

グローバル変数も設定されてしまいました。

質問

BasicObject#instance_eval だと定数とグローバル変数が犯されうることがわかりましたが、そのほかに危険性はあるでしょうか。具体的に攻撃文字列を挙げていただければ幸いです。
また、定数とグローバル変数が犯されると、どのような危険性が考えられるでしょうか。

以上2点について、よろしくお願いいたします。