枚举解密有密码的压缩包应该是常见需求了。没有工具的情况下可以自己写一段py脚本来实现。
环境:Windows10,python3.7.6
我稍微改了下参考链接1的代码,可以正确运行。 他的代码在解密基础上加了多线程,但是他的代码会打印很多个密码(第一个打印的就是真密码)。
我对多线程了解很少,但我认为我这段代码是对的(只要对flag
变量的所有操作都是原子的),因为只有一个线程能找到密码,找到密码的线程等待cpu调度期间即使有其他线程执行done_callback,也无法进入if那块代码。
作者:hans774882968以及hans774882968
注意:
python zip_pwd.py
或python zip_pwd.py
import queue
import zipfile
import itertools
import sys
from concurrent.futures import ThreadPoolExecutor
# 创建一个标志用于判断密码是否破解成功
flag = True
def extract(file, password):
if not flag: return
file.extractall(path='.', pwd=''.join(password).encode('utf-8'))
def result(f):
global flag
exception = f.exception()
if not exception and flag:
# 如果获取不到异常说明破解成功
print('密码为:', f.pwd)
flag = False
class BoundedThreadPoolExecutor(ThreadPoolExecutor):
def __init__(self, max_workers=None, thread_name_prefix=''):
super().__init__(max_workers, thread_name_prefix)
self._work_queue = queue.Queue(self._max_workers * 2) # 设置队列大小
def get_pwd_list():
# 生成数字+字母的6位数密码
# nums = [str(i) for i in range(10)]
# chrs = [chr(i) for i in range(65, 91)]
# return itertools.permutations(nums + chrs, 6)
# 生成所有4位数
return itertools.product(*[[str(j) for j in range(10)] for i in range(4)])
# https://cloud.tencent.com/developer/article/1806690
def main():
fname = "shell-shell漏洞.zip"
if len(sys.argv) > 1: fname = sys.argv[1]
# 创建一个线程池
pool = BoundedThreadPoolExecutor(100)
password_lst = get_pwd_list()
# 创建文件句柄
zfile = zipfile.ZipFile(fname, 'r')
for pd in password_lst:
pwd = "".join(pd)
if not flag: break
f = pool.submit(extract, zfile, pwd)
f.pwd = pwd
f.pool = pool
f.add_done_callback(result)
if __name__ == '__main__':
main()
首先pip install rarfile
,然后要把unrar.exe加到环境变量PATH变量,否则python代码运行报错(根据官方文档,测试环境变量添加是否成功,只需要在powershell执行unrar -v
)。注意,请添加一个文件夹,比如C:\Program Files\WinRAR\
,而非一个exe文件!
因为zip和rar的api用法差不多,所以一开始为了让代码的颜值高,写了抽象类的版本,线程池的使用方式类似于f = pool.submit(mgr.extract, pwd)
、f.add_done_callback(result)
,但是跑得比上一小节的代码慢不少。所以后面改回了面向过程的版本,代码比较丑。
注意:
import queue
import zipfile
import rarfile
import itertools
import sys
import os
from concurrent.futures import ThreadPoolExecutor
# 创建一个标志用于判断密码是否破解成功
flag = True
fileType = ""
output_dir = ""
RAR_TYPE = ".rar"
ZIP_TYPE = ".zip"
def extract(file, password):
if not flag: return
if fileType == ZIP_TYPE:
file.extractall(path=output_dir, pwd=''.join(password).encode('utf-8'))
else:
file.extractall(path=output_dir, pwd=''.join(password))
def result(f):
global flag
exception = f.exception()
if not exception and flag:
# 如果获取不到异常说明破解成功
print('密码为:', f.pwd)
flag = False
class BoundedThreadPoolExecutor(ThreadPoolExecutor):
def __init__(self, max_workers=None, thread_name_prefix=''):
super().__init__(max_workers, thread_name_prefix)
self._work_queue = queue.Queue(self._max_workers * 2) # 设置队列大小
def get_pwd_list():
# 生成数字+字母的6位数密码
# nums = [str(i) for i in range(10)]
# chrs = [chr(i) for i in range(65, 91)]
# return itertools.permutations(nums + chrs, 6)
# 生成所有4位数
return itertools.product(*[[str(j) for j in range(10)] for i in range(4)])
# https://cloud.tencent.com/developer/article/1806690
def main():
global file_dir,output_dir,fileType
file_dir = "shell-shell漏洞.zip"
if len(sys.argv) > 1: file_dir = sys.argv[1]
output_dir = os.path.dirname(file_dir)
ext_name = os.path.splitext(file_dir)[1].lower()
if ext_name != ZIP_TYPE and ext_name != RAR_TYPE:
raise Exception("Expect .zip or .rar file, but get \"%s\" file" % ext_name)
fileType = ext_name
# 创建一个线程池
pool = BoundedThreadPoolExecutor(100)
password_lst = get_pwd_list()
# 创建文件句柄
cfile = zipfile.ZipFile(file_dir, 'r') if fileType == ZIP_TYPE else rarfile.RarFile(file_dir)
for pd in password_lst:
pwd = "".join(pd)
if not flag: break
f = pool.submit(extract, cfile, pwd)
f.pwd = pwd
f.pool = pool
f.add_done_callback(result)
if __name__ == '__main__':
main()