0日目
私は自宅用に外部公開していないUbuntu Serverを運用しています。
時折SSHでログインしてsudo apt update && sudo apt upgrade
とかWinSCPでファイル操作しているのですが、ある日こう思いました。
root所有のファイルに触れないのがめんどくさい
そこでなんとなく自分がrootグループに所属してれば解決する気がしたので、少し検索してこのコマンドを入力しました。
$ sudo usermod -G root kurema
ここで私は3つ間違いを犯しています。
- rootグループに所属したところでroot権限は得られない。得られるのも望ましくない。
- rootグループに所属したところでパーミッションが
rwxrwx---
みたいなファイルしか触れない。大抵はrwx------
とか。 usermod
の-G
オプションは副グループが指定したものに書き換わる。追加したいなら-aG
。
やらかしました。
この時は気付いていません。
(ただしsambashareグループは残っていたので何か別の操作をしたかもしれません。)
1日目
しばらくしてログインした時、sudo
で以下のエラーが出ることに気づきました。
$ sudo apt update
kurema is not in the sudoers file. This incident will be reported.
ここでusermod
コマンドを間違えたくさいと思い当たりました。
Ubuntu Serverではsudoグループに所属しているユーザーがsudoできます。
/etc/sudoers
に書いてあります。adminでも良いようです。
しまった。現時点でsudo権限を持ったユーザーが居ない。どうしよう?
なんとかして誤魔化せないか。いや一般ユーザーがroot権限を普通に奪取出来たら脆弱性だ。
権限昇格系の脆弱性が公開されるのを待つか?いや待ってられないし実証コードとか絶対めんどくさいに決まってる。
考えろ。考えるんだ…。
まぁこの時点で解決策は分かっていました。
サーバーには物理アクセスできるわけですから、キーボードとモニターを刺してレスキューモードに入る、最悪ハードディスクを抜いて直接書き換えればどうにでもなる(ファイルシステムは暗号化していません)。
しかしそれは嫌でした。
なぜならめんどくさいからです。
そこで思い浮かびました。
確かcrontab
でroot
が毎日シェルスクリプトを回してる。
もうsudo
できないので記憶頼みだけど確かそうです。
しかもkurema
が書き換え可能な権限持ってる!
やった。勝った!
というわけでシェルスクリプト末尾に以下の行を追加しました。
cd `dirname $0`
#...
usermod -aG sudo kurema
そして安心して寝ました。
cronは夜働くからです。
2日目
再びログインして、sudo
を試しました。
$ sudo apt update
kurema is not in the sudoers file. This incident will be reported.
何も変わりません。groups
の結果も同じです。
スクリプト自体は動いた形跡があります。
とりあえずエラーか何かで途中で終了したのかもと考え、usermod
行を末尾から先頭に移動しました。
ちなみにシェルスクリプトでは途中エラーが出ても普通に下まで実行するはずなのでこれは間違いです。
途中で終了させたい場合はset -e
などとしますが、今回してないので推測がおかしいです。
その辺はなんとなく分かってましたがダメもとです。
usermod -aG sudo kurema
cd `dirname $0`
#...
3日目
再び試しました。案の定ダメです。
以前、cronでshutdown
を実行するときrootでもsudo shutdown -r now
のように書かなければならなかったことを思い出し、sudo usermod -aG sudo kurema
のようにしました。
ないだろうなぁ。
sudo usermod -aG sudo kurema
cd `dirname $0`
#...
4日目
ダメです!
意味が分かりません。エラー文が見たいのでファイル出力を設定しました。
明日解決する可能性はないですが、原因は分かるはずです。
これは3日目にまとめてやったかも。
sudo usermod -aG sudo kurema > /home/.../usermod.log 2>&1
cd `dirname $0`
#...
5日目
ファイルを確認してみよう。
あれ、ファイルが存在しません。
シェルスクリプト自体が実行された形跡はあります。
これはおかしい…。
ここでいくつか推測。
- ほぼ同一のシェルスクリプトが他の場所にあるのでそっちを実行してた…?←一行目が
cd `dirname $0`
(シェルスクリプトの場所にcd)なのでそれはないはず - セキュリティ上の理由で、シェルスクリプトは
crontab -e
実行時のものがキャッシュされる仕組みがある?←そんな非直感的な仕様はないはず。調べてもなさそうだった。
違う。
そして思い出しました。
「そういやこれ、フォルダをdockerコンテナにvolumeでマウントして、docker内からシェルスクリプトを実行してる。」
忘れてた。
詰んだ。
これはもう素直にモニターを運んでつなげるしかないのでしょうか。
嫌だなぁ。
ただdocker
はroot権限でファイルは作れるんだよな。
何かできないか?
ファイル作れても仕方ないしなぁ。
そうだ!
/etc/sudoers.d/
をボリュームに追加でファイル作れるじゃん!
これで解決だよ。良かった。
というわけでdocker-compose.yml
(これもkuremaが変更可能)を書き換え、シェルスクリプトも書き換え、寝ました。
version: '3'
services:
nicochcgi:
#...
volumes:
- ./config:/etc/nicochcgi
- /home/share/niconico:/media/niconico
- /etc/sudoers.d:/media/sudoers.d #ここを追加
echo `kurema ALL=(ALL:ALL) ALL` > /media/sudoers.d/kurema
#...
6日目
確認。変化なし。
考えてみるとdocker-compose.yml
を実行中書き換えても反映されないだろうし、コンテナ再起動が必要か。忘れてた。
サーバーごと再起動っと。
$ shutdown -r now
Failed to set wall message, ignoring: Interactive authentication required.
Failed to reboot system via logind: Interactive authentication required.
Failed to open initctl fifo: Permission denied
Failed to talk to init daemon.
そりゃそうだ。
再起動は確か日曜日にスケジュールしてたはずだ。
電源ボタンを押せば手動でできるけど、dockerが起動しなくなったりすると厄介なので待とう。
7日目
(再起動までの数日除く)
ダメ。慣れてきた。
そういえば、ボリューム追加にはあらかじめマウント先のフォルダを作ってないといけないかったような。
とりあえずフォルダを作るか。
mkdir /media/sudoers.d
echo `kurema ALL=(ALL:ALL) ALL` > /media/sudoers.d/kurema
#...
さすがにもう一週間は待てないので電源ボタンを押す。まぁ大丈夫だろう。
8日目
またもダメ。変化なし。
しかしなぜ動かないんだろう。
dockerはroot権限で動いて、作るファイルもroot所有…。
あ!
Ubuntu ServerのdockerはSnappyで動いてる!
Snappyだと/etc
とかには直接触れないんだ!
思い出した…。そんなことあったわ。
うーん。何か手はないか。
…まぁないだろ。
サンドボックス下からsudo権限取れたら話にならんし。
dockerをclassicオプション付きで再インストールできれば良いが、当然sudoが必須だし。
…諦めよう。
9日目
仕方ないのでキーボードとモニターを持って行ってサーバーに繋げました。
shutdown -r now
はなぜかsudo
なしで動きました。直接繋ぐとOKなのかな?
まぁ目の前に電源ボタンがあるからsudo
必須にする意味もないか。
(ちなみに下の作業前にインストールメディアから色々やろうとしたが、LVMのマウントが面倒だったので検索しなおした。)
- 電源投入時Esc連打。
- GRUBメニューが出たらnormalEnterすぐEsc。
-
Advanced options for Ubuntu
選択。 -
Ubuntu, with Linux *.*.*(recovery mode)
選択。2つあったがどっちでも良い。 -
root:Drop to root shell prompt
選択。 -
ls /home
とかでサーバーと同じ環境で普通にマウントされてることを確認。念の為。 -
usermod -aG sudo kurema
。groups kurema
で確認。
終わり。
長かった。
毎日やったのは数行程度の作業だから「最初からこうすれば」ということはなかった。
数日sudo
使えなくても実害はないし。
むしろモニターとキーボードをつないで作業するってのはホントめんどくさい。
というわけで奮闘むなしくシングルユーザーモードでログインして解決しました。
一番避けたかった(再インストールやHDD抜き差しという最悪の事態は回避できたとはいえ)結果に終わったのは残念ではあるけれど。
改めて攻撃者の立場で見てみると、結構やらかしてる点があるというのに気づきました。
最終的にroot奪取はできなかったけど、sudo権限を奪われてもrootでファイル操作は多少できていたし、docker-composeも書き換えられるし。
自分はsudo可能だから大して気にしてなかったけど本来はよろしくないね。
あと念のためレスキュー用ユーザーでも作っておくのも良いかなとも思いました。散らかるのでやらないけど。