ゴルフ場のセキュリティ
Rui ゴルフ場の話をすると、ゴルフ場のサイトって任意コード実行なわけじゃないですか。そのセキュリティがどうなっているのかというのを聞きたいのですが。
Hamaji ゴルフ場のセキュリティと言ったときに達成したい目標は多分2つあって、一つは好き勝手なことをされたくないということ。例えばディスク使いきるとか、外にネットワークアクセスするとか、大事なファイル消すとか、要するにrootとられて何でもかんでもされるっていうのはあまりうれしくない。そういう普通の意味でのセキュリティがある。もう一つはチートされたくないっていうゴルフ場特有のセキュリティがあります。チートされたくないというのは、例えばどこかの短いURLにゴルフの難しい問題の解答を置いておけばそれをダウンロードしてきてevalするだけで終わってしまうので、例えばそういうのを防ぎたい。典型的にはファイルを残されたくないんですね。ファイルを残されるとそのファイルを読むだけで答えを返せちゃうので、ファイルが残らないように一応気を使っています。大体その2つが達成したいゴールですね。
Rui ゴルフ場はシェルもあって根本的に何のコマンドも実行できるし、仮にCコンパイラしか使えなかったとしてもCコンパイラって入力に対して頑強になっているわけじゃないから、コンパイラのバグを突くCプログラムを読ませればコンパイラを狂わせてプロセスを乗っ取るとかも可能なわけじゃないですか。だからゴルフ場は本当になんでも実行できる環境なわけですが。
Hamaji ゴルフ場は2レイヤーのsandbox的なものがあって、1レイヤー目が単にXenで動いていて、ウェブサーバなどはそちらで動いています。2レイヤー目のVMが実行サーバみたいな感じになってて、その中でなら任意コード実行していいよっていう感じにしています。ネットワーク的に2レイヤ目の仮想ネットワークから外に出れないようにしてあるので、そういうレイヤリングで表側のフロントエンド側のサーバは任意コード実行とは無縁のところで動いている。
Rui どういうことですか? そのVMではネットワークデバイスが無いってことになっている?
Hamaji あるけど、親しか見えていない。インターネットが見えていない。
Rui じゃあプライベートなIPになっている?
Hamaji ですね。はい。
Rui 親には通信可能?
Hamaji 親には通信可能ですね。そうしないと、親からいろいろ持ってきたりしたいので。
Rui VM自体を次回を毎回再起動しているってわけではないんですか。
Hamaji してないですね。それすると遅すぎる。最近はどうなのか分からないけど。
Rui レジュームみたいなやつできるんじゃないですか?
Hamaji うん。ただもう昔の技術だとできなかった気がしますね。どうだろう、分からないけど。その手のことは開いているソケットとかもちろんないわけだから、できないわけではないかもしれないけど、どうなんでしょうね、メリットがあるんだろうか。
Rui ゴルフ場のためにカーネルに手を入れてませんでしたっけ。
Hamaji 2レイヤー目のカーネルには手が入っています。今言ったやつだけだと全然ファイルを残すとかできちゃうので。あとゴルフ場特有の事情としてexecveというシステムコールを禁止したいんですね。それをされてしまうと、Cのプログラムなのにいきなりsystemっていう関数を呼んでPerlを実行されると、すべてのCのプログラムの解答はPerlプラス何バイトみたいな感じになってしまって全然面白くないので、execの回数をカウントするとかそういうことをやっている。
Rui そうは言っても例えばシェルスクリプトとかだとexecが本質的に必要。
Hamaji そうですね。いくつかの言語は明示的にexecを許してます。というか正確にはexecってプログラムの起動中に必要な言語処理系が結構あるので。
Rui CだってCコンパイラドライバがcc1を起動してみたいなことはやるわけですよね。
Hamaji コンパイルは別ステップなのでそっちは数えてないです。実行中に何回execveが呼ばれたかっていうのをカウントしている。
Rui なるほど。
Hamaji WineとかだとWineのサーバとかいっぱい動くので、hello, world動かすだけでも確か7〜8個とかプロセスが動く。
Rui WindowsのWine?
Hamaji はい。ゴルフ場はWindowsバイナリをサポートしておりますので。
Rui (笑)
Hamaji で、そういういろいろなシステムコールにフックを入れてexecveの数を数えるとか、あと念のためsetuidを禁止するとか、ユーザ権限だとソケット関係のシステムコールが全く動かなくなるようにしてあるとか、そういうチョコザイなことをいろいろしている。
Rui そのVM内ではrootを取られてもいいということになっているんですか。
Hamaji なってないです。取られたくないです。
Rui そうですよね、別に毎回再起動するわけでもないし。
Hamaji だから取られたくないなぁということで一応念のためぐらいのおまじないぐらいの理由でsetuidとか全部塗りつぶされているというか。
Rui それってカーネルに手を入れないとできないんでしたっけ?
Hamaji カーネルモジュールでやってますね。当時はどうだろう、今はseccomp-bpfとかあとalt-syscallみたいなやつとかがあるからできるかもしれないけども。
Rui システムコールをフックするって汎用的なメカニズムだし何かありそうな気がするんですけれど。
Hamaji いろいろあるけれど当時使い物になったものっていうものがあまりない気がするし、というかカーネルモジュールを書くというのはわりと簡単な部類だから、悪くない方法だと思うんですよね。
Rui カーネルモジュールをつかってシステムコールをフックするって、どうやるんですか?
Hamaji カーネルモジュールの初期化ルーチンでシステムコールテーブルの関数ポインタを片っ端から入れ替えていくっていうだけですね。非常にシンプル。
Rui 確かに。そこに元々入っていた関数っていうのを呼んでよければ呼ぶ。良くなかったらもうそこでreturnしちゃう。
Hamaji はい。ソケット関係のシステムコールを殺すと言っても本当に全部殺しちゃうとUNIX domain socketとか作れなくなっちゃうので、確かC#のMonoとかが動かなくなる。
Rui いろいろサポートしてますね。
Hamaji そりゃあもうそうです。
Rui 何種類サポートしてるんですかそれ。
Hamaji 100ちょいだったと思いますけど。109って書いてありますね。
Rui 100個。
Hamaji 言語が100個ですね。同じ言語とかも何個かあったりとか。例えば最近bashの2種類目みたいなの出して、任意コマンドを実行できるbashとビルトインだけで戦うbashみたいなのが。echoとかは使ってもいいけどlsとかは使えないbash。forkはできて、サブプロセスやサブシェルは作れるけど、execができないbash。
Rui つまりファイルシステムに/bin/bashしかない環境というか。
Hamaji はい。それでも結構問題は解けるので。
Rui bashビルトイン、計算もできるし。
Hamaji そうですね、いろいろできるので。
Rui APL系の言語はどうなんですか
Hamaji 今見たら3位がJっていうAPL系の言語ですね。
Rui JってなんかASCIIだけで書けるようにしたAPLみたいな言語ですよね。APLってなんかいかにも短くなりますよね。
Hamaji そうですね。そう思います。ベクトル計算みたいなのは強いんでしょうね。
Rui 行列計算がそのままですからね。あと演算子の優先順位とかがなくって、全部右結合じゃなかったでしたっけ。
Hamaji そうなんですか。
Rui なんかAPLは少なくともそうだった気がするなぁ。
Hamaji うーん。なるほど。
Rui だから括弧書くのが少なくて済むのかな。わからないなそれは。
Hamaji 僕も真面目に書いたことないからなぜこんなに強いのかよく分かってないんですけど、多分に属人的というか……。
Rui 単にJエキスパートがいるだけ。
Hamaji そう、Jでゴルフを頑張った人っていうのが何人か居て、っていうのももちろんあると思いますね。しかしRubyを倒しているっていうのは凄いですね。
Rui 標準の機能っていうのは少なそうなイメージがあるけどどうなんですかね。Rubyは組み込みの機能がいっぱいあるけど。
Hamaji でもゴルフの問題とかってシンプルな問題が多いから、例えばウェブサーバを動かせって言われたらRubyの方が短いかもしれないけど、FizzBuzzを書けって言われたらJも頑張るんですかね。わからないですけど。
Rui あとなにか別の理由でカーネルに手を入れてませんでしたっけ?
Hamaji 基本的にはシステムコールを置き換えるぐらいしかしてないと思いますね。カーネルとは直接関係ないけど、ファイルをうっかり残せるようにしちゃってたみたいなチートは多かったんですけど、そういうのじゃなくて結構あぁなるほどと思ったのが、System V IPCを使うっていうのがあって。
Rui System V IPCって何でしたっけ?
Hamaji カーネル空間にメッセージを残せちゃうんですよね。
Rui あー、なんか確かにキューが付いている気がする。
Hamaji SysV IPCみたいなのはもうこの世に存在しないものとして考えても良い気がするんですが。
Rui SysV IPCってカーネル内でメモリリークせずに使うのが逆に難しいものだった気がする。
Hamaji そうだと思います。だからいくらでも残せるみたいな。そこの空間に答えを残しておいて使うことによって短い答えを実現するみたいなことをやった人がいて。なるほどと思って。
Rui それはどうやって防ぐんですか。
Hamaji 普通にprocfsでメッセージのサイズみたいなのを極端に絞ったので、今は大丈夫だと思います。
Rui 極端に絞ったって1バイトとか?
Hamaji 覚えてないです。なんかの理由で16バイトとかそのぐらいほんの少しだけ許さないとダメだった気がしたので、完全にゼロにはしないけど、普通に答えを埋めるには明らかに不十分な空間にした。
Rui 16バイトってわりと十分そうにも聞こえますけど。
Hamaji 100バイトとか200バイトはほしいですよね。だって単純にSysV IPC呼ぶのにコードが必要なんだから、それより長いものを取ってこれないと割にあわない。
Rui ではゴルフ場チート専用言語でSystem V IPCが1バイトでできる言語を作ればどうか。
Hamaji そういうのはでも結局、"h"って書くとhello, worldって出る言語とかはあるので、アイデアとしてはあるけどあんまり面白くはないですね。
Rui 確かに面白くはないですね。
DEFCON CTF »