File-Descriptors

Set-UID 能力洩漏攻擊

  • July 20, 2019

我有一個C程序來展示capability leak關於 set-uid 的攻擊。

// cap_leak.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

void main()
{  
   int fd;  char *v[2];  
   /* Assume that /etc/zzz is an important system file, and it is owned by root with permission 0644. Before running this program, you should create the file /etc/zzz first. */  

   fd = open("/etc/zzz", O_RDWR | O_APPEND);

   // Print out the file descriptor value  
   printf("fd is %d\n", fd);    
   if (fd == -1) 
   {     
       printf("Cannot open /etc/zzz\n");     
       exit(0);  
   }  
   // Permanently disable the privilege by making the  
   // effective uid the same as the real uid  
   setuid(getuid()); 
   printf("Real user id is %d\n", getuid());    
   printf("Effective user id is %d\n", geteuid());    

   // Execute /bin/sh  
   v[0] = "/bin/sh"; v[1] = 0;  
   execve(v[0], v, 0);        
}

最初,cat /etc/zzz給出:

this is a very important file

現在我編譯這個程序:

gcc -o cap_leak cap_leak.c

將所有者更改為 root 並打開 setuid 位:

sudo chown root cap_root
sudo chmod 4755 cap_root

現在,當我從普通使用者執行程序時,我得到一個 shell 提示:

fd is 3
Real user id is 1000
Effective user id is 1000
$whoami
$seed
$echo bbbbbb >&3
$cat /etc/zzz
$this is a very important file
bbbbbb

最後一次寫入fd = 3ie/etc/zzz是成功的,儘管在打開文件後setuid()呼叫了該函式,該函式基本上將真實、有效和保存的 uid 設置為原始 uid。我的問題是,為什麼最後一次寫入是成功的,即使它是在之後執行的,setuid()並且在這種情況下為了防止能力洩漏,應該把setuid()它放在哪裡,為什麼?

沒有其他地方應該放置setuid(),您不應該讓文件保持打開狀態以供寫入。

原因是在打開文件時檢查權限,而不是在每次write()呼叫時檢查。

如果非特權 shell 不應該寫入該文件,則沒有理由讓文件以寫訪問權限打開。

引用自:https://unix.stackexchange.com/questions/531191