自己动手写H3C校园网登录客户端(Linux平台版)

自己动手写H3C校园网登录客户端(Linux平台版)

By 马冬亮(凝霜  Loki)

一个人的战争(http://blog.csdn.net/MDL13412)

        周一晚上的时候,和实验室的ZL同学提聊到了Android手机使用Wifi连接学校的无线网掉线的问题。由于我们学校的上网登录客户端仅支持Windows平台,在其他平台无法使用,所以,一直以来大家的解决方案就是使用浏览器进行登录。在Linux PC上使用网页登录还是很稳定的,但是一旦使用我的小平板(Android系统)登录的时候,就会在10分钟以内掉线。其实,早在一年前就想给我的Linux PC写一个登录的客户端,但是一直懒得去分析协议,这次经ZL同学一说,决定动手分析一下登录协议,写一个客户端给大家用。

        首先交代一下我的开发环境:

                操作系统:Fedora 16(Verne)

                内核版本:3.3.1-3

                浏览器:Google Chrome 17.0.963.79

                开发语言:Python(3.2)

                开发工具:Eclipse 3.7.1 (PyDev 2.2.4.2011110216)

                网络分析工具:WireShark 1.6.5

        下面开始分析登录协议,在gnome-terminal终端下使用root权限运行wireshark(注意:在Fedora上,必须要用root权限去运行wireshark才能设置网卡到混杂模式),如下图所示:


        接下来设置过滤器,点击菜单栏上的“Capture”->“Options”,弹出如下图所示的"Capture Options"对话框:


        单击“Capture Filter”按钮,弹出过滤器选择对话框,如下图所示:


        由于我是要分析网络客户端登录的数据包,所以用IP进行过滤是最佳选择,我们校园网验证的服务器地址为192.168.252.251,将其填入上图的"Filter string"选项中就可以进行过滤了。然后点击“确定”,在单击“Start”开始抓包。

        打开浏览器,输入http://192.168.252.251:8080/portal/index_default.jsp,这个地址是我们进行网页登录的首页。此时抓到的数据并不是我们想要的数据,填入帐号和密码,如下图所示:


        点击“上线”,开始查看数据包,经过分析,我找到的关键数据包如下图所示:


        我们在Line-based text data: application/x-www-form-urlencoded这项中看到了如下字段,userName=mdl_&userPwd=V1hYWVlESkowMDA%3D&isQuickAuth=false&language=Chinese&browserFinalUrl=&userip=null,很明显userName没有进行加密,而userPwd被加密了,为了得知加密算法,我修改了几次密码,并对其映射关系进行了分析,映射关系如下:

        AAA000                  QUFBMDAw
        000AAA                  MDAwQUFB
        000000A                MDAwMDAwQQ%3D%3D
        000000AA              MDAwMDAwQUE%3D
        000000AAA            MDAwMDAwQUFB
        000BBB                  MDAwQkJC
        000000B                MDAwMDAwQg%3D%3D
        000000BB              MDAwMDAwQkI%3D
        000000BBB           MDAwMDAwQkJC

        经过分析,这个加密算法是每3个字节加密一次,并且将其映射为4位ASCII字符,对于不足三位的用%3D填充,很明显了,这个是Base64加密。有了加密算法,还要分析Cookie字段Cookie: JSESSIONID=3D4B4FBA9E201DFEF973138DF52B5161; hello1=mdl_; hello2=false; hello3=; hello4=\r\n,对于记住密码和不记住密码,这个字段的内容是不同的,经过分析HTTP的流程,我发现Cookie的JSESSIONID是客户端Notify给服务器的,那么就给我们伪造Cookie提供了可能。

        经过分析,hello1字段是用户名,hello2字段是是否记住密码,hello3字段在记住密码的时候是一段经过加密的字符串,不记住密码的时候为空,hello4字段是登录的资费类型,我们学校没有使用到这个字段,所以始终为空。

        分析完这个数据包,我发现,帐号和密码验证成功后客户端又向服务器发送了如下的数据包:


        其中Cookie字段和上一个数据包一致,Line-based text data: application/x-www-form-urlencoded中language=Chinese&heartbeatCyc=240000&heartBeatTimeoutMaxTime=3&userDevPort=IAG_5000-vlan-02-0000%40vlan&userStatus=99&userip=null&serialNo=-19730&basip=这段后来经过分析,是同时post给本地和服务器的,客户端的在线页面也要接收一份此字段中的参数。

        接下来,我找到了心跳检测的数据包,这个是客户端主动发送给服务器的验证包,如下图:

           开始的时候我认为只要每隔一段时间向服务器GET这个数据包的内容,并且保持TCP长连接就可以不掉线了,但是经过验证,这是不可行的。后来又尝试模拟浏览器的所有行为,但是也没有成功。最后,想到在一台机器上如果帐号已经在线,再次发送的登录请求,服务器会返回用户已经在线信息,并重新设置掉线时间,于是突破点找到了,我每隔1分钟,向服务器发送一次登录请求,终于,可以保证稳定在线了。

        下面将我用Python写的客户端代码贴出来,给大家做一个参考,为了能最小负担的移植到其他平台,我将最初的PyQt4做的界面去掉了,还是使用了纯终端的程序:

        这个项目总共分为3个文件,config.ini保存用户的账户和密码,NsINodeLogin.py负责登录并维持在线,NsINodeLogout.py负责下线。

config.ini

[Account]
username:mdl_
password:MYPASSWORD
NsINodeLogout.py
# -*- coding: utf-8 -*-

welcomeInfo = '''
作者:马冬亮
单位:内蒙古科技大学信息工程学院ACM程序设计协会
博客:http://blog.csdn.net/MDL13412
邮箱:mdl2009@vip.qq.com
Q Q:401074567
版权所有 (C) 2012 凝霜.保留所有权利.

使用方法:
修改当前路径下的config.ini文件,将用户名和密码填写至相应字段
登录使用NsINodeLogin.py
注销使用NsINodeLogout.py
在线时请不要关闭本程序
'''

import http.client
import base64
import os
from configparser import ConfigParser

requesteaders = {
    'Connection':'keep-alive',
    'Cache-Control':'max-age=0',
    'User-Agent':'Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11',
    'Content-Type':'application/x-www-form-urlencoded',
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Encoding':'gzip,deflate,sdch',
    'Accept-Language':'zh-CN,zh;q=0.8',
    'Accept-Charset':'GBK,utf-8;q=0.7,*;q=0.3',
    'Cookie':''
}

if __name__ == '__main__':
    try:
        print(welcomeInfo)
        
        try:
            configFile = ConfigParser()
            configFile.read(filenames=os.getcwd() + '/config.ini', encoding='utf-8')
            username = configFile.get('Account', 'username')
            pwd = configFile.get('Account', 'password')
        except:
            print('加载用户信息错误')

        logoutBody = 'userName={0}&userPwd={1}&isQuickAuth=false&language=Chinese&browserFinalUrl=&userip=null'
        requesteaders['Cookie'] = 'JSESSIONID=F447CB1C348B7D7AA6C02CBA3ECBF7AF; hello1={0}; hello2=flase; hello3=; hello4='.format(username)
       
        pwd = base64.encodebytes(pwd.encode(encoding='utf_8', errors='strict'))
        pwd = pwd.replace('='.encode(encoding='utf_8', errors='strict'), '%3D'.encode(encoding='utf_8', errors='strict'))
        logoutBody = logoutBody.format(username, pwd)
        logoutBody = logoutBody.replace("b'", "")
        logoutBody = logoutBody.replace("\\n'", "")
        
        while True:
            conn = http.client.HTTPConnection('192.168.252.251:8080')
            conn.request('POST', '/portal/logout.jsp', logoutBody, headers=requesteaders)
            res = conn.getresponse()

            if res.status == 200:
                print('下线成功')
            else:
                print('下线失败')
    
            break
    except Exception as e:
        print('出错啦...请检查网络连接...')

NsINodeLogin.py

# -*- coding: utf-8 -*-

import http.client
import time
import base64
import os
from configparser import ConfigParser

requesteaders = {
    'Connection':'keep-alive',
    'Cache-Control':'max-age=0',
    'User-Agent':'Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.79 Safari/535.11',
    'Content-Type':'application/x-www-form-urlencoded',
    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Encoding':'gzip,deflate,sdch',
    'Accept-Language':'zh-CN,zh;q=0.8',
    'Accept-Charset':'GBK,utf-8;q=0.7,*;q=0.3',
    'Cookie':''
}

if __name__ == '__main__':
    try:
        os.system('python3 ./NsINodeLogout.py')
        
        try:
            configFile = ConfigParser()
            configFile.read(filenames=os.getcwd() + '/config.ini', encoding='utf-8')
            username = configFile.get('Account', 'username')
            pwd = configFile.get('Account', 'password')
        except:
            print('加载用户信息错误')

        loginBody = 'userName={0}&userPwd={1}&isQuickAuth=false&language=Chinese&browserFinalUrl=&userip=null'
        onlineBody = 'language=Chinese&heartbeatCyc=240000&heartBeatTimeoutMaxTime=3&userDevPort=IAG_5000-vlan-02-0000%40vlan&userStatus=99&userip=null&serialNo=15500&basip='
        requesteaders['Cookie'] = 'JSESSIONID=F447CB1C348B7D7AA6C02CBA3ECBF7AF; hello1={0}; hello2=flase; hello3=; hello4='.format(username)
       
        pwd = base64.encodebytes(pwd.encode(encoding='utf_8', errors='strict'))
        pwd = pwd.replace('='.encode(encoding='utf_8', errors='strict'), '%3D'.encode(encoding='utf_8', errors='strict'))
        loginBody = loginBody.format(username, pwd)
        loginBody = loginBody.replace("b'", "")
        loginBody = loginBody.replace("\\n'", "")
        
        while True:
            conn = http.client.HTTPConnection('192.168.252.251:8080')
            conn.request('POST', '/portal/login.jsp', loginBody, headers=requesteaders)
            res = conn.getresponse()

            if res.status == 200:
                print('发送验证信息成功')
                data = res.read()
                if -1 == data.find(b'3032'):
                    print('登录信息正确')
                else:
                    print('请检查登录信息')
                    break
            else:
                print('发送验证信息失败')
                continue
            
            conn = http.client.HTTPConnection('192.168.252.251:8080')
            conn.request('POST', '/portal/online.jsp', onlineBody, headers=requesteaders)
            res = conn.getresponse()
            
            if res.status == 200:
                print('发送在线信息成功')
            else:
                print('发送在线信息失败')
                continue

            time.sleep(60)
    except Exception as e:
        print('出错啦...请检查网络连接...')
        这个程序因为属于实验性的代码,没有进行详细的错误校验,不过对于校园网的登录来说,已经足够用了。

802.1x Supplicant for Linux 安装使用说明 安装 安装过程分为两个步骤,首先解开压缩包,然后执行安装文件。 解压缩 tar –xzvf h3c802.1xClient.tar.gz 执行安装文件 到展开的文件夹中执行 ./pre.ps 使用 用户可通过命令行的方式和程序进行交互。 配置用户信息 可以通过如下命令开始用户信息的配置: linux1x –c 发起网络认证 可以通过如下命令开始认证: linux1x [-u username[/password]] [-n netchar] [-d] [-p] 无参数 如果没有参数,则使用上次成功认证的参数 -u 后输入的应是用户名和密码 -n 后输入的应是认证网卡的名字,如eth0, eth1, eth2 等等 -d 标识程序以守护方式运行,通过认证后转到后台运行 -p 逐项提示用户输入需要的信息 例子: 用户想通过用户名为user1,密码为pass1,网卡eth0发起认证,可使用如下命令: (1) linux1x –u user1/pass1 –n eth0 (默认为在前台运行) (2) linux1x –u user1/pass1 –n eth0 –d (通过认证后转到后台运行) (3) linux1x –u user1/pass1 (在随后的提示中输入需要的信息) (4) linux1x (在随后的提示中输入需要的信息) (5) linux1x –p (不使用存储的用户认证信息,提示输入所有的需要的信息) 查看网络状态和本信息 可通过如下命令查看网络状态和本信息: linux1x –v [seconds] -v 后可输入想要显示的时间,以秒为单位 例子: 1. 用户想一直查看网络统计信息, 可使用如下命令: (1) linux1x –v (2) linux1x –v 0 2. 用户想查看一段时间的网络统计信息,如想查看5秒后退出,可使用如下命令: (1) linux1x –v 5 断开网络连接 用户可通过如下命令断开网络连接 linux1x –k -k 断开当前的网络连接 ----------------------------------------------------------------------------------------------------------- 上面这些是README的文档说明 我在ubuntu下就用这个联网的,最近很多人发邮件索取这个软件,貌似很多学校都不提供这个。我也没到论坛上搜索,不知道之前有没有人发上来过。 连网的时候可能需要libstdc++-libc6.2-2.so.3这个文件,一并在压缩包里了,将它拷贝到/usr/lib 目录下就好了。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值