Cisco AnyConnect/OpenConnect 客户端代理转发技术分析
普通的代理客户端如何转发客户端流量
本文编写时,较为流行的代理软件有 Clash, Shadowsocks, Tarjan, V2Ray 等,他们的 Windows 客户端无一例外地采用了 HTTP 代理或者 PAC 的方式来转发用户流量。
这样做的好处是: - 每次开启和关闭代理功能时,只需要调用系统级别的 HTTP代理开关即可 - PAC 可以容纳很大的域名和IP规则(GFW List)
当然了,也有缺点: - 部分软件不支持:终端 (需要配置环境变量), UWP 应用(需要配置 Local Loopback) - 对于某些用户来说,不够安全(并非所有流量都经由隧道转发)
Cisco AnyConnect 如何转发客户端流量
综上所述,Cisco AnyConnect 和各大厂商的 VPN 软件都采取了同一种方式。维护 Windows 的本地路由表(ROUTE.EXE
)。
这个路由表是系统级别的,对所有软件生效。
这里我输出了我自己的路由表,作为例子。
pwsh> route PRINT -4
===========================================================================
Interface List
16...00 ff 76 77 13 94 ......TAP-Windows Adapter V9
36...00 15 5d fb 59 43 ......Hyper-V Virtual Ethernet Adapter
18...3c 2c 30 99 07 5e ......Realtek PCIe GbE Family Controller
32...0a 00 27 00 00 20 ......VirtualBox Host-Only Ethernet Adapter
25...b4 69 21 54 05 88 ......Intel(R) Wireless-AC 9462
31...b4 69 21 54 05 89 ......Microsoft Wi-Fi Direct Virtual Adapter #4
20...b6 69 21 54 05 88 ......Microsoft Wi-Fi Direct Virtual Adapter #5
9...00 50 56 c0 00 01 ......VMware Virtual Ethernet Adapter for VMnet1
29...00 50 56 c0 00 08 ......VMware Virtual Ethernet Adapter for VMnet8
1...........................Software Loopback Interface 1
===========================================================================
IPv4 Route Table
===========================================================================
Active Routes:
Network Destination Netmask Gateway Interface Metric
0.0.0.0 0.0.0.0 <My WAN IP> <My WAN IP> 26
0.0.0.0 0.0.0.0 10.12.0.1 10.12.0.68 2
10.12.0.0 255.255.255.0 On-link 10.12.0.68 257
10.12.0.68 255.255.255.255 On-link 10.12.0.68 257
10.12.0.255 255.255.255.255 On-link 10.12.0.68 257
<VPN EXTERNAL GW> 255.255.255.255 <My WAN GW> <My WAN IP> 26
127.0.0.0 255.0.0.0 On-link 127.0.0.1 331
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
127.255.255.255 255.255.255.255 On-link 127.0.0.1 331
169.254.0.0 255.255.0.0 On-link 169.254.92.21 281
169.254.92.21 255.255.255.255 On-link 169.254.92.21 281
169.254.255.255 255.255.255.255 On-link 169.254.92.21 281
172.18.240.0 255.255.240.0 On-link 172.18.240.1 271
172.18.240.1 255.255.255.255 On-link 172.18.240.1 271
172.18.255.255 255.255.255.255 On-link 172.18.240.1 271
192.168.38.0 255.255.255.0 On-link 192.168.38.1 291
192.168.38.1 255.255.255.255 On-link 192.168.38.1 291
192.168.38.255 255.255.255.255 On-link 192.168.38.1 291
192.168.232.0 255.255.255.0 On-link 192.168.232.1 291
192.168.232.1 255.255.255.255 On-link 192.168.232.1 291
192.168.232.255 255.255.255.255 On-link 192.168.232.1 291
<My WAN SUBNET> 255.255.255.0 On-link <My WAN IP> 281
<My WAN IP> 255.255.255.255 On-link <My WAN IP> 281
<My WAN GW> 255.255.255.255 On-link <My WAN IP> 281
224.0.0.0 240.0.0.0 On-link 127.0.0.1 331
224.0.0.0 240.0.0.0 On-link <My WAN IP> 281
224.0.0.0 240.0.0.0 On-link 169.254.92.21 281
224.0.0.0 240.0.0.0 On-link 192.168.232.1 291
224.0.0.0 240.0.0.0 On-link 192.168.38.1 291
224.0.0.0 240.0.0.0 On-link 172.18.240.1 271
224.0.0.0 240.0.0.0 On-link 10.12.0.68 257
255.255.255.255 255.255.255.255 On-link 127.0.0.1 331
255.255.255.255 255.255.255.255 On-link <My WAN IP> 281
255.255.255.255 255.255.255.255 On-link 169.254.92.21 281
255.255.255.255 255.255.255.255 On-link 192.168.232.1 291
255.255.255.255 255.255.255.255 On-link 192.168.38.1 291
255.255.255.255 255.255.255.255 On-link 172.18.240.1 271
255.255.255.255 255.255.255.255 On-link 10.12.0.68 257
===========================================================================
Persistent Routes:
Network Address Netmask Gateway Address Metric
0.0.0.0 0.0.0.0 10.12.0.1 1
===========================================================================
路由表主要分为两大部分,上部是我们的网卡,又叫适配器(Adapter),又叫接口(Interface)。 分别拥有自己的 MAC,和 friendly-name.
而下方就是我们的路由表了。 我将逐行进行讲解。
Network Destination Netmask Gateway Interface Metric
这五个参数是一条路由的基本参数: - Network Destination 目标网段 - Netmask 其子网掩码 - Gateway 默认网关 - Interface 流量出接口 - Metric 路由距离 (网段的规则不唯一时相当于优先级,越小越优先)
直连流量出接口
0.0.0.0 0.0.0.0 <My WAN IP> <My WAN IP> 26
此路由指定了直连流量的出接口,为我们联网的网卡,在没连VPN时,它的路由距离是很小的,所以流量会从这里直接出去。这里 AnyConnect 将其改为 26,在 miss 掉所有 AnyConnect 的规则后,会匹配上此路由,进行直连。
VPN 流量出接口
0.0.0.0 0.0.0.0 10.12.0.1 10.12.0.68 2
VPN 的流量出接口,这里是 Remote 的 Inside IP
Remote LAN 流量代理路由
10.12.0.255 255.255.255.255 On-link 10.12.0.68 257
将 LAN IP 交由VPN隧道代理。
localhost
127.0.0.1 255.255.255.255 On-link 127.0.0.1 331
天经地义,不能动。
Cisco AnyConnect 的路由表保护
为了安全,AnyConnect 客户端会监听路由表,确保其完整性。完成这一工作的是其客户端中的 CHostConfigMgr::StartInterfaceAndRouteMonitoring()
函数。
如果出于某种原因,你想修改路由表的话,你需要用 IDA 或者 OllyDebug 修改这一函数,让他直接 return 掉。同时还需要绕过思科的 checksum 检查。(位于 vpnagentd.exe
中)。
一些黑魔法
如果你碰巧使用的是 Linux 系统,你可以尝试手写一个黑魔法函数——_ZN14CHostConfigMgr32StartInterfaceAndRouteMonitoringEv
1.黑魔法函数
#include <sys/socket.h>
#include <linux/netlink.h>
int _ZN27CInterfaceRouteMonitorLinux20routeCallbackHandlerEv()
{
int fd=50; // max fd to try
char buf[8192];
struct sockaddr_nl sa;
socklen_t len = sizeof(sa);
while (fd) {
if (!getsockname(fd, (struct sockaddr *)&sa, &len)) {
if (sa.nl_family == AF_NETLINK) {
ssize_t n = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
}
}
fd--;
}
return 0;
}
2.编译
gcc -o libhack.so -shared -fPIC hack.c
- 安装
libhack.so
到 Cisco library path中:
sudo cp libhack.so /opt/cisco/anyconnect/lib/
- 关闭 AnyConnect
/etc/init.d/vpnagentd stop
- 检查进程
ps auxw | grep vpnagentd
如果它不肯体面,我们就帮它体面。
kill -9
- 如果存在
/etc/init.d/vpnagentd
的话,尝试添加LD_PRELOAD=/opt/cisco/anyconnect/lib/libhack.so
到底层二进制文件被调用的地方,最后应该看起来像这样:
LD_PRELOAD=/opt/cisco/anyconnect/lib/libhack.so /opt/cisco/anyconnect/bin/vpnagentd
新版本的 AnyConnect 使用了 /etc/init.d/vpnagentd
而不是 /lib/systemd/system/vpnagentd.service
所以应该:
sudo mv /opt/cisco/anyconnect/bin/vpnagentd /opt/cisco/anyconnect/bin/vpnagentd.orig &&
{ echo '#!/bin/bash' &&
echo "LD_PRELOAD=$HOME/vpn/libhack.so exec /opt/cisco/anyconnect/bin/vpnagentd.orig"
} | sudo tee /opt/cisco/anyconnect/bin/vpnagentd &&
sudo chmod +x /opt/cisco/anyconnect/bin/vpnagentd
- 扫清六合,天下归一,是时候启动了
/etc/init.d/vpnagentd start
- 注意此时 AnyConnect 已经把路由表干烂了,需要手动修复:
iptables-save | grep -v DROP | iptables-restore
- 如果你有本地LAN的访问需求的话,自己改路由表。
指定接口:
route add -net 192.168.1.0 netmask 255.255.255.0 dev wlan0
- 检查结果
route -n
(未完待续)