枚举解密有密码的压缩包应该是常见需求了。没有工具的情况下可以自己写一段py脚本来实现。
环境:Windows10,python3.7.6
仅支持ZIP的版本
我稍微改了下参考链接1的代码,可以正确运行。 他的代码在解密基础上加了多线程,但是他的代码会打印很多个密码(第一个打印的就是真密码)。
我对多线程了解很少,但我认为我这段代码是对的(只要对flag 变量的所有操作都是原子的),因为只有一个线程能找到密码,找到密码的线程等待cpu调度期间即使有其他线程执行done_callback,也无法进入if那块代码。
作者:hans774882968以及hans774882968
注意:
- 同时支持zip和rar的代码在下一小节。
- 使用的命令可以是
python zip_pwd.py 或python zip_pwd.py <zip文件的绝对路径或相对路径> - 这段代码如果找到了密码,也会把解压出的文件放在python文件所在文件夹下。
- 参考链接2告诉我们,如果你想用WinRAR创建zip压缩文件,用来学习测试zip枚举解密,记得勾选ZIP传统加密。
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():
return itertools.product(*[[str(j) for j in range(10)] for i in range(4)])
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()
支持ZIP和RAR的版本
安装
首先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) ,但是跑得比上一小节的代码慢不少。所以后面改回了面向过程的版本,代码比较丑。
注意:
- 跑zip的时候cpu使用率很正常,解得也很快。但跑rar的时候cpu飙升到100%,对于4位数密码似乎要解一分钟左右。
所以最好还是去找工具 - 使用命令同上。
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():
return itertools.product(*[[str(j) for j in range(10)] for i in range(4)])
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()
参考链接
- python解压zip:https://cloud.tencent.com/developer/article/1806690
- zip需要勾选“ZIP传统加密”:https://blog.csdn.net/Tiny007/article/details/105121800
|