MENU

LinuxのSUID/SGIDビット脆弱性と対策|特権昇格につながる危険なファイルの検出・無効化ガイド

Linuxサーバーのセキュリティチェックを依頼されたとき、真っ先に確認する項目の一つがSUID/SGIDビットです。「何となく知っている」「設定はデフォルトのまま」というエンジニアの方が多い領域ですが、攻撃者はここを見逃しません。

ペネトレーションテスト(侵入テスト)でサーバーへの足がかりを得た後、「次の一手」を探す攻撃者が真っ先に実行するコマンドがあります。それが find / -perm -4000、つまりSUIDBITが立ったファイルの全件洗い出しです。

この記事では、LinuxのSUID/SGIDビットが特権昇格(一般ユーザーからroot権限への乗っ取り)にどう悪用されるかを防御目的で解説し、情シス1人でも実施できる検出・無効化・継続監視の手順を現場レベルでお伝えします。

TOC

SUID/SGIDビットとは?なぜセキュリティリスクになるか

Linuxのファイルには「rwxrwxrwx」形式のパーミッションが設定されています。その中で、通常の実行権限とは別の動作をする特殊ビットが SUID(Set User ID)SGID(Set Group ID) です。

SUIDビットが設定されたファイルは、実行した際に「ファイルの所有者の権限」でプロセスが動作します。所有者がrootでSUIDビットが立っているコマンドを一般ユーザーが実行すると、そのプロセスはroot権限で動くことになります。

SGIDビットは同様の概念をグループに適用したものです。ファイルに設定された場合、実行時にファイルのグループ権限でプロセスが動作します。ディレクトリに設定された場合は、そのディレクトリ配下に作成されるファイルが同じグループに帰属します。

SUIDビットが立ったファイルを ls -l で確認すると、次のように表示されます。

-rwsr-xr-x 1 root root 64448 ... /usr/bin/passwd # 所有者の実行ビット位置が 'x' ではなく 's' になっている → SUIDビットが設定済み

passwd コマンドはSUIDが必要な代表例です。一般ユーザーが自分のパスワードを変更するには /etc/shadow に書き込む権限が必要ですが、その権限はrootだけに許可されています。passwdコマンドにSUIDを設定することで「passwdを使う間だけroot権限を借りる」仕組みを実現しています。

問題は、本来SUIDが不要なファイルにビットが残っている場合です。システムインストール時のデフォルト状態から変わっていないSUIDBINARYや、管理者が誤って設定したSUIDBITが、攻撃者の権限昇格の踏み台になります。

攻撃者はSUID/SGIDをどう悪用するか

Linuxサーバーへの侵入に成功した攻撃者は、最初は「一般ユーザー権限」しか持っていないことがほとんどです。そこからroot権限を奪う操作が「ローカル権限昇格(Local Privilege Escalation)」と呼ばれる攻撃フェーズです。SUID悪用はその代表的な手法です。

防御目的で手口の概要を理解しておきましょう。

SUIDファイルの列挙: 攻撃者は find / -perm -4000 2>/dev/null でSUIDビット付きファイルを洗い出します。このコマンドは一般ユーザーでも実行できます。
悪用可能なバイナリの選別: GTFOBins(特権昇格に使えるバイナリをまとめた参考情報サイト)などを参照し、SUIDが設定されたバイナリの中からシェルを奪取できるものを選びます。
rootシェルの取得: たとえば vimfind に誤ってSUIDBITが設定されていた場合、それらのバイナリが持つシェル起動機能を使ってrootシェルを起動できます。
完全な権限奪取: root権限を手にした攻撃者は、バックドアの埋め込みや /etc/passwd の改ざんなど、システム全体にわたる操作が可能になります。

「内部ネットワークだから大丈夫」という考えは危険です。社員の端末が踏み台にされたり、VPN経由の不正アクセスが発生した場合、サーバー内部でのSUID悪用が一気に被害を拡大させます。

システム上のSUID/SGIDファイルを一斉に洗い出す

まず現状把握から始めましょう。標準の find コマンドだけで調査できます。

1. SUIDビット付きファイルの検出

# SUIDビット付きファイルをシステム全体から検索 find / -perm -4000 -type f 2>/dev/null # /proc・/sys・NFS等の仮想FSを除外した効率的な検索 find / -xdev -perm -4000 -type f 2>/dev/null # 所有者・パーミッション・パスを一緒に表示 find / -xdev -perm -4000 -type f -exec ls -la {} \; 2>/dev/null

-xdev オプションを付けると、現在のファイルシステム内のみを検索します。/proc や /sys のような仮想ファイルシステムへのアクセスエラーが大幅に減り、出力がすっきりします。

2. SGIDビット付きファイルとディレクトリの検出

# SGIDビット付きファイル find / -xdev -perm -2000 -type f -exec ls -la {} \; 2>/dev/null # SGIDビット付きディレクトリ(共有ディレクトリの確認) find / -xdev -perm -2000 -type d -exec ls -la {} \; 2>/dev/null

3. SUID/SGID両方を一度に検索してファイルに保存

# SUID(4000)またはSGID(2000)が立っているファイルをまとめて検索し保存 find / -xdev \( -perm -4000 -o -perm -2000 \) -type f \ -exec ls -la {} \; 2>/dev/null | tee /tmp/suid_sgid_list.txt # 件数の確認 wc -l /tmp/suid_sgid_list.txt

実行すると数十行から数百行の出力が返ってきます。このリストをすべて無効化すればよいわけではありません。次のステップで「消してはいけないSUID」と「不要なSUID」を見分けます。

「消してはいけないSUID」と「不要なSUID」を見分ける

SUIDが正常動作のために必要なバイナリは存在します。誤って除去するとシステムが機能しなくなります。

バイナリ SUIDが必要な理由 判定
/usr/bin/passwd /etc/shadowへの書き込みにroot権限が必要 必要(残す)
/usr/bin/sudo 権限昇格の仕組みそのもの 必要(残す)
/usr/bin/su ユーザー切り替えにroot権限が必要 必要(残す)
/usr/bin/newgrp グループ切り替えにSUIDBITが必要 必要(残す)
/usr/bin/ping ICMPソケット操作(カーネル4.X以降は不要なケースも) 環境依存(動作確認後に判断)
/usr/bin/find 本来SUID不要 不要(外す)
/usr/bin/vim・/usr/bin/nano 本来SUID不要 不要(外す)
/usr/bin/nmap 本来SUID不要 不要(外す)

判別の基本ルールは「そのバイナリが正常動作するために構造的にroot権限が必要かどうか」です。テキストエディタ・ファイル検索ツール・ネットワークスキャンツールなどはSUIDが不要なケースがほとんどです。

パッケージマネージャーで正規品かどうかを照合する方法もあります。

# RHEL/CentOS/AlmaLinux系:RPMデータベースとの照合 rpm -V $(rpm -qf /path/to/binary) # Debian/Ubuntu系:dpkgデータベースとの照合 dpkg --verify $(dpkg -S /path/to/binary | cut -d: -f1) # パッケージ管理外のファイルかどうかを確認 rpm -qf /path/to/binary # 管理外の場合: file /path/to/binary is not owned by any package

パッケージが管理していないファイルにSUIDBITが立っていたら、それは特に要注意です。攻撃者が埋め込んだ悪意あるバイナリの可能性があります。

不要なSUID/SGIDビットを無効化する手順

不要なSUIDBITは chmod コマンドで取り除けます。作業前に変更内容を記録し、変更後は動作確認を行います。

1. SUIDビットを外す基本コマンド

# SUIDビットのみ除去(グループ・その他の実行権限は維持) sudo chmod u-s /usr/bin/find # SGIDビットのみ除去 sudo chmod g-s /usr/bin/write # SUID/SGID両方を除去 sudo chmod ug-s /path/to/binary # 変更後の確認('s' が消えて 'x' に戻っていればSUID除去成功) ls -la /usr/bin/find # 期待出力例: -rwxr-xr-x 1 root root ... /usr/bin/find

2. pingのSUID判定は動作確認が必要

Linuxカーネルのバージョンや設定によって、pingコマンドがSUIDBITなしで動作するかどうかが変わります。安易に除去するとpingが使えなくなるため、事前確認が必要です。

# pingのSUID状態を確認 ls -la /usr/bin/ping # カーネル4.X以降はnet.ipv4.ping_group_rangeで制御可能な場合がある sysctl net.ipv4.ping_group_range # 出力例: net.ipv4.ping_group_range = 1 0 # ↑ この場合はSUIDなしでも一般ユーザーがpingを実行できる # 確認後にSUID除去し、一般ユーザーアカウントでpingが動作するかテスト sudo chmod u-s /usr/bin/ping ping -c 1 127.0.0.1

3. 変更履歴を残す

# SUID無効化の作業ログを記録(監査対応にも役立つ) echo "$(date '+%Y-%m-%d %H:%M:%S') $(whoami): removed SUID from /usr/bin/find" \ >> /var/log/suid_changes.log

継続監視:新たなSUID/SGIDファイルを自動検知する仕組みを作る

一度整理しても、パッケージ更新やソフトウェアのインストールによって新しいSUIDBITが付いたファイルが増えることがあります。定期的な監視が欠かせません。

1. cronによる差分検知スクリプト

#!/bin/bash # /usr/local/bin/suid-monitor.sh # SUID/SGIDファイルの変化を検知してメール通知する REPORT_DIR="/var/log/suid-monitor" CURRENT="${REPORT_DIR}/current.txt" PREV="${REPORT_DIR}/previous.txt" DIFF_LOG="${REPORT_DIR}/diff-$(date +%Y%m%d-%H%M%S).txt" ADMIN_EMAIL="admin@example.com" mkdir -p "$REPORT_DIR" # 現在のSUID/SGIDファイル一覧を取得(パス・パーミッション・所有者を記録) find / -xdev \( -perm -4000 -o -perm -2000 \) -type f \ -exec ls -la {} \; 2>/dev/null | sort > "$CURRENT" # 前回との差分を比較して変化があれば通知 if [ -f "$PREV" ]; then diff "$PREV" "$CURRENT" > "$DIFF_LOG" if [ -s "$DIFF_LOG" ]; then mail -s "[SECURITY ALERT] SUID/SGID変更検知 $(hostname)" \ "$ADMIN_EMAIL" < "$DIFF_LOG" logger -t suid-monitor "SUID/SGID変化を検知。詳細: ${DIFF_LOG}" fi fi # 今回の結果を次回比較用として保存 cp "$CURRENT" "$PREV"

# スクリプトに実行権限を付与 sudo chmod +x /usr/local/bin/suid-monitor.sh # crontabに登録:毎日深夜3時に自動実行 # sudo crontab -e で以下の行を追加 0 3 * * * /usr/local/bin/suid-monitor.sh

2. AIDEとの連携

すでにAIDE(ファイル整合性監視)を導入している環境では、AIDEのポリシーにパーミッション変化の監視を含めることで、SUID/SGIDビットの変化も自動的に捕捉できます。

# /etc/aide.conf のバイナリ監視設定にパーミッション変化を含める例 # p=パーミッション, i=inode, u=UID, g=GID も監視対象に加える /usr/bin CONTENT+p+i+u+g /usr/sbin CONTENT+p+i+u+g

中小企業でも今日からできること

大規模な仕組みを構築する前に、まず現状把握から始めましょう。追加ツールは一切不要です。

Step 1 — SUID一覧を取得してファイルに保存する: find / -xdev -perm -4000 -type f 2>/dev/null > ~/suid_list.txt を実行します。リストを眺めるだけで「あれ、これSUID不要では?」と気づく項目が見つかるはずです。
Step 2 — /tmp・/home 配下のSUIDBITは即調査: ユーザーの作業ディレクトリや一時ファイル置き場にSUIDBITが立っているファイルがあれば、不審なファイルの可能性があります。
Step 3 — テキストエディタ・スキャンツール類のSUIDBITを外す: vim・nano・find・nmap などにSUIDBITが付いていれば基本的に不要です。動作確認しながら chmod u-s で除去します。
Step 4 — 月1回の定期チェックをcronで自動化: 上記の監視スクリプトをcronに仕込むだけで継続監視が始まります。メール通知があれば異変にすぐ気づけます。
Step 5 — パッケージ更新後は必ずチェック: yum updateapt upgrade の後にSUID一覧を再取得し、前回との差分を確認する習慣を付けます。

LinuxサーバーのSUID/SGID管理を体系的に学びたい方は、姉妹サイトLinuxMaster.JPでもLinuxのパーミッション体系・権限管理の基礎から実践まで解説しています。

よくある誤解と注意点

「デフォルト設定のまま使っているから安全」は誤りです。 OSインストール直後のデフォルト状態には、環境によっては不要なSUIDBITが付いたファイルが含まれることがあります。ディストリビューションのバージョンや追加インストールしたパッケージによっても変わるため、環境ごとに確認が必要です。

「コンテナ環境は関係ない」とは言えません。 Dockerコンテナイメージ内のバイナリにSUIDBITが立っていた場合、コンテナブレイクアウトの脆弱性と組み合わさると、ホストOSへの影響が出る可能性があります。コンテナイメージのセキュリティスキャン時にもSUID確認を含めてください。

「全部のSUIDBITを外せばいい」は禁物です。 passwdsudo など機能的にSUIDBITが必要なバイナリを誤って変更すると、一般ユーザーがパスワード変更できなくなったり、sudo自体が動作しなくなります。必ず段階的に確認しながら進めてください。

「100%安全な設定は存在しない」ことも念頭に置いてください。 SUID管理はLinuxセキュリティの一要素です。ファイアウォール設定・ログ監視・定期的なパッチ適用・アクセス権の最小化といった他の対策と組み合わせることで初めて実効性が上がります。

本記事のまとめ

対策項目 実施方法 難易度
SUID/SGIDファイルの全件検出 find / -xdev -perm -4000 (または -2000) 低(すぐできる)
不要なSUIDBITの除去 sudo chmod u-s /path/to/binary 低(動作確認を忘れずに)
パッケージとの照合で正規品確認 rpm -V / dpkg –verify 中(判断力が必要)
cronによる差分監視・メール通知 シェルスクリプト+crontabに登録 中(スクリプト設定)
AIDE連携による自動検知 aide.confにCONTENT+p+i+u+g設定追加 中(AIDE導入済み環境向け)

SUID/SGIDビットの管理は地味な作業に見えますが、攻撃者が「サーバーへの侵入に成功した、次はroot権限を取ろう」と考えたとき、真っ先に確認するのがこのリストです。定期的なパッチ適用や不審ログの監視と同様に、SUID/SGID管理を日常のセキュリティチェック項目に組み込んでください。

Linuxサーバーのセキュリティ設定、どこまで対処できていますか?

SUID/SGIDの管理だけでなく、SELinux・PAM・firewalld・ログ監視など、Linuxサーバーを堅牢に保つための設定は多岐にわたります。
正しいセキュリティ知識を体系的に身につけたい方へ、メルマガで実践的なセキュリティ対策ノウハウをお届けしています。

Let's share this post !

Author of this article

TOC