理由
現状の一般的な使われ方(特にデスクトップでの)では、 "権限を持つアカウント" と "権限を持たないアカウント" の分離を無意味なものにしてしまっているから。
概要
"現状の一般的な使われ方" とは、ネット閲覧などの普段使いのアカウントに "ALL=(ALL) ALL" のような設定をしているような使い方です。
(例えばUbuntuのインストール時に作ったアカウントでそのまま普段使いをしているような場合)
これらのツールは実行時にパスワードによる認証を必要とするため、一見そのような使い方でも安全であるかのように思えます。
しかし実際は、そもそもの第一歩となるこれらのツールがユーザーのセッションから起動されるためそのパスワードによる保護にはあまり意味がありません。
なおあくまで一般的な状態での話であり、「強制アクセス制御とか使えば防げるよ!」といったあたりには触れません。
例
これらのツールのパスワード保護は実質的には無意味であること、 "su|sudo|polkit が使えるアカウント" (以下アカウントAとする)の侵害が "システム全体" の侵害と同等であることの説明であるため、スタート地点はアカウントAが侵害された時点です。
つまり攻撃者はアカウントA自身のファイルを改ざんしたりはできるが、パスワードは知らないため "sudo rm -rf --no-preserve-root" などは実行しようとしても実行出来ないという状態です。
- Bashのfunctionを使う
攻撃者はアカウントAの.bashrcなどは書き換えることが出来ます。
なのでそれらのファイルに
function sudo() {
if [ ! -f "/tmp/pass" ] ; then
stty -echo
$(which sudo) -k
echo "[sudo] password for $USER:"
read pass
stty echo
echo $pass >> /tmp/pass
echo "Sorry, try again."
fi
$(which sudo) "$@"
}
のように追記するだけで攻撃者は正規のユーザーが次にsudoを使う時に、実際のsudoをバイパスさせてパスワードを盗むことが出来ます。
- Xorgを使う
Xは各クライアント毎の入出力になんら制限を課していません。
なのでX上でアカウントAが入力するパスワードは同じXサーバに接続する他のクライアントプロセスから覗き放題となっています。
簡単に確認するには、xinputを使ってみるといいと思います。
端末を2つ起動し片方でxinputを実行、もう片方でsudoなどを使うと、パスワード入力もきちんと取得されているのが確認できます。
ちなみに「xinputをインストールするのにrootの権限が必要だろう」と思う人がいるかもしれません。
ですが、rootの権限が必要なのは書き込む権限のない場所に展開しようとするからであって、攻撃者はアカウントAのホームに展開すればいいだけなのでなんの問題にもなりません。
「共有ライブラリの存在やバージョン違いなどで起動できないだろう」というのもディストロ配布のバイナリはそうなっている、というだけで攻撃者には大した制限にはなりません。
まとめ
"su|sudo|polkit が使えるアカウント" は "権限を持たない普通のアカウント" ではありません。
たとえそれらを使っていない時でも、 "su|sudo|polkit が使える" 時点でそれはrootと同じ "権限を持つアカウント" であり、そのアカウントでのログインはrootでのログインとセキュリティ的には同じです。
"su|sudo|polkit が使えるアカウント" が侵害されれば、それは "システム全体" が侵害されたのと同じです。
対策
根本的な対策はXやシェル等を巻き込んで大きく変更しないといけないため個人レベルでは難しいと思います。
それでも出来る対策としては、これらのツールでも2段階認証を行うようにするとかでしょうか。
ですが現状のLinuxの狙われ具合からするとそこまでする必要はないかな、と言う気もします。
とりあえず自分の行っている対策は次のような形です。
(ちなみに例であげたようにこれらのツールのパスワード保護は実質あまり意味のあるものではないため、この対策を行った上でならNOPASSWDを使ってパスワード入力を省略してしまっても安全性はたいして変わりません)
- /etc/pam.d/sudo 内で pam_exec.so を使いsudoによって目的のコマンドが実行される前にスマホにメールでアラートが行くようにし、メールの送信が失敗した場合は目的のコマンドも実行されないようにする
sudoによって対象のコマンドが実行される前の段階で別のシステム上にsudoが使われた記録を残すことで、侵害自体は防げなくとも少なくとも"侵害があった"という記録を攻撃者には消せない形で残せるようになります。
これがもし対象のコマンドが実行された後や、/var/log/に記録を残すという形の場合ユーザーに気づかれる前に攻撃者によって消されてしまう可能性があるため、前の段階と別のシステム上というのが重要です。
もっと良い方法のアドバイスや「それじゃ駄目だよ!」とか「むしろ危険になってるじゃん!」などもツッコミもいただけると嬉しいです。