こんにちは、プラットフォーム技術部の佐藤です。

以前『【CVE-2017-5638 / S2-045】SELinuxポリシーのバグフィックスでTomcatアプリのRCEは防げるようになったのか』で、記事を書かせていただきました。

そのときは「リモートコード実行(RCE)を防げないかなー、防ぎたいなー」という目的に対してはあまり期待した結果には至らなかったですが、それでも SELinux 無効状態よりは防御力はあがる、ということを確認できたと思っています。

今回は SELinux の tomcat 用デフォルトポリシーをカストマイズして、更なる防御力アップを目指したいと思います。

今回の目標

RCE 脆弱性を突いて悪用されそうなものは /sbin, /usr/sbin, /bin, /usr/bin に配備されているコマンド群です。これらのパスに含まれるコマンドの多くは、タイプが shell_exec_t や bin_t となっています。これらの実行権限を tomcat から剥奪することで RCE 悪用被害を軽減します。 実は tomcat 自体を起動するための処理に必要なコマンドもあるので、単純に剥奪しただけでは宜しくないのですが、それらへの対処についても実施していきます。

tomcat ポリシーの修正版作成

最初に selinux-policy-targeted のソースから tomcat ポリシーのソースを取り出して変更していきます。

SELinux ポリシーのソース入手

ソースパッケージのダウンロードとビルドに必要なパッケージをインストールします。

selinux-policy-targeted のソースパッケージをダウンロードします。

selinux-policy のビルドに必要な依存パッケージをインストールします。

selinux-policy ソースパッケージをインストールします。~rpmbuild 以下に展開されます。

rpmbuild のパッチ適用まで実施します。

これで tomcat ポリシーモジュールのソースが出来上がりました。

こちらのソースをベースに新ポリシーモジュールを作成していきます。

tomcat ポリシーから shell_exec_t と bin_t の実行権限を剥奪

先ほどの tomcat ポリシーモジュールのソースをコピーします。

勇んで修正しようと思いましたが tomcat.te を確認しても bin_t や shell_exec_t を直接許可する定義はありません。

いろいろ調べた結果 corecmd_exec_bin() と corecmd_exec_shell() でそれぞれ許可されるようなので、これを削除します。

他にも不要そうな実行権限らしきものがあったので削除しています。オリジナルとの差分は以下になりました。

ビルドします。

いくつか Error: duplicate definition of のエラーが出ますが container 関係の定義ですので無視します。どうしてもエラーが気になる方は、

  1. rpmbuild -bp rpmbuild/SPECS/selinux-policy.spec で生成された rpmbuild/BUILD/serefpolicy-3.13.1/policy/modules/contrib/tomcat.te を直接編集
  2. rpmbuild -bi -short-circuit rpmbuild/SPECS/selinux-policy.spec を実行
  3. 生成された rpmbuild/BUILD/serefpolicy-3.13.1/tomcat.pp を使う

という手もあります。tomcat.pp さえ手に入ればよいので完了まで待つ必要はないももの、ビルドに gcc が必要かつ時間がかかります。

tomcat ポリシーモジュールのインストール

ビルドしたポリシーモジュールをインストールします。

インストールしたポリシーモジュールはプライオリティ 400 でインストールされます。デフォルトのモジュールはプライオリティ 100 で残りますので、プライオリティ 400 のモジュールを削除すれば元の状態に戻すことができます。

新ポリシーの実行可能権限を確認すると、bin_t や shell_exec_t は含まれなくなっていることが確認できます。

tomcat_exec_t 以外にもまだ execute 権限が残っていますが、shell_exec_t や bin_t は含まれなくなりました。
因みにデフォルトのポリシーでの実行権限は以下でしたので、6 つの実行権限が減ったことになります。

tomcat 実行環境整備

jsvc コマンドでの起動に変更

shell_exec_t や bin_t の実行権限は剥奪できましたが、このままでは tomcat は起動できません。tomcat は java コマンドで動いており、java コマンドのタイプが bin_t なためです。

java 実行ファイルのタイプを bin_t から tomcat_exec_t に変更してもよいのですが、tomcat 以外でも利用される可能性を考えると避けたいところです。

ということで java コマンドを使わずに jsvc コマンドで起動できるように起動処理を修正していきます。
まず tomcat-jsvc パッケージを導入します。

SELinux 無効状態で起動確認

Permissive 状態で起動してみて、いくつポリシーに引っかかるか確認してみます。

audit.log を確認します。

readlink と bash で denied となっています。tomcat-jsvc.service の起動処理を調べてみると

  1. /usr/libexec/tomcat/server
  2. /usr/libexec/tomcat/preamble
  3. /usr/libexec/tomcat/functions
  4. /usr/share/java-utils/java-functions

の順で読み込まれていることがわかります。

  • bash は /usr/libexec/tomcat/server や build-classpath シェルスクリプトの実行に必要
  • readlink は /usr/share/java-utils/java-functions で JVM_ROOT や JAVA_HOME の設定に必要

となっているようです。

シェルを介さない起動処理に変更

ちょっと対応に悩みましたが、シェルの実行権限(shell_exec_t)は剥奪したままにしておきたいので、シェルではなく jsvc を直接実行するように tomcat-jsvc.service を変更します。

/usr/libexec/tomcat/functions の run_jsvc() を確認すると、jsvc での起動コマンドは以下のようになることがわかります。

停止コマンドは以下になります。

これらを ExecStart=, ExecStop= に指定しようと思いますが、/usr/bin/jsvc のタイプは bin_t ですので、unconfined_service_t で起動してしまいます。tomcat_exec_t ではないので、せっかく作成した tomcat ポリシーが効きません。
/usr/libexec/tomcat/jsvc を用意してタイプを tomcat_exec_t に変更し、そちらを実行するようにします。

タイプ変更は本来 tomcat.fc を変更して適用すべきですが、いったんコマンドで直接変更しました。
では tomcat-jsvc.service を修正します。

ExecStart= と ExecStop= を以下のように変更します。

SELinux 有効状態で起動確認

SELinux を Enforcing にして起動してみます。

無事起動できたようです。

リモートコード実行防御確認

struts2-showcase をデプロイして脆弱性回避できるか確認します。

コマンドの実行結果は表示されることなく、Struts2 Showcaseのトップページが表示されました。 /var/log/audit.log でも jsvc プロセス (scontext=system_u:system_r:tomcat_t:s0) から bash コマンド (tcontext=system_u:object_r:shell_exec_t:s0) が拒否されていることが確認できます。

コンテナにしたほうが楽なのか

コンテナ化をしたほうが楽なのではないかという意見もあるかと思いますので試してみましょう。 ベースイメージのサイズが小さいとされる Alpine ベースの tomcat を使用して Docker コンテナを作ります。Docker 実行環境自体の環境構築は割愛します。SELinux は無効化しています。 Dockerfile を用意してイメージをビルドします。

起動します。

RCE を試してみます。

単純にコンテナ化しただけでは当然 RCE 自体は防げませんし、サイズが小さいとされる Alpine ベースであっても、コマンド自体は多数含まれていますので「攻撃者ができることを減らす」という意味ではあまり効果がありません。被害がコンテナ内に限定されるという考えもありますが、データベースにアクセスして内容を攻撃者のサイトにアップロードするといった手法も考えるとコンテナ内だから安心とは一概には言えないと思います。

最後に

結局のところ、RCE 脆弱性をつかれても被害が広がらないようにするためには、脆弱性を悪用して実行できるコマンドを減らすことが重要になると思います。それを SELinux でおこなうか、実行可能なコマンド自体を減らしたコンテナを作るか、になるのかと思います。 また、今回の検証では触れていませんが SELinux は管理者権限昇格といった攻撃にも有効です。 セキュリティ以外の要件も考慮したうえで、適切な方式を選択することが重要だなと感じました。

あ、あと /usr/libexec/tomcat/jsvc を用意して手動でタイプを変更していますが、本来こちらも tomcat.fc でタイプ定義すべきものです。ちょっとサボりましたが悪しからず。

 

この記事が気に入ったら
いいね!しよう

最新情報をお届けします

Twitter で「株式会社アークシステム」をフォローしよう!

SELinuxポリシー修正によるTomcat実行環境の防御力アップhttps://devlog.arksystems.co.jp/wp-content/uploads/2018/07/military-jet-1008278_1280-1200x857.jpghttps://devlog.arksystems.co.jp/wp-content/uploads/2018/07/military-jet-1008278_1280-150x150.jpgksatoプラットフォーム技術部システム運用・保守Tomcat,SELinuxこんにちは、プラットフォーム技術部の佐藤です。 以前『【CVE-2017-5638 / S2-045】SELinuxポリシーのバグフィックスでTomcatアプリのRCEは防げるようになったのか』で、記事を書かせていただきました。 そのときは「リモートコード実行(RCE)を防げないかなー、防ぎたいなー」という目的に対してはあまり期待した結果には至らなかったですが、それでも SELinux 無効状態よりは防御力はあがる、ということを確認できたと思っています。 今回は SELinux の tomcat 用デフォルトポリシーをカストマイズして、更なる防御力アップを目指したいと思います。 今回の目標 RCE 脆弱性を突いて悪用されそうなものは /sbin, /usr/sbin, /bin, /usr/bin に配備されているコマンド群です。これらのパスに含まれるコマンドの多くは、タイプが shell_exec_t や bin_t となっています。これらの実行権限を tomcat から剥奪することで RCE 悪用被害を軽減します。 実は tomcat 自体を起動するための処理に必要なコマンドもあるので、単純に剥奪しただけでは宜しくないのですが、それらへの対処についても実施していきます。 tomcat ポリシーの修正版作成 最初に selinux-policy-targeted のソースから tomcat ポリシーのソースを取り出して変更していきます。 SELinux ポリシーのソース入手 ソースパッケージのダウンロードとビルドに必要なパッケージをインストールします。selinux-policy-targeted のソースパッケージをダウンロードします。selinux-policy のビルドに必要な依存パッケージをインストールします。selinux-policy ソースパッケージをインストールします。~rpmbuild 以下に展開されます。rpmbuild のパッチ適用まで実施します。これで tomcat ポリシーモジュールのソースが出来上がりました。こちらのソースをベースに新ポリシーモジュールを作成していきます。 tomcat ポリシーから shell_exec_t と bin_t の実行権限を剥奪 先ほどの tomcat ポリシーモジュールのソースをコピーします。勇んで修正しようと思いましたが tomcat.te を確認しても bin_t...ARK Solution Development Division Developers Blog.