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)。
这个路由表是系统级别的,对所有软件生效。
这里我输出了我自己的路由表,作为例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 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 ...3 c 2 c 30 99 07 5 e ......Realtek PCIe GbE Family Controller 32 ...0 a 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.黑魔法函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <sys/socket.h> #include <linux/netlink.h> int _ZN27CInterfaceRouteMonitorLinux20routeCallbackHandlerEv() { int fd=50 ; 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
所以应该:
1 2 3 4 5 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
(未完待续)
Reference
route
add no longer works when I connected to VPN via cisco anyconnect client
- StackOverflow
How
to allow local LAN access while connected to Cisco VPN?