GNU Screenには、プログラムが出力した特定の制御シーケンスを自動的にscreenコマンドとして再解釈し実行してしまうという、とても危険でありながらも魅力的な設定があります。実際にはこれを知っていてもあまり役に立ちませんが、なにかまじめに取り組んでいるふりをしながら暇を潰したりするにはちょうどよい機能かもしれません。
有効化
この設定は以下のscreenコマンドで有効化されます。
acladd :window:
一見なにも変わったようにはみえませんが、これを有効化したら、あなたは端末へ出力されるシーケンスを適切に予測し続けなければいけません。
もし制御に失敗して出力に予測不可能な外部データが紛れ込もうものなら、SSH鍵などをぶっこぬかれたり端末を乗っ取られたりしてもおかしくない状態です。やばいですね。
使い方
遊び方の幅は無限大ですが、ここでは端末への安全な出力が特に(あえて?)考慮されていないように見受けられるプログラムのひとつである、gccを使ってみます。
gccがこのモードのGNU Screenでコンパイルされることを前提にすれば、コンパイル時の副作用を擬似的に表現することができます。
たとえば、コンパイルの途中で/usr/bin/ejectを呼んでみることにしましょう。
Cのソースに以下のようなディレクティブを書きます。
#warning ^[]83;!/usr/bin/eject^G
ここで、"^["、"^G"は制御文字のつもりで書きました。
実際に入力するときは、エスケープせずに直接入力する必要があるので、「C-v + C-[」や「C-v + C-g」のようにタイプします。
$ gcc test.c
とすればコンパイル時にejectが走ると思います。
また、screenコマンドを走らせるアクションは同期的に実行される、というところもポイントです。たとえばこのようにすれば、リモートにあるコードも参照可能になります。
#warning ^[]83;!wget remote.server/program.c^G
#include "program.c"
コツをつかめば自己改変や本格的な対話的インターフェースを実現することも難しくはなさそうですね。
他にもちょっとした細工で特殊な文字列を出力に紛れ込ませることが可能なプログラムはいくつかありますので、探してみるのも面白いでしょう。
特に外部システムなどから受けとったデータをそのまま端末に流してしまうタイプのものは、脆弱性と判断されることが多いみたいです。
今回はGNU Screenを使って遊びましたが、別解として、この機能に相当するような一部の端末エミュレータの脆弱性を活用するという方法もあります。
でもこれをちゃんと動作させるには端末や環境を選びますし、何より早く修正しろみたいな話になってしまいますよね。
その点GNU Screenはあえて確信犯的にこれを実装しているようなので、脆弱性ではなく機能である、と言い張ることができそうです。さすがですね。