-
Notifications
You must be signed in to change notification settings - Fork 16
Description
基础
前言
本教程的主要目的是帮助 inode 5.X 与 inode 7.X 版本的受害者,可以通过自己对最终编译出适合自己学校的 nxhsarp 及 njit8021xclient 程序。更明确的说,在inode 5.X 后期版本中,引入了一种验证选项,在开启本选项后,会激活一套私有的“挑战-应答”机制,利用该机制可以检验用户是否在使用官方版本的inode。而现在的工作就是,如何在 nxsharp / njit8021xclient 中复原这一机制,对不同的挑战请求,返回正确的答案,通过交换机的验证,避免被交换机踢下线。
本项目用于辅助对虚拟机、linux 和 openwrt的学习和使用,请勿用于非法用途。
inode 防御机制简介
截至目前已知情况,inode对用户请求的验证具有四层机制:
- 正常的 802.1x 验证机制。对于此机制,需要实现基本的802.1x验证客户端。
- inode 与标准 802.1x 协议不符的行为机制。严格来说,这并不是一种验证机制,但确实也挡住了一系列标准的 802.1x 客户端。对于此机制,需要根据 wireshark 抓包分析完全根据官方 inode 的行为模式,进行模拟。俗话来说,就是“他干啥我也干啥”。对于此问题,已经有很多优秀的博客文章对其进行分析:
iNode协议逆向研究初步入门
民间 H3C inode 客户端黑历史 - inode 私有的客户端版本验证算法。在此需要强调的是,目前挡在大多数第三方客户端面前的障碍即为本机制。此版本验证算法需要输入一个客户端版本号,而这个版本号在不同学校并不相同。这也是你随便去网上找一个 njit8021xclient 却没法使用的最大原因。因为你需要将自己学校的版本号定制进去才可以正常工作。
目前此机制已经由 AGanNo2 / liuqun 等前辈完全解析并实现在njit8021xclient中,在此向各位前辈致敬。此算法的具体原理参见:inode版本号加密/解密 。
同时为了辅助大家更方便完成版本号的提取,我在 H3C_toolkit 项目中提供了 version_sniffer 小工具,希望可以给大家做一点微小的帮助。 - inode 所谓的“客户端完整性校验”。如果您确认在完成以上三层验证机制(尤其是第三条)的基础上,依然无法正常上网,那么你可能要面对的就是此挑战。这也是本教程的最大目的。
神奇“客户端完整性校验”在哪里?
“客户端完整性校验”其实是一种“挑战-应答”机制,即交换机发来一个问题,你的inode会返回一个答案,如果答案正确,那么即通过验证。因此,我们就要找到“问题”在哪里,以及“答案”在哪里。
请打开您的 wireshark 抓包工具,将过滤器设置为eapol
然后启动官方inode完成认证登录。
请关注您的抓包结果中标为Unknown Code(0x0A)
的数据包,依次打开这些数据包(如果有多个0x0A数据包,那么以最新的为准),凭肉眼,你可能会发现一串以 2b 35 为起始的字段,该字段长度为32位。
下图为0x0A数据包:
下图为“问题”字段:
如果您找到这样的一串字段,那么恭喜你,贵校已经启用了“客户端完整性校验”。上述32位的序列即为交换机发来的“问题”,它正等待您的客户端返回一个正确的回复呢。
既然“问题”来了,那么答案在哪里呢?请选择0x0A数据包之后的 Response,Identity
数据包,观察是否存在一个以 16 20 为起始的32位字段。这就是inode发回给交换机的响应答案。
再次啰嗦下,请确认你确实抓到'16 20'起始的数据了,才需要看后面的内容,不然后来发现贵校根本就启动“客户端完整性校验”,那岂不是白花精力了。
“客户端完整性校验”是如何工作的
我们已经发现了inode的“客户端完整性校验”在哪里,那么问题的核心就是:inode 客户端是依赖什么样的算法生成的应答序列,才能通过交换机验证的。
一个好消息是,在很久以前的探索中,我已经替大家还原出了其生成算法,暂命名为h3c-AES-MD5算法。该算法原理具体请参考:AES-MD5验证算法。另外我已经将这一算法以C语言实现在我的 nxsharp / njit8021xclient 客户端中了,所以你不用再造一遍轮子了。
坏消息来了。如果你深入看了上述的 h3c-AES-MD5 算法,那么你就会发现里面有一个叫“字典查找”的东东,顾名思义,你得拥有一本字典,才能查找出对应的内容。对不同的学校,这本字典是不同的,所以你又不能直接使用现成的客户端了。更大的困难是,这样的字典并不是一个单独的文件,而是藏在inode客户端程序自身的代码中的,所以你需要通过二进制分析工作,才能提取出这样的字典,而这一工作颇有难度,并需要一定的工作量和细心。
字典查找简要原理
此处我们抛开 inode 的实现机制,仅以我的 nxsharp / njit8021xclient 客户端中实现为例说明。
首先我在 h3c_AES_MD5.c 字典查找函数原型为:
char* get_sig(uint32_t index, int offset, int length, unsigned char* dst)
其中输入的参数包括:一个四位的 index 参数,这个就是查字典所查的“单词”;一个 offset ,这个参数指明的是你需要查找序列的初始偏移量,比喻来说就是我查到一个单词,然后从解释这个单词的第 offset 个字字母开始读取;然后是 length,即读取多长的序列;这样的一个查询结果是什么呢?就是一个长度为 length 的16进制序列而已。最后,将上述结果存储在 dst 指示的位置处。
我的字典查找函数核心算法很 naive :
switch (index_tmp)
{
case 0x15D0EADF:base_address = x15D0EADF; break;
case 0x09F40DE7:base_address = x09F40DE7; break;
case 0x189DF2CE:base_address = x189DF2CE; break;
. . .
以C语言基础理解就是,如果输入一个 index 等于某个值的话,那么就把基地址设给这个值所对应的数组。请注意,上述代码中0x15D0EADF
为一个4位的数值,而x15D0EADF
为一个数组的名。这就是最简单的查字典过程嘛,0x15D0EADF
就是要查的单词,x15D0EADF
就是单词释义所在的位置。
这样的单词是在哪里存储的呢?请参考:h3c_dict.h。在这里你能看到40组不同的数组,其命名与前文 switch
语句中的查字典过程一一对应,而其内容为256字节长度的16进制序列,就是字典值。
如何构造自己的字典?
首先说如何“做字典”,我们先假设你通过神奇的手段取得了字典内容,那么你需要做的工作是:
- 修改
h3c_dict.h
,以相同的格式,将字典的键值和对应的序列内容添加到此文件中; - 修改
h3c_AES_MD5.c
,把你获取的键值以相同的格式添加到switch
语句中。
这样你的字典才能正常工作。
那么如何才能获取字典的内容呢?如上文所说,字典是隐藏在 inode 可执行文件代码自身之中的。这一分析过程很繁琐,因此我在分别对于 inode 5.X 及 inode 7.X 通过视频教程讲解。