前言
Netkeeper(以下简称NK),是一款校园宽带拨号软件,它通常被认为是该类软件的代表,而不仅指代这一款软件。它的功能是在计算机和网络之间设障碍,每个宽带账户像一个通行证,每次只允许一台计算机通过。如果两台计算机都想联网,不采取措施的情况下只能办理多个宽带账户。
知识预备
网络基础
1. 物理层
使电/光信号能够从一端传到另一端
物理层指的是信号传输的媒介,通过如电缆(网线)、光缆、空气(无线) 等媒介连着两台设备才有可能进行通信,通过高低电平传输数据。但物理层的数据并不可靠,因为磁场、宇宙射线等因素可能影响正在传输的高低电平,使到达另一端的数据并非原本的数据。
2. 数据链路层(PPP)
使数据能准确无误的在相邻的两台设备间传输
数据链路层就是为了解决这个问题,常见如点对点协议(Point to Point Protocol),简称PPP,PPP会检测到已经损坏的数据,并抛弃该段数据,要求重新传送,直到传送的是正确的数据,在PPP之上,你不必担心你接收到的数据是否正确,因为损坏的数据被丢弃了;PPP可以让你可靠地在点与点之间传输数据,但显然你不能用一根网线穿越太平洋,你的网线没有那么长,只够连接到离你最近的路由器。
3. 网络层(IP)
使数据能够传送到远程(非相邻)设备上
网络层协议最常见如IP协议,IP协议被大多数路由器支持,你只需要向路由器发送报文,并说明报文的目的地(目的IP地址),报文就能被沿途所有支持IP协议的路由转发,最终被目的IP的设备接收。但网络层协议的不足在于,只要中途的某一次转发出错,这个报文就永远到达不了目的地了。
※ 如果IP包总是到达不了目的地,这个报文也不会被无休止的转发,报文中TTL会限制最大转发次数。
4. 传输层(TCP/UDP)
使数据能够准确无误的传达
传输层协议可以解决这个不足,比如TCP,这是一种使数据准确无误地传输到远程的协议。达到准确无误的方式并不是让IP包不出错,而是在其出错的时候,检查到此次错误,并令源设备重发该条出错的报文。使最终的效果是,目的设备准确无误地收到顺序的数据。
※ TCP协议有很多细节用于提高效率,比如快速失败
5. 安全层(SSL/TLS)
使数据在传送过程中不被窥探
安全层并不是ISO模型中的一层,但我觉得可以单独拎出来说。
直到传输层,报文可以做到远程可靠地传输,但这些报文是以明文在传输,一旦中途某个路由节点被控制,所有的流量都可以被窥探和篡改,安全层则以某种规范加密报文中的有效数据,可以保护流量的安全。
6. 会话层(无单独实现)
使应用建立和维持会话,并能使会话获得同步
无单独实现
7. 表示层(无单独实现)
表示层为在应用过程之间传送的信息提供表示方法的服务
无单独实现
8. 应用层(FTP/SMTP/HTTP)
使应用程序间能够交流
会话层、表示层虽然是ISO模型的一部分,但并没有被现实采纳,而是被统一归并为应用层。
如在应用层协议HTTP中,首部字段cookies、session充当了会话层,包体中的html文档就充当了表示层,xml、json充当了应用层。
PPPOE
一般来说,你的计算机要与远程进行数据交换,得使用TCP/IP协议,那么你本机就需要有一个IP地址,IP地址是一个标识,一般由上级网关分配。如果上级网关不分配IP给你的计算机,那你的计算机就不能联网。
如果我有一个合法的宽带账户,获取IP的过程是怎么样的?
在计算机获取IP之前,只能在链路层通信,PPP协议是点对点的,为两个对等地址建立连接通道,即相邻的两个设备。运营商显然不会把宽带账户数据库放在与你的计算机相连的设备上。所以事实上,验证宽带账户的方式使用的是一种叫PPPOE的链路层协议,PPPOE为非点对点链路的以太网物理链路上承载PPP报文提供了一种创建虚拟点对点隧道链路的协商方式和封装方式。即:不获取IP的情况下,使用PPPOE协议可以与运营商远程设备进行校验宽带账户合法性的操作。一旦校验通过,就会为你的计算机分配IP地址。
NK运作机制
网络环境:
NK客户端网站服务器
PPPOE服务器
DHCP服务器
NK工作流程:
版本1:
PC客户端启动
等待用户输入宽带账号、密码
加密宽带账号得到临时账号
使用使用临时账号,调用系统API进行PPPOE拨号
账号密码通过验证,得到IP地址
while 客户端正在运行 && 本地无共享行为 {
持续网络连接
}
断开网络
版本2:
PC客户端启动
从服务器加载token,并显示二维码在PC客户端上
手机客户端启动,并登录宽带账户
手机扫描PC客户端二维码
服务器为扫描的token生成临时宽带账号
PC客户端发现当前token对应的临时宽带账号
PC客户端使用该临时账号拨号,调用系统API进行PPPOE拨号
拨号时发送TCP/UDP密文,协助账号密码验证
账号密码通过验证,得到IP地址
while PC客户端正在运行 && 本地无共享行为 {
持续网络连接
}
断开网络
防止网络共享策略
不为路由器分配公网IP地址
确定一台正在拨号的设备是否为路由器听起来有点难度,实际上NK是这样做的,
NK客户端把宽带账号转换为具有时效性的其它字符串,调用系统拨号API拨号。
如果使用路由器,你填入的必定是正常的宽带账号,验证宽带合法性的时候就不会通过,因为只有被转换过的宽带账号可以通过,所以路由器就得不到IP地址。不可输入的宽带账号
如果转换出的有时效性的字符串被获取了,用它登录路由器似乎仍然可行。但是转换出的字符串有不可见字符呢?网页上可不能输入不可见字符到文本框,所以无法输入,也无法拨号。检测网络共享软件
这是NK客户端的另一个主要作用,笔记本通常有两个网卡,各种共享大师可以把笔记本变成无线热点分享网络,NK客户端在本地检测这类共享软件,检测到,立即断开网络。客户端存在检测
如果用NK连上网络后立刻结束进程,再开共享大师情况会如何呢。答案是会享受几百秒的WiFi时光,仅此而已。因为当你联网成功后,NK会每隔几百秒发送一次心跳报文,如果对方服务器一段时间内没有收到心跳报文,主动断开网络。利用路由器的弱点
大多路由器在进行PPPOE验证时,会释放IP,不可以发送TCP/UDP报文。而PC会在PPPOE交互完成前持有IP,可以发送TCP/UDP报文。这个版本就是在PPPOE交互时,需要NK向一个公网IP发送一段TCP/UDP密文,否则PPPOE交互不通过。
解决方法
版本1是需要用户手动输入账号密码的NK版本,防共享策略1~4
版本2是扫码版NK,防共享策略1~5
1. 不为路由器分配公网IP地址
既然NK把宽带账号加密了,那我把加密后的账号得到,拿这个账号去进行PPPOE拨号,一样会通过验证。
那么,如何得到加密后的账号呢?
最初,反编译可以得到了NK的宽带加密算法,任何时间都可以算出当前的临时宽带账号。这么严重的问题不久就被NK修复了,他们更换了算法,并且做了反编译处理。
后来,也可以这么干。Windows系统有系统日志这个东西,每次PPPOE拨号后,系统都会将宽带账号/密码记录在日志中,所以只需要去读系统日志,就知道NK上一次是用何种宽带账号拨号。NK很快把这个漏洞补上了,每次拨号后,NK都会清除系统日志。
再后来,这个问题被有效解决了,使用PPPOE协议中间人劫持策略。
宽带账号/密码是通过PPPOE协议传送的,而且传送的宽带账号是明文的。
所以只要编程模拟与本机进行PPPOE握手、协商、会话,宽带账号/密码可以在会话中明文获取。
*PPPOE协议工作流程
- 发现阶段,有四个报文交互,分别是PADI、PADO、PADR、PADS,用来建立会话的。
- 协商阶段,用于协商使用何种方式进行验证宽带信息,一般有两种:PAP、CHAP。PAP方式明文传输账号、密码;CHAP方式明文传输账号,密码不会明文传输。
- 会话阶段,根据协商阶段约定的验证方式,进行宽带信息验证。验证通过会给你IP,不通过的话会返回原因。
Windows有个库叫WinPCAP,这个库可以捕获、发送链路层及以上的流量,路由器下的LAN是局域网,当计算机开始PPPOE拨号,第一条报文就是PADI,这是条广播报文,目的MAC为FF-FF-FF-FF-FF-FF,局域网下的所有设备都能接收到这条报文,包括本机。这时,本机的自己的程序捕获到PADI报文时,向自己的MAC地址发送PADO报文,开始后边一系列的PPPOE交互。
如果自己的程序冒充PPPOE服务器,总得有个MAC地址吧,如果就填本机真实的MAC地址,那PPPOE客户端(NK)自己发出去的报文,自己又收到,会误以为是PPPOE服务器回的报文,这样就容易误判,导致某个阶段失败,交互不能再进行下去。这样自己的程序声称的MAC就不能是本机真实MAC,得是别的随意什么MAC,这样的话PPPOE客户端往这个MAC发送报文,自己岂不收不到?想想,我不正监听着所有出去的流量么。
2. 不可输入的宽带账号
浏览器的文本框不能输入不可见字符,路由器的管理App也不能输入。所以要把劫持到的临时账号粘贴到路由器管理页面是行不通的。
但既然路由器采用网页作为管理方式,使用的协议必定是HTTP,HTTP报文可以承载不可见字符。所以只需要分析出拨号时发送的HTTP报文包体的结构,用带有不可见字符的临时账号替换掉原本HTTP包体的正常账号,将这个HTTP报文发给路由器,路由器就会执行此次拨号。
就我分析的结果来看,很多同系列的路由器的管理网页界面虽然有差异,但HTTP请求是基本一样的。但不同厂家的路由器,管理页面和HTTP请求是不尽相同的。有些路由器的安全性做的比较好,登录获取Session时,本地就用JS对密码做了加密,全程不传输明文密码。也有安全做的差的,基本是老款路由器,直接把路由管理密码明文放在HTTP报文的Auth头部或Cookies中。
3. 检测网络共享软件
这是防止PC本地使用网络共享的策略,如果直接使用路由器,路由器连上网后把NK关了就OK了,这个问题不需要关心。
4. 客户端存在检测
服务器靠心跳报文检测客户端是否存在,那一直开着NK不行吗?
还真不行,与NK进行PPPOE交互的是中间人代码,而不是PPPOE服务器,得到宽带账号后就PADT终止会话了,NK的表现会是PPPOE连接失败,不会进行下一步循环发送心跳报文的步骤,所以NK一直开着也没用。
那怎么办呢,这步只能硬杠了。找到NK心跳报文的算法和秘钥,用自己的程序定时发送心跳报文。
我观察了心跳密文的特征、NK运行时的内存,加上一点运气,得出了心跳的加密方式、加密密钥。
加密方式用的AES-ECB-PKCS7、密钥是"nk4*hr"开头的16位字符串,协议是QUIC,一种基于UDP的协议。心跳密文解密后是一些键值对,包括宽带账号、IP、MAC、NK客户端版本等。
5. 利用路由器的弱点
路由器不能一边拨号,一边发TCP/IP报文。PPPOE交互过程中,服务器未收到密文不能就通过交互,拨号即失败。所以必须想办法让路由器一边拨号,同时还让要让NK发送的密文顺利地传到服务器。
观察发现,密文要到达的地址是个公网IP,也就是说任何运营商网络都可以访问到,包括手机的流量。正好笔记本一般都会有两个网卡,有线网卡插网线,用于NK与上级交换机通信;无线网卡连手机热点,用于顺利传送PPPOE交互时的密文。
平时你可能发现了,笔记本在同时连上有线、无线网络时,流量只会走一个网卡,那么什么时候让走有线、什么时候走无线呢?
答案是设置 跃点数 ,这样可以让两个网卡同时工作。对了,Windows家庭版似乎不支持设置跃点数,但你知道原理是双网卡同时工作就行,并非一定要设置跃点数才能让两个网卡同时工作。
结束
OK,以上是我大学时课余的一些小研究,纰漏之处请指正。
学习过程中,感谢陈姓小哥的指点,并且钦佩你的品质!