From 3c77b1537c786f5dac873629f751d847072a3c21 Mon Sep 17 00:00:00 2001 From: "tl@linuxmint" Date: Fri, 24 Jun 2016 14:24:07 +0800 Subject: [PATCH] Add dynamic encryted version send in step 3 of handshake --- README.md | 123 +---------------------------------------------- yah3c/eapauth.py | 69 ++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 126 deletions(-) diff --git a/README.md b/README.md index 049ac63..40dabb2 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,3 @@ YaH3C ===== - -YaH3C 是用于校园网认证的客户端,支持中山大学东校区。 - -感谢 [lpy](https://github.com/lpy) 为 OS X 提供的[版本](https://github.com/lpy/Yah3c)。 - -为什么不用iNode ---------------- - -* i开头完全是对Apple的侮辱嘛 = = -* 强制添加启动项 -* gui和cli使用的udp交互,很多时候Linux/Mac下掉线完全是因为实现的效率太低 -* 安装脚本居然是自删除的 -* 默认强制记录日志文件,增加CPU负载,减少硬盘寿命,一段时间后就过GB了(是否有敏感信息不得而知了) -* Linux下仅仅支持Ubuntu 32位系统 -* Mac下安装后居然要重启 -* 使用的第三方库乱放和HomeBrew冲突 - -依赖 ------------- - -* 主流Linux发行版,包括OpenWrt/DD-WRT -* Python2 - -安装 ------------- - -首先,从github上下载,可以直接利用`git clone`,也可以下载压缩包自己解压然后安装。下面以git为例,如果没有则需要先安装: - -```bash -# Ubuntu/Debian -sudo apt-get install git - -# ArchLinux -sudo pacman -S git -``` -然后,从项目中clone下来并安装 - -```bash -git clone git://github.com/humiaozuzu/YaH3C.git -cd YaH3C -sudo python setup.py install -``` - -**ArchLinux**默认安装的python是python3,你需要手动安装python2。 - -使用 ----- - -完整的联网过程有2步,首先使用本客户端通过交换机的认证,然后获取ip。 - -### 认证 - -程序运行时必须要有root权限: - -```bash -sudo yah3c -``` - -根据程序的提示输入账号密码就可以开始认证了,有些选项如果看不懂请直接按`Enter`。 - -### 获取ip - -因为YaH3C仅仅是**认证**客户端,所以通过认证后你需要自己获取ip联网,不过为了方便还是添加了dhcp支持。 - -如果没有指定dhcp的命令,你可以在认证成功后使用自己喜欢的网络管理工具获取IP,如NetworkManager或Wicd。 - -YaH3C支持基本的命令行参数,执行`yah3c -h`可以看到支持的命令行参数 - -``` bash -$ yah3c -h -usage: yah3c [-h] [-u USERNAME] [-debug] - -Yet Another H3C Authentication Client - -optional arguments: - -h, --help show this help message and exit - -u USERNAME, --username USERNAME - Login in with this username - -debug Enable debugging mode -``` - -如执行`sudo yah3c -u Maple`可以自动认证`Maple`这个帐号 - -配置文件格式 ---------- -用户的登陆信息按照如下的格式保存在文件`/etc/yah3c.conf`中: - -``` ini -[account] # 你的帐户 -password = 123456 # 密码 -ethernet_interface = eth0 # 使用的网卡,默认为eth0 -dhcp_command = dhcpcd # 验证成功后使用的dhcp命令(dhcpcd/dhclient),默认为空 -daemon = True # 验证成功后是否变成daemon进程,默认为是 -``` - -ScreenShots ------------ - -认证成功: - -![success](https://raw.github.com/humiaozuzu/YaH3C/master/screenshots/success.png) - -认证失败: - -![failure](https://raw.github.com/humiaozuzu/YaH3C/master/screenshots/failure.png) - - -Todo ----- -* ~~添加BSD BPF 支持,这样在OS X也可以使用了~~ -* 完善收集调试信息的功能,方便用户提交认证信息 -* 完善对H3C协议的支持 - -Thanks ------- -* [qiao](https://github.com/qiao) - Write python installation script for YaH3C -* [houqp](https://github.com/houqp) - Refered to houqp's [pyh3c](https://github.com/houqp/pyh3c) -* [tigersoldier](https://github.com/tigersoldier) - Write EAP-Md5 for YaH3C - -License -------- -YaH3C的代码使用MIT License发布,此外,禁止使用YaH3C以及YaH3C的修改程序用于商业目的(比如交叉编译到路由进行销售等行为) +在原工程的基础上,增加了iNode版本动态加密上传的feature,弥补了协议的不足。原版本中,该version是写死的,不适用于我司的iNode产品。 diff --git a/yah3c/eapauth.py b/yah3c/eapauth.py index f5fdac2..7d5abd1 100644 --- a/yah3c/eapauth.py +++ b/yah3c/eapauth.py @@ -8,7 +8,7 @@ __all__ = ["EAPAuth"] import socket -import os, sys, pwd +import os, sys, pwd,random,struct,base64,logging from subprocess import call from colorama import Fore, Style, init @@ -28,6 +28,9 @@ def display_packet(packet): print '\tType: ' + repr(packet[12:14]) class EAPAuth: + H3C_VERSION="EN V5.20-0408" + H3C_KEY="HuaWei3COM1X" + def __init__(self, login_info): # bind the h3c client to the EAP protocal self.client = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETHERTYPE_PAE)) @@ -37,7 +40,8 @@ def __init__(self, login_info): self.ethernet_header = get_ethernet_header(self.mac_addr, PAE_GROUP_ADDR, ETHERTYPE_PAE) self.has_sent_logoff = False self.login_info = login_info - self.version_info = '\x06\x07bjQ7SE8BZ3MqHhs3clMregcDY3Y=\x20\x20' + # self.version_info = '\x06\x07bjQ7SE8BZ3MqHhs3clMregcDY3Y=\x20\x20' + self.version_info="\x06\x07"+self.encryptH3cVersion()+"\x20\x20" def send_start(self): # sent eapol start packet @@ -122,7 +126,7 @@ def EAP_handler(self, eap_packet): else: display_prompt(Fore.YELLOW, 'Got EAP Failure') - #self.display_login_message(eap_packet[10:]) + self.display_login_message(eap_packet[10:]) exit(-1) elif code == EAP_RESPONSE: display_prompt(Fore.YELLOW, 'Got Unknown EAP Response') @@ -132,7 +136,7 @@ def EAP_handler(self, eap_packet): if reqtype == EAP_TYPE_ID: display_prompt(Fore.YELLOW, 'Got EAP Request for identity') self.send_response_id(id) - display_prompt(Fore.GREEN, 'Sending EAP response with identity = [%s]' % self.login_info['username']) + display_prompt(Fore.GREEN, 'Sending EAP response with identity = [%s] and version = [%s]' % (self.login_info['username'],self.version_info[2:-2])) elif reqtype == EAP_TYPE_H3C: display_prompt(Fore.YELLOW, 'Got EAP Request for Allocation') self.send_response_h3c(id) @@ -165,6 +169,63 @@ def serve_forever(self): print "Connection error: %s" %msg exit(-1) + def encryptH3cVersion(self): + # generate 32bit random int + randomInt=random.getrandbits(32) + + # transform the int to 8 bytes hex string + randomKey="%08x"%randomInt + logging.debug("[randomKey]"+':'.join(x.encode('hex') for x in randomKey)) + + # generate 16 bytes message + data=EAPAuth.H3C_VERSION+chr(0)+chr(0)+chr(0) + + # the 1st time encryt data with randomKey + data=self.XOR(data,randomKey) + logging.debug("[data after the 1st time encrypt]"+':'.join(x.encode('hex') for x in data)) + + # transform host number to network number + randomInt=socket.htonl(randomInt) + logging.debug("[htonl random]:%x"%randomInt) + + # append 4 bytes random int to data + data=data+struct.pack(">I", randomInt)[::-1] + + # encrypt data with H3C_KEY + data=self.XOR(data,EAPAuth.H3C_KEY) + logging.debug("[data after the 2nd time encrypt]"+':'.join(x.encode('hex') for x in data)) + + # return data encrypt with base64 + data=base64.b64encode(data) + logging.debug("[data return in base64]"+':'.join(x.encode('hex') for x in data)) + logging.debug("[that is]"+data) + + return data + + def XOR(self,dataString,keyString ): + logging.debug("[dataString]"+':'.join(x.encode('hex') for x in dataString)) + logging.debug("[keyString]"+':'.join(x.encode('hex') for x in keyString)) + + + # forward order xor + newData="" + for i in range(0,len(dataString)): + newData+=chr(ord(dataString[i])^ord(keyString[i%len(keyString)])) + dataString=newData + logging.debug("[dataString after forward xor]"+':'.join(x.encode('hex') for x in dataString)) + + + # inverse order xor + newData="" + for i in range(0,len(dataString)): + newData+=chr(ord(dataString[len(dataString)-1-i])^ord(keyString[i%len(keyString)])) + newData=newData[::-1] + logging.debug("[dataString after inverse xor]"+':'.join(x.encode('hex') for x in newData)) + return newData + + + + def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): '''This forks the current process into a daemon. The stdin, stdout, and