Skip to content

Commit

Permalink
Add dynamic encryted version send in step 3 of handshake
Browse files Browse the repository at this point in the history
  • Loading branch information
tony1016 committed Jun 24, 2016
1 parent c0d873c commit 3c77b15
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 126 deletions.
123 changes: 1 addition & 122 deletions README.md
Original file line number Diff line number Diff line change
@@ -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产品。
69 changes: 65 additions & 4 deletions yah3c/eapauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
Expand All @@ -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
Expand Down Expand Up @@ -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')
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3c77b15

Please sign in to comment.