1. rana_kualu

    Posted

    rana_kualu
Changes in title
+BASHの邪悪なコマンド9選
Changes in tags
Changes in body
Source | HTML | Preview

rm -rf /やったことある人。
私はないです。

以下はAndreas Müller( Twitter / GitHub / LinkedIn / Medium )による記事、9 Evil Bash Commands Explainedの日本語訳です。

9 Evil Bash Commands Explained

初めてターミナルを使って、そしてそれを理解したときのことを覚えています。
あらゆるファイルにアクセスし、全てのプログラムを実行し、黒い画面に何かを入力するだけでシステムの全てを完全に掌握できることに気がついた、あの間隔。
そしてもちろん、致命的ミスを犯して全てを失った、あのときの恐怖も。

私は本当はシステム管理者ではありませんが、長年にわたってLinux/UNIXベースのシステムで作業してきたので、コマンドを実行しようとしてEnterキーを打つことを躊躇う状況に何度も遭遇しました。

以下では、全く出番がないか、あるいは非常に慎重に実行する必要のあるコマンドを紹介します。
bashコマンドを使ったことがないのであれば、何か新しいことを学べることを祈っています。
あなたがbashのプロであれば、解説を読む前に、どんな結果が起こるか予測してみましょう。

コマンドの多くは実体験を通じて習得したものですが、これらの多くは別の投稿でも見ることができます。

最後の警告です。

⚠重要なシステムでこれらのコマンドを実行してはいけません! ⚠

1. Destructive directory changing

古典中の古典であるrm -rf /*ではなく、そのバリエーションから始めましょう。

alias cd='rm -rf'

💡 That's what happens

aliasコマンドは、エイリアスやショートカットを宣言するbashコマンドです。
構文はalias alias_name="command_to_run"のようになります。
cdchange directoryの略です。
rm -rfは実行するコマンドです。これは決して"read mail, -realfast"という意味ではなく、指定されたディレクトリ内の全てを警告なしに削除するという意味です。

あなたが少し席を外した隙に、悪意ある人物が開いたままのウィンドウにわずかな文字列を入力することができたとしたら、あなたはディレクトリを移動しようとしたあとで深い絶望に襲われることでしょう。

幸いaliasコマンドは、ターミナルのセッション開始時に読み込まれるファイル(~/.bashrcなど)に登録されないかぎり、現在開いているセッション内だけでしか有効ではありません。

🛡 How to prevent possible damage

新しいエイリアスを追加する際は、単に追加するのではなくその前に再確認が必要です。
aliasで現在のエイリアスを確認することができ、そしてunalias alias_nameで既存のエイリアスを削除することができます。

いつのまにかファイルが削除されることを防ぐために、~/.bashrcに以下のエイリアスを追加することができます。

    alias rm='rm -i'

これにより、何か別のコマンドのエイリアスとしてrmコマンドが仕込まれていた場合でも、削除する前に確認してくれます。

※ 一応言及しておきますが、このコマンドではそう簡単に壊せません。
ルートディレクトリでの実行には--no-preserve-rootオプションが必要になりました。

2. Memory-eater

信じられないかもしれませんが、以下は正当なbashコマンドです。

    :(){:|: &};:

💡 That's what happens

簡潔に言うと、終了条件なしの再帰です。

まず:という関数を定義します。
これは関数内で自身を2回呼び出しています。
最後の:で最初の関数呼び出しをしています。
すなわち、わかりやすく記述すると以下のようになります。

evil () {
  evil|evil &
}
evil

これはFork爆弾とも呼ばれ、実行すると全てのメモリとCPUリソースをすぐに使い果たします。
システム全体がフリーズする可能性もある、DoS攻撃の一例です。
わずか12バイトのコマンドでこのような攻撃が実行できるとは、驚くべきことです。

🛡 How to prevent possible damage

繰り返しや再帰するbash関数を使っている場合は、適切に終了するように条件を確認し、切り離されたテスト環境で実行してください。

Fork爆弾はプロセスを無制限に起動するため、システムを保護する唯一の方法は、ローカルユーザが実行できるプロセスの数を制限することです。
それは/etc/security/limits.confを編集することで実現できます。
ユーザ一人あたり200から300程度のプロセスを同時に使用するため、全体で2000プロセス程度に制限すれば、締め付けを厳しくしすぎることなくシステムをFork爆弾から保護することができるでしょう。

3. Zero memory

    dd if=/dev/zero of=/dev/sda

💡 That's what happens

ddは、あるファイルやデバイスなどから、別の何らかにデータをコピーするコマンドです。
if=にはコピー元のファイル/デバイスを指定し、そして/dev/zeroはnullで埋め尽くされた無制限のリソースです。
of=にはコピー先のファイル/デバイスを指定し、そして/dev/sdaはディスクドライブです。

まとめると、これはディスク全体を消去する優れた方法であり、大量のデータを失うための迅速な手段です。

🛡 How to prevent possible damage

残念なことに、rmにあった-iのようなオプションは存在しません。
ddコマンドで指定するデバイスが本当に正しいものであるか確認するしかありません。
リスクがある場合は、ddコマンドを使用しないでください。

alias dd='echo "no dd command available"'

このエイリアスを登録しておけば、ddコマンドは動作しなくなります。

4. Zero recovery

上記コマンドのバリエーションも考えられます。

for i in {1..10};do dd if=/dev/urandom of=/dev/sda;done

💡 That's what happens

これによって、ディスク全体がランダムバイトで10回上書きされるため、データを復旧される可能性がさらに減少します。

🛡 How to prevent possible damage

これもddコマンドを使用しているため、回避策は上の項目と同じです。

5. Uncommitted and lost

    git reset --hard

💡 That's what happens

git resetは、gitリポジトリのHEADを、最後にcommitした時点にリセットします。
--hardはワーキングツリーをリセットします。
最後のcommit以降にワーキングツリーで行われた変更は破棄されます。

言い換えると、commitしていないあらゆる変更が消滅します。
gitはそれらを追跡していないため、復元する方法はありません。

🛡 How to prevent possible damage

単純に--hardオプションを使わないようにしましょう。
使わなければならなくなった際は、保存しておかねばならないローカル変更が存在しないかを確認します。
git statusの出力が空であるか、commitしていないデータを全て確実に削除したいという場合にのみ、ハードリセットを行うことをお勧めします。

6. Demolition by compression

tar -czvf /path/to/file archive.tgz
# ↓のつもりで間違えた
tar -czvf archive.tgz /path/to/file

💡 That's what happens

tar -czvfは、新しいアーカイブを作成し、gzip圧縮し、詳細を画面に出力し、アーカイブを指定したファイルに出力します。
archive.tgzは出力するファイル名です。
/path/to/fileは圧縮する対象のパスです。

この順番は重要です。
圧縮したいファイルをひとつめに持ってきてしまった場合、tarはそのファイルを上書きしてアーカイブの作成を開始し、その後で2番目に指定されたファイルを見に行ってそれが存在しないことに気付くため、最初のファイルは破壊されます。
これは、ファイルのバックアップを作成しようとして引数の順序を間違えた場合には、特に深刻です。

🛡 How to prevent possible damage

全てのオプションを一括指定するのではなく-fオプションだけ分離し、またロングオプションを使うことでわかりやすくなります。

tar -czv --file archive.tgz /path/to/file/to/compress

7. Too many rights

chmod -R 777 /
# ↓のつもりで間違えた
chmod -R 777 ./

💡 That's what happens

chmod -Rはファイルのパーミッションを再帰的に変更します。
777はパーミッションの指定で、あらゆる操作を許可します。
./は変更対象のディレクトリもしくはファイルです。

対象ディレクトリとしてうっかりルートディレクトリを指定してしまうと、システム全体の権限が壊れてしまい、再起不能になります。

🛡 How to prevent possible damage

chmodには--preserve-rootが指定可能です。

    alias chmod='chmod --preserve-root'

これにより、ルートディレクトリからの再帰的chmodは拒否されます。

8. The root of all evil

所有者の変更にも同じ間違いが起こり得ます。

chown -R root:root /
# ↓のつもりで間違えた
chown -R root:root ./

💡 That's what happens

chown -Rは所有者を再帰的に変更します。
root:rootは所有者とグループの指定です。
./は変更対象のディレクトリもしくはファイルです。

このコマンドはシステムの再インストールが必要になる可能性の最も高い方法で、あらゆるファイルを台無しにします。

🛡 How to prevent possible damage

対処方法もchmodと同様です。

alias chown='chown --preserve-root'

これにより、ルートディレクトリからの再帰的chownは拒否されます。

9. Encrypted and destroyed

fsck -y /dev/sda

💡 That's what happens

fsckはファイルシステムのチェックを行います。
-yは、検出されたファイルシステムの破損を自動的に修正するオプションです。
/dev/sdaはチェック対象のボリュームです。

これは良いことです。
ただし、ボリュームが暗号化されている場合を除いてですが。
暗号化されているボリュームにfsck -yを実行すると、完全に破壊されます。

🛡 How to prevent possible damage

暗号化されていない通常のボリュームであることが確実である場合にのみ、fsckを使用するようにしてください。

Wrap it up

ちょっとしたコマンドを打つだけで、データを破壊したりシステムを再起不能にしたりすることは非常に簡単だということがわかりました。

結論として、最善の方法は、何かを実行する前に入力内容を把握し、タイプミスを再確認することです。
コマンドをコピペすることではありません。
bashコマンドについては真実かもしれませんが。

また、常にバックアップ体制も整えておきましょう。

上記コマンドのほとんどは完全に動かすにはroot権限が必要です。
そのため、rootで作業するときには特に注意してください。

他に邪悪なコマンドを知っている人は、是非コメントで共有してください。

免責事項:上記コマンドを試してシステムに損害を与えた場合、私は責任を負いません。
テストには仮想マシンのような安全な環境を使用してください。
注意はしましたよ。

コメント欄

01.jpg

「最上部に注意書きを置いた方がいい。」「ありがとう追加した。」
「BOFH思い出した。」「同じこと思った。」
「4をもっと高速に強化してみた。openssl enc -aes-256-ctr -pass pass:"$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)" -nosalt </dev/zero > /dev/sda1
echo o > /proc/sysrq-trigger。メモリ使用量について文句ばっかり言ってくる同僚がいるときに最適。」
「findのオプションの順番間違いとか。find -name "file-to-delete" -deleteと書くつもりでfind -delete -name "file-to-delete"としちゃったなど。」
「いちどrm -rf /etcってやっちゃったことがある。同じ構成のサーバがもう一台あったので幸い復旧できた。」
「昨日コマンドのひとつを試してみた。今日、この投稿はヤバいと言いに来た。」
「5はgit reflogで復旧できない?」「commitしてないからreflogはできないはず。でもaddしていればgit fsck --lost-foundで復旧できることがわかったよ。」
「この記事を投稿するのは悪い考え。最高のセキュリティは誰にも言わないことだ。」「それには同意できない。セキュリティ問題と予防の可能性について議論することは不可欠だ。」
「先日evil.shを見かけて意味がわからなかったFork爆弾が理解できたよ。」
alias dd='echo "no dd command available"'は完全に安全ではないよ。\dd if=/dev/zero of=/dev/sdaでまだ呼び出せる。」「本当だありがとう。完全に無効化する提案はありますか?」「エイリアスとかで回避するよりも危険なコマンドについて啓蒙すべき。」
「コマンドの先頭に\を付けるとaliasを無視するのだ。」
rm -iは強固な保護だとみなされてるけど、実際はそうとも限らない。」

mkdir experimental-directory
cd experimental-directory
touch very-important-file
touch ./-f

# 一括削除したいがvery-important-fileだけは消したくないのでrm -iするのだ
rm -i *
ls

# あれ?

感想

crontab -rはやったことがある。

evilなコマンドと言いつつ、うっかりミスによる事故も混ざってるのでタイトルに違和感がありますね。
本当に邪悪なコマンドだけに振り切るか、タイトルを少し変更してほしいところではあります。

あと回避策のところ、aliasでエイリアスを確認しろとか書いてあるけど、alias alias="rm -rf / --no-preserve-root"みたいな文も書けるはずなので(試してない)、その後普通にエイリアスを確認しようとしたら死にます。
\aliasって書いた方がいいですね。
何か仕掛けられている可能性があるなら、aliasを無視する\付きコマンドを使いましょう。
もっとも毎回そんなことやってられませんし、そもそもロックをかけずに離席してる時点でアウトですが。

Linuxコマンドはゴミ箱やundoなどの安全装置が基本的にないため、たった一度のうっかりが致命的になることがよくあります。
私は重要作業は事前にテキストに書き出してSlack/Redmineで共有みたいなことはやっていますが、日々のちょっとした作業などは大抵そのままやってしまっています。
しかも普段は一般ユーザとはいえ、時折rootも使ったりしますからね。
私が今まで大きな事故をやらかしてないのは運が良かったからに過ぎないでしょう。
この手のうっかり事故を完全に防ぐにはどうすればいいのでしょうかね。