这个脚本写起来难度并不是很大,博主还是一步步的分析下,这样思路会比较清晰,下次遇到类似系统脚本写起来也更快速。好了,一起来分析分析。

首先看下小米路由器的登录界面

可以看到只需要输入密码即可登录,博主这里为了演示,设置了简单的登录密码12345678,使用firebug记录登录的请求。当然,这里也可以使用Burp拦截请求,只不过有点大材小用了,来,我们尝试登录一下,看下做了哪些请求,使用正确的密码进行登录,post到服务端的数据如图所示

从图上很明显的可以看到,post了4个参数到这个地址:http://192.168.65.1/cgi-bin/luci/api/xqsystem/login 进行登录操作。

参数 username 的值为admin,这个很明显就是一个内置的用户名,也就是默认的用户名,所以页面只需要输入密码就可以正常登录。

参数 password 一眼看上去应该是个MD5加密后的密文

参数 logtype 的值为2,这个应该也是系统默认内置的一个登录类型

参数 nonce 看起来应该是 mac地址加时间戳加随机数的组合

登录成功之后的响应如图

上面对参数含义的推测不一定准确,为了了解真正的含义,博主决定去代码里面一探究竟,查看页面源代码,找到了处理登录的方法

function loginHandle ( e ) {

e.preventDefault();

var formObj = document.rtloginform;

var pwd = $( '#password' ).val();

if ( pwd == '') {

return;

}

var nonce = Encrypt.init();

var oldPwd = Encrypt.oldPwd( pwd );

var param = {

username: 'admin',

password: oldPwd,

logtype: 2,

nonce: nonce

};

$.pub('loading:start');

var url = '/cgi-bin/luci/api/xqsystem/login';

$.post( url, param, function( rsp ) {

$.pub('loading:stop');

var rsp = $.parseJSON( rsp );

if ( rsp.code == 0 ) {

var redirect,

token = rsp.token;

if ( /action=wan/.test(location.href) ) {

redirect = buildUrl('wan', token);

} else if ( /action=lannetset/.test(location.href) ) {

redirect = buildUrl('lannetset', token);

} else {

redirect = rsp.url;

}

window.location.href = redirect;

} else if ( rsp.code == 403 ) {

window.location.reload();

} else {

pwdErrorCount ++;

var errMsg = '密码错误';

if (pwdErrorCount >= 4) {

errMsg = '多次密码错误,将禁止继续尝试';

}

Valid.fail( document.getElementById('password'), errMsg, false);

$( formObj )

.addClass( 'shake animated' )

.one( 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function(){

$('#password').focus();

$( this ).removeClass('shake animated');

} );

}

});

}

很容易就能明白代码的意思,博主稍微精简下,登录地址为

/cgi-bin/luci/api/xqsystem/login

参数为

var param = {

username: 'admin',

password: oldPwd,

logtype: 2,

nonce: nonce

};

password参数对应到oldPwd,找到oldPwd的生成方法

var oldPwd = Encrypt.oldPwd( pwd );

而nonce的生成方法也很容易找到

var nonce = Encrypt.init();

这两个参数都是由

Encrypt

这个类里面的方法生成的,找到这个类即可。而在登录的方法中还有个登录次数的限制,很显然,这个登录的次数也只是js变量控制的,并不是后端限制,很鸡肋,依然可以无限次登录。

找到上面两个参数的生成方法

var Encrypt = {

key: 'a2ffa5c9be07488bbb04a3a47d3c5f6a',

iv: '64175472480004614961023454661220',

nonce: null,

init: function(){

var nonce = this.nonceCreat();

this.nonce = nonce;

return this.nonce;

},

nonceCreat: function(){

var type = 0;

var deviceId = '00:88:65:3d:bd:22';

var time = Math.floor(new Date().getTime() / 1000);

var random = Math.floor(Math.random() * 10000);

return [type, deviceId, time, random].join('_');

},

oldPwd : function(pwd){

return CryptoJS.SHA1(this.nonce + CryptoJS.SHA1(pwd + this.key).toString()).toString();

},

newPwd: function(pwd, newpwd){

var key = CryptoJS.SHA1(pwd + this.key).toString();

key = CryptoJS.enc.Hex.parse(key).toString();

key = key.substr(0, 32);

key = CryptoJS.enc.Hex.parse(key);

var password = CryptoJS.SHA1(newpwd + this.key).toString();

var iv = CryptoJS.enc.Hex.parse(this.iv);

var aes = CryptoJS.AES.encrypt(

password,

key,

{iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }

).toString();

return aes;

}

};

也是相当简单,值得注意的是这里生成的密码并不是MD5,而是由CryptoJS 这个库生成的可逆的密文,这跟我上面的推测有些差异,,nonce的生成在这段代码里面

var type = 0;

var deviceId = '00:88:65:3d:bd:22';

var time = Math.floor(new Date().getTime() / 1000);

var random = Math.floor(Math.random() * 10000);

return [type, deviceId, time, random].join('_');

类型+设备的mac地址+时间戳+10000以内的随机数,中间用下划线隔开。

搞明白每个参数的生成方法后模拟登录写起来可就简单多了。

利用requests模块进行登录,这里重点需要说明下密码的生成过程

CryptoJS.SHA1(this.nonce + CryptoJS.SHA1(pwd + this.key).toString()).toString();

密码+后端返回的一个key进行一次SHA1加密,转换成字符串之后与nonce相加再进行一个SHA1加密,最后进行一次字符串的转换就的到最终的密文。

好了,分析到这我们都已经清楚整个参数生成的原理,现在就要开始写Python了,首先需要知道要用哪些模块

运行脚本的时候需要直接带参数,所以需要sys模块

生成时间戳需要time模块

发送http请求需要requests模块

生成随机数需要random模块

接收服务端返回的数据并解析需要json模块

正则匹配获取key需要re模块

SHA1加密需要pycrypto模块

博主这里是Linux环境,自带的Python缺少requests模块,需要安装,具体安装方法不再累述

关于pycrypto模块的使用,可以参考链接 http://pythonhosted.org/pycrypto/

好了,下面开始脚本的编写,首先需要做的就是获取那个key,因为生成密码的时候要用到,这个key在登录页面初始化的时候就已经生成了,所以直接使用requests的get方法取回页面进行匹配就可以得到key,代码如下

host = sys.argv[1]

homeRequest = requests.get('http://'+ host +'/cgi-bin/luci/web/home')

key = re.findall(r'key: \'(.*)\',',homeRequest.text)[0]

这里的host直接由参数获得,请求回来的数据使用re进行匹配得到key,接着生成nonce,要用到time模块和random模块。

观察nonce生成规则发现所需要的mac地址真是本机的mac地址而不是路由器的mac,推测是在连接路由器的时候路由器就已经获取到的,登录页面初始化的时候会返回获取到的本机地址,所以直接从页面上抓取mac地址就可以了,同样适用re模块进行匹配

mac = re.findall(r'deviceId = \'(.*)\';',homeRequest.text)[0]

接下来就把获取到的mac地址带入拼接就可以生成nonce参数

nonce = "0_"+ mac +"_"+ str(int(time.time())) +"_"+str(random.randint(1000,10000))

有了nonce和key,那么生成密码的密文也就比较容易,两次SHA1加密就可以了,代码也很简单

pwdtext = sys.argv[2]

pwd = SHA.new()

pwd.update(pwdtext+key)

hexpwd1 = pwd.hexdigest()

pwd2 = SHA.new()

pwd2.update(nonce+hexpwd1)

hexpwd2 = pwd2.hexdigest()

原始明文密码直接由参数获得,密码生成之后进行param的组合,一般博主直接用一个json对象来把参数集合在一块,就像这样

data = {

"logtype":2,

"nonce":nonce,

"password":hexpwd2,

"username":"admin"

}

好了,参数都有了,咱们直接传过去吧,记得是post哦,代码如下

response = requests.post(url=aimurl,data=data,timeout = 5)

resjson = json.loads(response.content)

if resjson['code'] == 0:

print 'Login Success! Token is '+resjson['token']

else:

print 'Login Failed! Code is '+str(resjson['code'])

对于返回的数据,之前查看过是json格式,那么直接使用json模块进行解析即可,code返回0则为成功,会得到一个token,code为其他则失败,来看下运行截图

登录成功

登录失败

好了,到这咱们就已经成功实现了使用Python进行快速登录小米路由器的功能,下次咱们接着写,如何使用Python来对小米路由器进行设置和重启等。

补充

更多功能的脚本在 http://www.92ez.com/?action=show&id=23405

本文链接:https://www.92ez.com/?action=show&id=23373

!!! 转载请先联系non3gov@gmail.com授权并在显著位置注明作者和原文链接 !!! 小黑屋

提示:技术文章有一定的时效性,请先确认是否适用你当前的系统环境。

路由器运行python脚本_写个Python脚本来登录小米路由器相关推荐

  1. python 基于unittest写接口自动化脚本

    已过时.如感兴趣,请移步这篇文章 https://blog.csdn.net/tomoya_chen/article/details/121550706 python 基于unittest写接口自动化 ...

  2. 小米路由器3是基于linux,XiaomiRouter自学之路(12-改造小米路由器3使之支持spi启动)...

    题图:gratisography XiaomiRouter自学之路(12-改造小米路由器3使之支持spi启动) 上一章节已经说到小米路由器mini的Uboot.Openwrt都能够正常的启动了,现在想 ...

  3. python能写什么脚本_你用 Python 写过哪些牛逼的程序/脚本?

    原标题:你用 Python 写过哪些牛逼的程序/脚本? [导读]:有网友在 Quora 上提问,「你用 Python 写过最牛逼的程序/脚本是什么?」.本文摘编了 3 个国外程序员的多个小项目,含代码 ...

  4. python编写一个程序、实现文件的复制_写个python 脚本实现文件的递归拷贝

    <派森>(Python)3.13 win32 英文安装版 类型:编程工具大小:21M语言:英文 评分:8.7 标签: 立即下载 今天翻电脑时突然发现有个存了很多照片和视频的文件夹,想起来是 ...

  5. ctypes安装_用python amp; bat写软件安装脚本 + HM NIS Edit自动生成软件安装脚本

    2019-03-11更新:原来NSIS脚本也可以禁用64位文件操作重定向的! 1.在安装脚本的开始处定义 LIBRARY_X64. !include "MUI.nsh" !incl ...

  6. python如何运行脚本_怎么执行python脚本文件

    1.脚本式编程 将如下代码拷贝至 hello.py文件中:print ("Hello, Python!");python学习网,大量的免费python视频教程,欢迎在线学习! 通过 ...

  7. anaconda怎么运行python程序_第一个python程序,从安装python环境到人生第一个py脚本运行全过程...

    文章目录 前言一.安装python运行环境 1.官网https://www.python.org下载安装包.exe 2.安装python二.python模块下载 1.配置pip环境变量 2.下载pyt ...

  8. python写一个服务_写一个Python的windows服务

    1. 安装pywin32和pyinstaller pip install pywin32 pip install pyinstaller 2.写一个服务Demo # -*- coding: utf-8 ...

  9. python编写接口自动化脚本_简单的python http接口自动化脚本

    摘抄:今天给大家分享一个简单的python脚本,使用python进行http的接口测试,脚本很简单,逻辑是:读取excel写好的测试用例,然后根据excel中的用例内容进行调用,判断预期结果中的返回值 ...

最新文章

  1. URI、URL以及URN的区别
  2. (function() {})();和(function(){}())
  3. PMCAFF推出咖啡日报 更多好内容等你来发现
  4. vnc服务器和客户端怎么配置文件,VNC服务器端与客户端配置
  5. Zabbix 企业级监控_
  6. Android studio3.0打开Device File Explore(文件管理器)的方法(图文教程)
  7. if嵌套while循环语句_Python学习笔记015--while循环嵌套
  8. 2018.09.28 hdu5435A serious math problem(数位dp)
  9. 到了姥姥家我在小点点c++
  10. 英世曼 | 动量是否具有行为性?
  11. 【遥感图像预处理方法】
  12. 加州大学计算机系统,盘点:美国加州大学系统值得申请的专业
  13. 边缘的容器化 — WasmEdge 与 seL4
  14. 医疗器械软件 软件生存周期过程
  15. Android Studio不使用数据线调试adb
  16. 鸿蒙系统和海思系统有什么区别,鸿蒙系统和安卓系统 到底有什么区别?
  17. daas 数据即服务_什么是daas
  18. 【Linux驱动编程】Linux中断上半部和下半部
  19. AlexNet模型详细分析
  20. 稳稳压二极管原理及主要参数

热门文章

  1. Rocksdb 的优秀代码(二)-- 工业级 打点系统 实现分享
  2. leetcode-452 用最少数量的箭引爆气球
  3. 「欧拉定理」学习笔记(费马小定理)
  4. 【LeetCode】136. Single Number 解题小结
  5. CrackMe_001
  6. Vim----ma6174
  7. spring springboot springcloud常用注解
  8. Redis安装与调试
  9. 最简便的清空memcache的方法
  10. 提供前进、后退功能及其他JAVASCRIPT速成秘诀