進階說明

應用說明

    • 本應用分為以下部份:
      • TaskMgr 程式:以 root 身份執行。
        • (1) 使用者輸入 GID。
          • 若 GID 為 -1 則終止程式。
        • (2) 使用者輸入 UID。
        • (3) 執行 UserShell2 外部程式。
        • (4) 再返回 (1) 要求使用者輸入。
      • UserShell2 程式:
        • (1) 轉換為指定群組〈如:dasadm1〉下用戶〈如:dasusr1〉。
        • (2) 在該群組用戶下,執行外部程式 getID。
      • getID 程式:
        • (1) 透過 getgid()、getuid() 等系統 API 取得當前群組及用戶 ID。
        • (2) 執行外部程式 /usr/bin/whoami。
        • (3) 執行外部程式 /usr/bin/id。
    • 討論:
      • (1) 不應在 TaskMgr 轉換群組用戶原因:
        • 先進作業系統對於 setgid()、setuid() 等系統 API 有安全考量,防止木馬程式在較高權限帳號下,恣意任為。
        • 當由較高權限帳號下轉換群組及用戶時,又透過 Shell 執行外部程式,此時作業系統程序控制區塊〈Process Control Block〉中群組及用戶已經改變為較低權限之帳號。
        • 一但轉換為較低權限之帳號,再調用 setgid()、setuid() 等系統 API 時,受到作業系統安全保護,將不允許由權限帳號轉換為較高權限帳號。
      • (2) 應該在 UserShell2 外部程式轉換群組用戶原因:
        • 由自身程式轉換為該外部程式指定之權限帳號,確保程式運行環境為指定權限。
        • 若調用外部程式者之權限較低,則程式轉換指定權限帳號會失敗,作業系統安全機制避免非法執行較高權限程式。

/* * TaskMgr.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <sys/wait.h> #include <errno.h> struct INFO { gid_t GID; uid_t UID; }; char *runnerHomeDir = "/home/rich.lee/Workspace/UserShell/src"; char *runnerShell = "UserShell2"; void runShell(struct INFO *newInfo) { char shellCmd[64]; memset(shellCmd, 0, sizeof(shellCmd)); sprintf(shellCmd, "%s/%s %d %d", runnerHomeDir, runnerShell, newInfo->GID, newInfo->UID); system(shellCmd); } int main(int argc, char *argv[]) { struct INFO newInfo; while (1) { printf("GID="); scanf("%d", &newInfo.GID); if (newInfo.GID == -1) break; printf("UID="); scanf("%d", &newInfo.UID); runShell(&newInfo); } }

/* * UserShell2.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <string.h> #include <sys/wait.h> #include <errno.h> char *cmd = "/usr/local/bin/getID"; struct INFO { gid_t GID; uid_t UID; }; int getEnv(int argc, char *argv[], struct INFO *newInfo) { int ret = -1; if (argc < 2) return ret; newInfo->GID = atoi(argv[1]); newInfo->UID = atoi(argv[2]); ret = 0; return ret; } void userTask(struct INFO *newInfo) { if (setgid(newInfo->GID) != -1) { if (setuid(newInfo->UID) != -1) { system(cmd); } else { perror("userTask::setuid() Error"); } } else { perror("userTask::setgid() Error"); } } int main(int argc, char *argv[]) { struct INFO newInfo; if (getEnv(argc, argv, &newInfo)) return EXIT_FAILURE; userTask(&newInfo); return EXIT_SUCCESS; }

/* * getID.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <string.h> struct INFO { uid_t UID; gid_t GID; } currentInfo; int main(void) { memset(&currentInfo, 0, sizeof(struct INFO)); currentInfo.UID = getuid(); currentInfo.GID = getgid(); printf("%d:%d\n", currentInfo.GID, currentInfo.UID); system("whoami;id"); return EXIT_SUCCESS; }