admin管理员组

文章数量:815331

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

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

By 马冬亮(凝霜  Loki)

一个人的战争()

        周一晚上的时候,和实验室的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程序设计协会
博客:
邮箱: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 ConfigParserrequesteaders = {'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('下线失败')breakexcept Exception as e:print('出错啦...请检查网络连接...')

NsINodeLogin.py

# -*- coding: utf-8 -*-import http.client
import time
import base64
import os
from configparser import ConfigParserrequesteaders = {'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('请检查登录信息')breakelse:print('发送验证信息失败')continueconn = 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('发送在线信息失败')continuetime.sleep(60)except Exception as e:print('出错啦...请检查网络连接...')
        这个程序因为属于实验性的代码,没有进行详细的错误校验,不过对于校园网的登录来说,已经足够用了。

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