Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> 關於 Linux

UNIX/Linux SetUID 位元深度解析:原理、程式碼實作與安全最佳實踐

編輯:關於 Linux

SetUID(Set User ID upon execution) 是 UNIX/Linux 權限系統中最強大也最危險的機制之一:允許使用者執行檔案時,暫時獲得檔案擁有者的權限。本文從核心資料結構、程式碼實作、實戰演示到安全防護,完整解析 SetUID 運作原理。

SetUID 概念圖

一、核心資料結構:struct stat 與進程 ID

檔案狀態結構體(man 2 stat)

struct stat {
    dev_t     st_dev;      // 裝置 ID
    ino_t     st_ino;      // inode 號
    mode_t    st_mode;     // 權限與檔案類型(含 SetUID 位)
    nlink_t   st_nlink;    // 硬連結數
    uid_t     st_uid;      // 檔案擁有者 UID
    gid_t     st_gid;      // 檔案擁有者 GID
    dev_t     st_rdev;     // 裝置 ID(特殊檔案)
    off_t     st_size;     // 大小(bytes)
    blksize_t st_blksize;  // 塊大小
    blkcnt_t  st_blocks;   // 512B 區塊數
    time_t    st_atime;    // 最後存取時間
    time_t    st_mtime;    // 最後修改時間
    time_t    st_ctime;    // 最後狀態變更時間
};

進程四組 ID

二、SetUID 運作流程

  1. 使用者執行帶有 SetUID 位的可執行檔(chmod u+s prog 或 chmod 4755 prog)
  2. 核心檢查:檔案可執行、非目錄、檔案系統未掛載 nosuid
  3. 核心設定進程 euid = 檔案 st_uid,suid = 檔案 st_uid
  4. 進程以檔案擁有者身分進行權限檢查(開啟檔案、綁定埠口等)
  5. 進程可呼叫 setuid()、seteuid() 在 ruid/euid/suid 間切換

三、實戰演示:C 程式讀取 root 專屬檔案

1. 準備受保護檔案

# root 執行
echo "secret data" > /root/secret.txt
chmod 600 /root/secret.txt
ls -l /root/secret.txt
# -rw------- 1 root root 12 ... /root/secret.txt

2. 一般使用者編寫讀取程式

// read_secret.c
#include 
#include 
#include 
#include 

int main() {
    int fd = open("/root/secret.txt", O_RDONLY);
    if (fd == -1) {
        perror("open failed");
        return 1;
    }
    char buf[1024];
    ssize_t n = read(fd, buf, sizeof(buf)-1);
    if (n > 0) {
        buf[n] = '\0';
        printf("%s\n", buf);
    }
    close(fd);
    return 0;
}

3. 編譯與測試(無 SetUID)

$ gcc read_secret.c -o read_secret
$ ./read_secret
open failed: Permission denied

4. 啟用 SetUID(需 root)

# root 執行
chown root:root read_secret
chmod 4755 read_secret  # 或 chmod u+s read_secret
ls -l read_secret
# -rwsr-xr-x 1 root root ... read_secret  (s 表示 SetUID + 執行權限)

5. 一般使用者再次執行

$ ./read_secret
secret data
# 成功讀取!進程 euid 變為 root (0)

四、程式碼方式設定 SetUID(對應原文範例)

#include 

int main() {
    struct stat buf;
    stat("read_secret", &buf);
    buf.st_mode |= S_ISUID;        // 設定 SetUID 位
    chmod("read_secret", buf.st_mode);
    return 0;
}

五、SetGID 與 Sticky Bit 關聯

ID 類型宏/欄位含義SetUID 影響
Real UIDruid / getuid()啟動進程的真實使用者不變
Effective UIDeuid / geteuid()權限檢查時使用的 UID變為檔案擁有者 UID
Saved Set-UIDsuid / getresuid()保存的 SetUID,用於切換回設為檔案擁有者 UID
File System UIDfsuid檔案系統權限檢查用(通常等同 euid)跟隨 euid

六、安全風險與防護最佳實踐

⚠️ 風險場景

  • SetUID 程式存在緩衝區溢位、指令注入、路徑遍歷等漏洞 → 攻擊者取得 root shell
  • 環境變數污染(LD_PRELOAD、PATH、IFS)劫持程式行為
  • 不當使用 system()、popen() 呼叫 Shell
  • 臨時檔案競態條件(TOCTOU)

✅ 開發防護清單

  1. 盡量避免 SetUID:改用 sudo、capabilities、systemd socket activation、polkit
  2. 最小權限原則:僅在必要程式碼段提權,隨即降權(seteuid(getuid()))
  3. 清理環境:clearenv() 或手動重設 PATH、IFS、LD_*
  4. 避免 Shell:直接呼叫 execve(),不使用 system()
  5. 驗證輸入:嚴格檢查所有外部輸入
  6. 安全臨時檔:mkstemp()、O_EXCL
  7. 審計日誌:記錄關鍵操作供事後追蹤

✅ 系統管理防護

# 1. 定期掃描 SetUID 程式
find / -type f -perm -4000 -ls 2>/dev/null

# 2. 掛載選項限制
# /etc/fstab: /home  nosuid,nodev,noexec
# 禁止在家目錄執行 SetUID 程式

# 3. 移除不必要的 SetUID
chmod u-s /usr/bin/unnecessary-setuid-binary

# 4. 使用 capabilities 替代(Linux 2.1+)
# 例:ping 需原始 socket,改用 CAP_NET_RAW
setcap cap_net_raw+ep /usr/bin/ping
# 移除 SetUID
chmod u-s /usr/bin/ping

七、經典 SetUID 程式清單

機制位元八進位檔案效果目錄效果
SetUIDS_ISUID4000執行時 euid=檔案擁有者無效
SetGIDS_ISGID2000執行時 egid=檔案群組新檔繼承目錄群組
StickyS_ISVTX1000無效僅擁有者可刪除檔案

SetUID 是一把雙面刃:正確使用能實現最小權限提升,濫用則是提權漏洞溫床。現代 Linux 傾向以 Capabilities、systemd、Polkit 替代 SetUID,建議新專案優先評估替代方案。

Copyright © Windows教程網 All Rights Reserved
程式用途現代替代
/usr/bin/passwd修改密碼(寫 /etc/shadow)PAM + sudo
/usr/bin/su切換使用者sudo
/usr/bin/sudo提權執行核心工具
/usr/bin/pingICMP 需原始 socketCAP_NET_RAW
/usr/bin/mount掛載檔案系統sudo + /etc/fstab user 選項
/usr/bin/umount卸載檔案系統同上