侵害されたサーバーを分析して得られた教訓
家に帰ると、携帯電話にLinodeからのメールが届きました。最初は、すでに請求されているのかと思いました。
正直なところ、メールを読んでから最初の2分間は、どう対処すればいいのかわからなかったです。
Linodeの管理パネルを開いてサーバーの状態を確認したところ、CPUの使用率が急上昇していました。
ネットワークのトラフィックも同様の状態でした。
ネットワークログを確認すると、サーバーからの大量のアウトバウンドトラフィックが見られ、Linodeのサポートチケットに記載されていた問題が裏付けられました。
SSHでサーバーにログインして状況を確認しました。
驚いたことに、しばらくの間、パスワードを連続して入力していたわけではありません!
/var/log/secure
を表示するのは避けるべきです。このファイルは連続して表示され、終わりがありません。
head
(またはtail
でも可)を使ってファイルの最初の部分を確認すると、すべてが正常に見えたのですが、非常に短い時間間隔での失敗した試行が続いているのを見て、誰かがroot
ユーザーのログインをブルートフォース攻撃していることを確認しました。
/var/log/secureがいっぱいになっていました。
最初にサーバーをセットアップする際には、root
ログインを無効にし、SSHキーを使用するべきでしたが、翌日に延期してしまいました。私のミスです。
次に、iptables
(またはufw
)を使って、必要なもの以外のすべてのトラフィックをブロックするのが論理的です。その後、すべてのログを確認します。
yum installが失敗
多くのLinuxディストリビューション、例えばUbuntuはデフォルトでufw
を含んでいます。SELinux
を含むcentOS
がufw
を含まないというのはありえないことです。私の推測では、攻撃者がそれを完全に削除した可能性が高いです。
問題ありません。yum install ufw
を試しましたが、パッケージをミラーから取得する際にネットワークのタイムアウトが発生しました。他のパッケージ(strace
、tcpdump
など)でも同様の問題が発生しました。
接続が非常に遅いのですが、私のネットワークの遅延は非常に少ないです。
ufw
が失敗したらiptables
に戻る
ufw
は「Uncomplicated Firewall」の略で、低レベルの複雑さを直接扱わずに済みます。
ufw
を使用して特定のIPアドレスからのすべての着信トラフィックをブロックするのは非常に簡単です。
$ sudo ufw deny from <IPアドレス>
私にはufw
がないので、iptables
に戻ることにしました。
サーバーからのすべてのアウトゴーイングリクエスト/接続を確認
これには$ netstat -nputw
を使用しました。
このコマンドは、UDP (u)
、TCP (t)
、およびRAW (w)
のアウトゴーイング接続をリストします(lやaは使用しない)、数値形式で表示され(nはDNSクエリの長期化を防ぐ)、関連するプログラム(p)も含まれます。
cd
コマンドがネットワーク接続に関与しているとは?
次に、$ ps aux
を実行してすべてのシステムプロセスを確認しました。ここでも問題のプロセスが目立っていました。
プロセスはCPUの95%を占有していました!最後にcoreutils
がこんなにCPUを消費するのを見たのはいつでしょうか?
さらに調査するために、cd
プログラムが開いているファイルを確認しました。
攻撃者は/usr/bin
に悪意のあるプログラムを実行しており、これは攻撃者がサーバーにrootアクセスを持っていたことを意味します。他の方法で/usr/bin
に配置することは考えられませんでした。
もし他に誰かがログインしていると感じる場合は、次のコマンドで確認できます。
$ netstat -nalp | grep ":22"
彼が侵入したかどうか確認するために、次のコマンドを実行しました。
$ cat /var/log/secure* | grep ssh | grep Accept
そして驚くべきことに
この時点で、前述のようにネットワーク経由で yum
を使って何もインストールできないため、strace
や gdb
のようなツールがありませんでした。
ソースからコンパイル?
wget
もどこにも見当たりませんでした!
ただ思いついたのは、プロセスを一度終了させてどうなるかを見ることでした。 $ kill -9 3618
を実行してプロセスを殺し、再び ps aux
をチェックして特定のプログラムを探しましたが、新しいプロセスとして再び現れただけでした。
幻術 3
再びプロセスを終了させてチェックしました。今回はそれを見つけませんでした。
しかし、私が間違っていました。今度は、cd
と同じように CPU を占有する別のプロセスが存在しているようです。
正直なところ、これは私にとって非常にクレイジーなことでした。そして、私はアドレナリンがどんどん出てきました。朝の3時であっても、完全に眠りを失ってしまいました。このクソみたいな状況を朝にやって終わらせるわけにはいきませんでした!
私は ps aux
を二回チェックして、何か不審なものがないか再確認しました。そして今回は、特に終了させるべきものが何も見当たらなかったのです。
安堵?
その後、yum
を使ってパッケージのインストールを試みましたが、相変わらずネットワークタイムアウトでした。
なぜ bash history
をチェックしなかったのか疑問に思うかもしれません。信じてください、クリーンでした!私が入力したものしか見えませんでした。何であれ、賢いものでした。しかし、これが基本的なことだと思いますが、何も残さないのです。
nmap で全てを調べる
なぜなら、そうするだけです!
サーバー上で簡単なスキャンを実行しました
$ sudo nmap ovirtlinode.gsoc.orgStarting Nmap 7.40 ( https://nmap.org ) at 2017-05-25 14:35 IST Nmap scan report for ovirtlinode.gsoc.org Host is up (0.035s latency). Not shown: 978 filtered ports PORT STATE SERVICE 22/tcp open ssh 25/tcp closed smtp 80/tcp open http 113/tcp closed ident 179/tcp closed bgp 443/tcp open https 1723/tcp closed pptp 2000/tcp closed cisco-sccp 2222/tcp open EtherNetIP-1 5432/tcp open postgresql 6000/tcp closed X11 6001/tcp closed X11:1 6002/tcp closed X11:2 6003/tcp closed X11:3 6004/tcp closed X11:4 6005/tcp closed X11:5 6006/tcp closed X11:6 6007/tcp closed X11:7 6009/tcp closed X11:9 6025/tcp closed x11 6059/tcp closed X11:59 6100/tcp open synchronet-db
UDP 接続をチェック
$ sudo nmap -sS -sU -T4 -A -v ovirtlinode.gsoc.org Starting Nmap 7.40 ( https://nmap.org ) at 2017-05-25 14:37 IST NSE: Loaded 143 scripts for scanning. NSE: Script Pre-scanning. Initiating NSE at 14:37 Completed NSE at 14:37, 0.00s elapsed Initiating NSE at 14:37 Completed NSE at 14:37, 0.00s elapsed Initiating Ping Scan at 14:37 Scanning ovirtlinode.gsoc.org (172.104.36.181) [4 ports] Completed Ping Scan at 14:37, 0.01s elapsed (1 total hosts) Initiating SYN Stealth Scan at 14:37 Scanning ovirtlinode.gsoc.org (172.104.36.181) [1000 ports] Discovered open port 80/tcp on 172.104.36.181 Discovered open port 443/tcp on 172.104.36.181 Discovered open port 22/tcp on 172.104.36.181 Discovered open port 6100/tcp on 172.104.36.181 Discovered open port 5432/tcp on 172.104.36.181 Discovered open port 2222/tcp on 172.104.36.181 Completed SYN Stealth Scan at 14:37, 4.22s elapsed (1000 total ports) Initiating UDP Scan at 14:37 Scanning ovirtlinode.gsoc.org (172.104.36.181) [1000 ports] Completed UDP Scan at 14:37, 4.19s elapsed (1000 total ports) Initiating Service scan at 14:37
あまり多くの情報は得られませんでした。
これで、攻撃者によって設置された攻撃ベクターが休止状態になるのを見た瞬間です。もう一度、特に注意を引くような活動は見られませんでした。
サーバーを一晩放置しました(愚かな決断でしたが、単に好奇心が勝ってしまいました)次の朝に状態を確認しました。
結果として、ネットワーク上でのアウトバウンドコールがまだかなりの量で行われていることがわかりました。
CPU グラフは同様でした
その後、サーバーをしばらくの間停止させました。この間にCPUグラフが以下のようになりました。
その後、アウトバウンドネットワークコールはありませんでした。
余波
サーバーを完全に停止させました。再度使用することはありません。イメージを再構築するつもりです。
サーバーには私の公開鍵が含まれていました。これはすぐに心配することではありません。公開鍵から秘密鍵を取得するのは非常に難しいからです。これは公開鍵暗号の仕組みです。(「非常に」とは、政府の努力でも難しいという意味です。NSA が破れない限り、普通の人にとっては非常に安全です)
しかし、念のため、SSH 鍵を再生成し、使用されていた場所で古い鍵を削除し、新しい鍵に更新しました。
念のため、古い SSH 鍵を使用していたサービスのアクティビティログを確認しました。異常なアクティビティはありませんでした。
学び
- ルートパスワードログインを無効にする
サーバーをプロビジョニングした後、最初にこれを行うべきでした。これにより、攻撃者がルートとしてログインして混乱を引き起こすのを防ぐことができます。
sshd
が使用するポートを隠す
デフォルトの 22
ではなく、一般的でないポートに変更することが重要です。攻撃者もあなたもこのポート番号を知っている可能性があります。
しかし、セキュリティの隠蔽が安全性を確保するとは考えないでください。
セキュリティの隠蔽は初心者の失敗です!秘密を保持し、悪用を難しくするのと、秘密に依存して安全性を確保するのは別物です。金融機関が長年それを行っていましたが、効果がないことを学びました。
自分自身の方法を考案するよりも、良い実践、プロトコル、技術を使用する方が良いです。逆向きエンジニアリングは、スペースロケットからスマートトースターまで行われています。OS バージョンやライブラリを特定するのは通常 30 分もかかりません。例えば、PING RTT を見て OS を特定することができます。
結局のところ、ベストプラクティスを使用することに対して誰も責められることはありません。しかし、システムを出し抜こうとすると、すべてが自分のせいになります。
- fail2ban で SSH を保護する
Fail2ban は、設定された回数以上のログイン試行があった場合に自動的に iptables ファイアウォール設定を変更するルールを作成することで、この問題を軽減できます。これにより、あなたの介入なしにサーバーが不正なアクセス試行に対応できます。
- パスワードログインではなく、公開鍵を使って SSH することを推奨します。
- ソース IP アドレスによって SSH アクセスを制限します。もし限られた IP からのみ接続するのであれば、ポート 22 へのアクセスをそれらの IP のみで制限することができます。ほとんどの VPS プロバイダーは、これを自分のウェブサイトを通じて許可します(エッジルーターなどにプッシュされます)。
- 私は非常に簡単に推測できる辞書ベースのパスワードを使用していました。これを認めざるを得ません。これは単に最も愚かなことの一つです。そして、はい、私はそれをしました。私の唯一の理由は、それが使い捨てサーバーだったからですが、それがセキュリティプラクティスに従わない言い訳にはなりません。 したがって、強力なパスワードを維持してください!サーバーに対するブルートフォース攻撃があったとしても、強力なパスワードを使用していれば、パスワードを解読するのは相対的に非常に難しいです。
ブルースが このエッセイ について書いています。彼の言っていることを繰り返すことはしませんので、読んでみてください。
研究によれば、大文字/数字/記号などのパスワード複雑性要件を追加すると、ユーザーは予測しやすい変更を行い、全体的に簡単なパスワードを作成することが多いです。覚えにくくなるからです。
また、OWASP のブログ も読んでください。
セキュリティ交換 でのディスカッションもあります。
- サーバーの定期的なバックアップ/スナップショットを取る。そうすれば、何かおかしなことが起こった場合でも、以前の状態に戻すことができます。
- 一部のファイルは共通の攻撃ポイントにあります:
$ ls /tmp -la$ ls /var/tmp -la$ ls /dev/shm -la
これらをチェックして、そこに存在すべきでないものがないか確認してください。
残念ながら、その時点でサーバーを再起動してしまったため、この情報を失いました。
- 重要なシステムファイル(
ls
,ps
,netstat
,md5sum
など)のクリーンなコピーをどこかに保存し、それらの MD5 サムを保存し、ライブバージョンと定期的に比較します。ルートキットはこれらのファイルを改変することが多いです。オリジナルが改ざんされていると疑われる場合は、これらのコピーを使用してください。 aide
またはtripwire
を使用してファイルの変更を確認します(データベースが改ざんされていない限り)。また、syslog を設定して、ログファイルを遠隔のログサーバーに送信し、侵入者によって改ざんされないようにします。これらのリモートログファイルを監視して、不審な活動を確認します。- 定期的にログを確認します —
logwatch
やlogcheck
を使用して重要な情報を統合します。 - サーバーの状態を把握しておきます。どのような活動やログが正常かを理解します。
chkrootkit
のようなツールを使用して、定期的にルートキットをチェックします。
締めくくり
Linux サーバーがハッキングされているかどうかはどうやって知るのか?
わからないのです!
はい、その通りです — しかし、それが悲しい現実です。もちろん、多くの手がかりはありますが、もしシステムが特定のターゲットとして狙われていた場合、正確に知るのは不可能かもしれません。完全に安全であることは決してありません。
もしシステムが侵害された場合、つまり誰かがあなたのホスト上でルート権限を持っている場合、あなたが見るすべてのものを信頼できません。より明白な方法で、ps
, ls
などを改ざんするだけでなく、カーネルレベルのシステムコールを攻撃して IO 自体を支配することもできます。ターミナルが伝えることは何も信頼できません、完全にです。