晴耕雨読

working in the fields on fine days and reading books on rainy days

Hardening 2021 Active Fault 参加記

2021年11月17-20日と27日にHardening Projectというセキュリティの攻撃からシステムを堅牢化する競技会にTeam8として参加しました。 Hardening本大会は初参加でした (Micro Hardeningには過去3回参加)。 個人的な目標であった「SELinuxの導入と運用」をするまでの経緯とか苦労した点を書いていきたいと思います。

SELinux以外のことは他の参加者が書いてくれると思うので、ここではSELinux関連のことしか書きませんが悪しからず。

参加経緯

最近は Hack The Box などのペネトレーションテストができるプラットフォームが増えてきました。 これらのコンテンツを使ってペネトレーションテストの勉強をしつつ、Web経由で実際にリバースシェルを立てて侵入成功して権限昇格できれば勝ち、という遊びをしていました。 ある日、Webの脆弱性を試せる環境をOVAファイルで拾ったので、これでペネトレーションテストをしていました。 OSコマンドインジェクションかRCEで適当なコマンド (id や cat /etc/passwd など) を実行するところまでは成功したのですが、curlやpythonなどの権限昇格する上で必要なコマンドが使えず、おかしいおかしいと嘆きながら出会ったのがSELinux (とAppArmor) でした。 SELinuxの下では apache ユーザは curl でネットワーク通信する権限も、python でスクリプトを実行する権限もなかったのです。 今までSELinuxについて真面目に勉強してこなかったのですが、今の自分ならSELinuxが本当にすごい仕組みであることを広く共有できるのではないか、と胸が高鳴りました。

ちょうどその頃、Hardeningが開催されることを知りました。参加したいけど平日の昼間で業務と被らないか心配だな〜という気持ちを職場の上位者に伝えたら、話が進んで、業務の予定などについて何も心配することなくHardeningに参加できるようになりました。 HardeningではCentOSサーバもあるので、運用を考慮したSELinuxの導入の技術検証ができればいいな、という思いで応募フォームを記入し提出をしました。

事前準備

SELinuxについて勉強できる本やサイトは限られています。 SELinuxが本当にすごい仕組みであるという事実は、世間に広く受け入れられていないからです。 その中でもSELinuxを勉強したい、という人のために、私自身が役に立った本やサイトのリンクを以下に紹介します。

  • とほほのSELinux入門 - とほほのWWW入門
    • みんな大好き「とほほの〇〇入門」シリーズです。初心者向けに内容を選んで書かれているので読みやすいです。初めてSELinuxを試してみたい人は、ここから入門すると良いと思います。
  • SELinux の使用 | Red Hat Enterprise Linux 8
    • RHEL 8 向けの文書で、SELinuxについてより詳細な情報が書かれています。SELinuxユーザやSELinux関連のトラブルシューティングの方法について書かれています。SELinux関連コマンドについて練習をしたい中級者向けといったところでしょう。
  • SELinux ユーザーおよび管理者のガイド | Red Hat Enterprise Linux 7
    • RHEL 7 向けの文書ですが、上記の 8 よりも各サービス(Apache, Samba, NFS, BIND, MariaDB/MySQL, PostgreSQL, postfix など)とSELinuxとの相互関係についての情報が書かれています。特に、各サービスのブール値はよく使用するものが書かれているので、サービスと組み合わせてSELinuxを使用する場合は必見です。
  • 『CentOS 8で作るネットワークサーバ構築ガイド』- 秀和システム
    • SELinuxについて日本語で書かれている数少ない技術書です。加えて、restorecondのような定期的にファイルコンテキストを確認して、修正を検知して修復を行う仕組みについても触れられており、競技中には活かせないものの、非常に勉強になります。 Amazonで調べてもSELinuxの技術書が見つからない!という方はまずこちらの本をおすすめします。
  • CIS Benchmarks
    • CIS Benchmarksとはシステムを安全に構成するためのベストプラクティス集みたいなものです。この中の CentOS 6 と CentOS 7 の「1.6.1 Configure SELinux」の項に、ブートローダの設定からSELinuxの有効化について書かれてあります。カーネルパラメータとSELinuxの関係はこの文書がわかりやすいと思います。

事前期間はVirtualBoxやHyper-VにCentOSを入れて、技術検証という名の勉強をしていました。

Activation

11/17(水),18(木)はMPの選定と競技資料の読み込みでした。 事前にチームメンバーには、競技環境のサーバに CentOS があれば SELinux を導入します、と伝えておきました。 SELinux有効化にはサーバ再起動が必要なので、チームメンバに声かけしてから再起動します、とも伝えておきました。 事前資料をもらったときに、CentOS の文字があって心の中で「よし!」と叫んでいました。

Hardening Day

11/19(金)はハードニング当日でした。 ネットワークとFirewall周りはチームメンバーが担当してくれたので、私はSELinuxの作業に集中することができました。 パスワード変更の作業を終えた後に、以下の流れでSELinuxの有効化をShopが稼働しているサーバ3から進めていました。

  1. 事前に用意したブートローダのカーネルパラメータを確認するコマンドを実行
  2. 事前に用意した/etc/selinux/configの設定をdisabledからpermissiveに書き換えるコマンドを実行
  3. ss -tualpn コマンドで開いているポート一覧を確認(再起動後にサービスが停止する可能性を考慮)
  4. チームに連絡してから reboot コマンドで再起動
  5. 踏み台サーバからpingを叩いて起動するまで待機
  6. setenforce 1 でSELinux有効化
  7. 監査ログ (audit.log) を眺めて、DB接続やメール送信に問題があれば、拒否ルールを修正

監査ログをサーバ2〜9で監視して運用に問題がないか確認しながら進めていました。 SELinuxによるアクセス拒否時に許可ルールを追加する基準は、同じ拒否ログが一定間隔で出力され続けるときか、チームメンバがWebの管理画面から操作したときにエラーの報告を受けたとき、だけとしていました。

競技中のファインプレー

他のチームがランサムの攻撃を受けている間、WAFもなく脆弱性修正もしていないTeam8でしたが、何事もなくショップが正常稼働しており、JPCERT/CCから共有された情報をもとに当該サーバの対象ディレクトリを調べても何も出てこなかったので、SELinuxくんが守ってくれた?!という感じでした。競技終了後のFault Analysis DayでCiscoさんから「他のチームはランサムのスクリプトを攻撃者サーバから取得する通信が発生していたけど、Team8はその通信がなかった」という報告を受けて、RCEによるcurlかwgetの通信をSELinuxが防いでくれたのだと信じています。 SELinuxは裏切らない!と思った瞬間でした。

2021/12/12 追加:後日、もくもく会(mokumokuHardening)の中でCiscoのMP担当してくれた方とのログ調査のやりとりの中で、ランサムウェアの攻撃を受ける1分前に Docker の Remote API である 2375/tcp にアクセスがあったので、これがランサムの原因であると結論付けられました。 私たちの Team8 ではFWはデフォルト拒否の方向で設定をお願いしていたために、ランサムを防ぐことができたようです。 このままでは SELinux が何もしていないように見えてしまうので、SELinux が防いだ攻撃の一覧を Hardening Projectで記録されたSELinuxによる拒否ログの一覧 にまとめましたので、よければご覧ください。

想定内のトラブル

SELinux有効化後はDBが別サーバにあるので、DB接続の通信時にSELinuxの拒否が発生することは想定済みでした。 想定済みだったのですぐにルールを修正することができました。 あとは、メール送信権限については拒否にするか許可にするか迷いましたが、ショップを稼働しているサーバでメール関連のSELinuxのアクセス拒否が発生した場合は、許可ルールを追加するようにしました。

Webの管理画面からファイルをアップロードする際に、SELinuxでアクセス拒否されたので、チームメンバが画像ファイルをアップロードするほんの20秒程度だけ、SELinuxを無効化して対応していました。 本来であれば、アップロード先ディレクトリのSELinuxコンテキストを「httpd_sys_content_t」から「httpd_sys_rw_content_t」にラベルを付け替える作業をしないといけないのですが、商品画像3枚のアップロード(1回きり)のために時間をかけることではないので、一瞬だけSELinuxを無効化する対応となりました。

想定外のインシデント

SELinuxのルールなどを修正するsemanageコマンドが使えなかったのは、想定外でした。 幸いにも audit2allow コマンドは使えたので良かったです。 今思えば、semanageもaudit2allowも同じpolicycoreutils-pythonパッケージの中のコマンドなのに、片方だけ使えないのは不思議な気がしますが…、なんだったのだろうか。

競技中、SELinuxを有効化したまま放置していた新卒採用ページのsrv07と内部向けDNSサーバであるsrv02がsshログインできなくなりました。 srv07に関しては最後に繋いでいたsshセッションも切られてしまったので、原因調査ができませんでした。

sshログインできないsrv02に関してはsshセッションが残っていたので、原因を調査したところ、user1〜9以外にuser10,11という想定外のアカウントが存在しており、パスワード変更の作業が漏れてしまい、攻撃者の侵入を許してしまいました。 そして、別端末からsrv02にsshログインを試みると、原因不明でしたがSELinuxがsshログインを拒否していました。 競技のレギュレーションである「hardeningアカウントでログインできること」を守るために、やむを得ず、終了5分前にsrv02のSELinuxを無効化し、sshログインができることを確認した後、競技が終了しました。

Fault Analysis

競技終了後、SELinuxによるSSHログイン拒否の原因を調べるために、手元にあるわずかなログから、一人反省会という名のログ考察をしました。 結論だけ述べると、srv02はsshdが攻撃者の用意したsshdに切り替わっていた (sshdサービスが改竄されていた) 可能性が高いです。

競技中、srv02にSSHログインできない問題が発生しており、それを解決するために私が繋いでいた最後のsshセッションで監査ログを確認しながら、別端末でsrv02にsshログインを試みた際の拒否ログが以下のものでした。

[root@srv02 ~]# tail -f /var/log/audit/audit.log | grep denied
type=AVC msg=audit(1637308627.855:412): avc:  denied  { dyntransition } for  pid=14774 comm="sshd" scontext=system_u:system_r:kernel_t:s0 tcontext=system_u:system_r:sshd_net_t:s0 tclass=process permissive=0
type=USER_AVC msg=audit(1637308658.268:422): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:kernel_t:s0 msg='avc:  denied  { start } for auid=n/a uid=0 gid=0 cmdline="/usr/lib/systemd/systemd-logind" scontext=system_u:system_r:kernel_t:s0 tcontext=system_u:system_r:kernel_t:s0 tclass=service  exe="/usr/lib/systemd/systemd" sauid=0 hostname=? addr=? terminal=?'
type=AVC msg=audit(1637308658.273:428): avc:  denied  { dyntransition } for  pid=16916 comm="sshd" scontext=system_u:system_r:kernel_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0 tclass=process permissive=0
type=AVC msg=audit(1637308658.321:432): avc:  denied  { transition } for  pid=16922 comm="sshd" path="/usr/bin/bash" dev="vda3" ino=100664377 scontext=system_u:system_r:kernel_t:s0 tcontext=unconfined_u:unconfined_r:unconfined_t:s0 tclass=process permissive=0

推測ですが、上記のエラーの内容は以下の意味を持つと考えています。

  1. sshdコマンドによるプロセス生成がルールに一致せずSELinuxで拒否
  2. systemdコマンドがsystemd-logindファイルを使ったサービス起動をSELinuxが拒否
  3. sshdコマンドによるbashプロセスの生成がドメイン遷移ルールに一致せずSELinuxで拒否

エラー内容を確認してみると、いくつかおかしい点がありました。 一般的に、sshdはSELinuxの「sshd_t」ドメインで起動されるのですが、上記の拒否ログでは「kernel_t」ドメインしか出てきません。 さらにログに注目すると以下のことに気づきました。

  • sshでログインするときのシェルが /usr/bin/bash になっており、ユーザが追加したbashを起動しようとしている(通常は /bin/bash のようなシステムのものを使用する)

この点から、侵害されたsrv02では攻撃者が用意したsshdが起動していたと考えられます。 攻撃者は、バックドアとして機能するsshdサービスを侵入先に構築して、何も知らずにログインしてきたユーザから入力パスワードなどの機密情報を抜き出そうとしたか、または内部経由で攻撃するための踏み台サーバとして利用しようとしていたのかもしれません。 ただ、srv02は攻撃者の用意したsshdがSELinuxによって期待通りに機能しなかった可能性が高いです。

ここまでの流れをまとめると、時系列は以下のようになります。

  1. user10, 11 から攻撃者が侵入し、攻撃者が用意したsshdサービスが起動した
  2. sshdがログインシェルとして /usr/bin/bash を起動しようとしたが、SELinuxがドメイン遷移ルールに一致しないことを検知してアクセス拒否した
  3. そして誰もsshログインできなくなった

管理者権限に昇格できるユーザでSELinuxを無効化されなかったことは不幸中の幸いでした。 ただ、基本的なログイン可能アカウントチェックが出来ていなかったのは反省点です。 次回はSSHログイン可能アカウントを一覧で表示するスクリプトを準備してから挑みたいと思います。

Softening Day

最終発表日、Team8の発表でランサムウェアをSELinuxで防ぐことができた点を発表してくれました。

SELinuxでランサムウェアを防ぐことができたの図

そのとき、Discord上ではSELinuxが絶賛されていました。 好評だったので嬉しかったです。

  • 「すごい!SELinux!」
  • 「SELinuxを使いこなしている」
  • 「SELinux有効化!すごい!(有効化すると、むしろ動かないサービスが多そうだから、使うのはためらう)」
  • 「SELinuxすごい!」
  • 「SELinuxが使えるとはうらやましい」
  • 「あの土壇場でSELinuxを入れる判断はすごい」
  • 「SELinuxやるのは英断 やり切るのは素晴らしい」
  • 「質問:SELinuxを有効にすると想定以上に動かなくなるものがあると思いますが、SELinuxのチューニングはどういうポリシーでやったのですか?」
  • 「SELinux はファインプレー判定。」

下から2番目の質問に関しては、繰り返しになりますが、SELinuxのルールチューニングのポリシーは、同じ拒否ログが一定間隔で出力され続けるときか、チームメンバがWeb上の管理画面から操作したときにエラーの報告を受けたとき、だけとしていました。

Team8(チーム名:グラフェンジャー)の発表はイエローレンジャーによるステージ上での変身もあり、オンラインで発表の中継を聞きながら一人で爆笑していました。 私もチームの一員であるブルーレンジャーとして技術面でチームに貢献できたことを誇りに思います。 Team8のメンバーとして参加できて良かった、と心から思いました。

見込み販売力(全体成績)の順位としてTeam8は4位 (全11チーム中) でしたが、神戸デジタル・ラボ様のスポンサー賞を頂くことができました! Team8の取り組みが神戸デジタル・ラボ様の企業理念「前進・探求・共創」に当てはまってたことが評価されたようです。 以下Team8の詳細な成績です。

  • 見込み販売力:158,760,384 (4位)
  • 技術点:4300 (2位)
  • 顧客点:2000
  • 対応点:5200
  • 経済点:6345 (3位)
  • 協調点:5850 (1位)
  • 購読点:2876

SELinuxの取り組みはファインプレー判定で加点対象となったらしいので、頑張って良かったです。

終わりに

環境を用意してくれた運営とSELinuxの作業に集中させてくれたチームメンバーに感謝しています! SELinuxの技術検証は成功し、SELinuxが本当にすごい仕組みであることを共有できたので満足です。

最後にTeam8 グラフェンジャーの参加証明書を載せて、参加記を閉めたいと思います。 関係者の皆様、ありがとうございました。

Team8 グラフェンジャーの参加証明書

以上です。

参考文献