很多人看到标题可能会疑惑为什么要写这个路由器的登录过程?一般来说路由器的登录不都是
使用的HTTP头来确认是否为管理员的吗?但是很不幸,TP这个公司为路由器新开发的固件里面并未
使用HTTP头来认证,而是用了POST方法,理论上来说会比HTTP头的认证过程更加安全,但是这
对一心想黑你路由器的黑客来说并没有什么卵用,还不如刷个OpenWRT然后用SSH。好了扯远了,
来说下这个路由器的登录过程的不同吧。
我自己没有这个路由器,找朋友借的路由器,借来后上电连LAN,开IE用HttpWatch开始抓包
从进入登录界面到成功登录的界面的过程所获取的包如下图
先看第一个请求,其内容为
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>TL-WR886N</title>
<meta name="MobileOptimized" content="240">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=0.5, maximum-scale=2.0, user-scalable=yes">
<link rel="Shortcut Icon" href="../web-static/images/icon.png" type="image/jpeg" />
<link rel="stylesheet" href="../web-static/dynaform/class.css"></link>
<script type="text/javascript" src="../web-static/dynaform/class.js"></script>
</head>
<body>
<div id="Error"></div>
<div id="Confirm"></div>
<div id="Con"></div>
<div id="Help"></div>
<div id="Cover"></div>
<div id="Login"></div>
<script type="text/javascript">
var gBeInCNA = "NO";
pageOnload();
</script>
</body>
</html>
顿时懵逼了,什么鬼?连个按钮都没有,就几张图片,然后几个div,登录界面可是有输入框和按钮的
好吧,暂且先不管这个,先看看POST登录过程
密码加密了,为"o2Qg443HtTefbwK",在意料之中,应该是Base64加密吧,来试试看吧
Oh, Shit。竟然不是Base64加密,那会是怎么加密的?那就往上找看有没有加密的函数,上面有好几个JS,还有两个
htm文档,先看看Content.htm,里面就一个JSON对象,
{"error_code":-40401, "data":{"code":-40407,"time":20,"group":0}}
也看不出什么东西来,然后看看Login.htm
好像出现button了,但是好像也找不到对应的响应方法,再看看JS,好像唯一一个和身份认证有关的就是Verify.js了,
在里面找了半天也没有找到,好像这里面的是确认参数是否正确的函数,到这里基本上想不出其它办法来找出加密
函数了,于是到网上去搜搜看有没有人用程序登录过WR886N,但是百度一搜基本上都是什么如何设置WR886N的
根本没有用程序登录WR886N的。
没办法了,并且已经到了饭点,于是先去吃饭,回来再看看有没有其它办法来获取加密算法。吃完饭后又到网上
改变关键字搜,发现了可以使用谷歌浏览器的开发者工具动态调试网页,由于以前根本没有用过谷歌浏览器的开发者
工具,于是搜了篇教程,开始尝试调试路由器网页,终于让我发现了一点点蛛丝马迹
发现了一个"c.extend.auth",应该这个方法就是加密的方法了,于是到这个JS里面开始寻找"auth"
发现有两处,上面图片中的是auth的定义,并且这里出现了“$.sendAjaxReq("",{method:"do",login:{password:a}},”
这明显和POST数据一样,再看另一处auth的调用
可以明显看到这里的调用的三个形参为"$.pwd",一个很长的函数,然后是"c";$.pwd,从表面上看就是密码了
,但是再返回去看auth的定义发现其实是加密了的密码,因为auth的定义中出现的“$.sendAjaxReq("",{method:"do",login:{password:a}},”中a对应于第一个参数,所以$.pwd是加密后的密码,既然已经有了加密后的密码,那就去看pwd的定义吧
里面应该有加密函数
然而却扑了个空,pwd的定义直接是空字符串,那就只有找找pwd的调用了,应该是在某个调用中改变了pwd的值,
有5个pwd的调用,后来把目标锁定在了这个setLgPwd函数的定义里
因为其他调用都只是返回pwd或是将pwd和其他值比较而已,这有这里赋了值,然后又寻找setLgPwd函数的调用
发现了两个$.setLgPwd(""),一个$.setLgPwd(a),一个$.setLgPwd(c),以及一个$.setLgPwd(orgAuthPwd(b))
嗯,一看这个orgAuthPwd(b)好像就有戏,于是又继续找orgAuthPwd的定义
他的定义竟然是又调用一个函数securityEncode,于是又找securityEncode的定义
securityEncode:function(a,b,c)
{
var e="",f,g,h,k,l=187,n=187;
g=a.length;
h=b.length;
k=c.length;
f=g>h?g:h;
for(var p=0;p<f;p++)
n=l=187,
p>=g?n=b.charCodeAt(p):p>=h?l=a.charCodeAt(p):(l=a.charCodeAt(p),n=b.charCodeAt(p)),e+=c.charAt((l^n)%k);return e},
最终发现了加密代码,坑爹的TP,把加密方法放得这么深,特么我都找了几个来回了,这个代码可能不会JS的人不太清楚
其流程,我因为主要使用C#,所以将其转换为C#代码并带了注释,代码如下
//a:短验证码
//b:密码
//c:长验证码
public string securityEncode(string a,string b,string c)
{
string e="";
int f,g,h,k,l=187,n=187;
g=a.Length;//短验证码的长度(固定为15)
h=b.Length;//密码长度
k=c.Length;//长验证码的长度(固定为255)
if(g>h)//将短验证码字符串和密码字符串的长度进行比较
{
f = g;
}
else
{
f = h;
}
//f取长的那个字符串的长度
for(int p=0;p<f;p++)
{
n=l=187;
if(p>=g)
{
n=b.Substring(p, 1).ToCharArray()[0];//n取密码中的以0开始的第p位字符
}
else
{
if(p>=h)
{
l=a.Substring(p, 1).ToCharArray()[0];//l取短验证码中的以0开始的第p位字符
}
else
{
l=a.Substring(p, 1).ToCharArray()[0];//l取短验证码中的以0开始的第p位字符
n=b.Substring(p, 1).ToCharArray()[0];//n取密码中的以0开始的第p位字符
}
}
//每次计算出l和n的值之后对其取异或然后除以k(也就是除以255),
//取长验证码中以0开始的第(l^n)%k位,然后拼接到字符串e的后面
e+=c.Substring((l^n)%k,1);
}
return e;//返回加密后的密码
}
然后开始调试看加密算法是否正确,长验证码和短验证码可以直接在JS中找到,为固定字符串
可以看到,加密函数得出了正确结果,为"o2Qg443HtTefbwK",好了,可以去POST尝试登录路由器了,但是发现无法登录
HttpWebRequet的GetRequestStream方法一直报错
到网上查到了解决办法,但是根本没有效果,快要断电了,今天就搞到这吧,以后有时间再来解决这个POST的问题
来自一年后的更新:发送POST请求时Http header需要用application/json方式提交,如果不是application/json方式就会出现上面的问题