任务:
第十三周
完成实验楼上Linux安全类实验中的一个,两人一组,题目不能重复。
作业标题 “学号《Linux内核原理与分析》第X周作业”,重点是遇到的问题和解决方案内容涵盖教材学习和视频,提交格式用Markdown,同时提交转换的 PDF(VSCode 有相关插件)。
实验:Python实现Zip文件的暴力破解
我们在网上好不容易下载到一个想要的 zip 资源却发现这个 zip 文件是加密的,或者忘掉自己压缩后的密码(一想到就头疼)。这时候我们就会想办法,将里面的内容提取出来。我目前已知的破解 zip 的方式只有 “Known plaintext attack(已知明文攻击)” 和 “暴力破解”。由于 “Known plaintext attack” 也有比较大的局限性,而且本次实验的定位是入门级的。所以本次实验将带领大家用 Python 的 zipfile 模块实现 Zip 文件的暴力破解。
实验环境
Ubuntu Linux
Python 3.x 版本
代码获取
你可以通过下面命令将代码下载到实验楼环境中,作为参照对比进行学习。
$ wget https://labfile.oss-internal.aliyuncs.com/courses/636/decodeZip.py

一、zipfile 模块:
从本次实验的主题可以看出我们的重点是对 zip 文件的操作,而 zipfile 就是本次实验的核心。zipfile 模块是 python 中自带的模块,提供了对 zip 文件的创建读、写、追加、解压以及列出 zip 文件列表的工具。这里我们主要用到 ZipFile 对象的 extractall 方法来解压 zip 文件,现在我们看一下 ZipFile 的文档, 在 shell 中运行 Python3 交互环境,并使用 help 方法来查看模块的使用方法 (此模块在下文也有详细讲解)。

找到 ZipFile 对象 extractall(path=None, members=None, pwd=None) 方法的说明。
我们先来看下如何用 zipfile 模块解压一个带密码的 Zip 文件。为了照顾不熟悉 Linux 系统的同学们,我这里带着大家准备一下我们需要的文件。
首先我们进入 Code 目录:
cd Code
创建一个用于我们实验的目录 deZip:
mkdir deZip
进入 deZip 目录:
cd deZip

现在我们创建 1.txt 文件:
touch 1.txt
将 1.txt 文件压缩成加密的 1.zip 文件,密码为 1314:
zip -r 1.zip 1.txt -P 1314

现在我们的准备工作就完成了,我们来看一下 Demo 吧!
import zipfile
try:
with zipfile.ZipFile('1.zip') as zFile: #创建 ZipFile 对象
#解压文件
zFile.extractall(path='./', pwd=b'1314')
print('Extract the Zip file successfully!')
except:
print('Extract the Zip file failed!')

将代码保存为 demo.py 我们测试一下是否能正确解压文件:

二、argparse 模块
我们来演示一下 argparse 的用法:
import argparse
parser = argparse.ArgumentParser(description='Regards to your name.')
parser.add_argument('-n', dest='m_name', type=str, help='your name')
options = parser.parse_args()
print('Hello',options.m_name)

先看一下运行结果:

现在我们分析这个例子来学习 argparse 的使用方法: 首先我们导入了 argparse 这个模块,通过 argparse.ArgumentParser 方法来获得解析器对象。description 是在我们输出命令行参数帮助信息时起到描述的作用。add_argument 方法用来添加我们需要解析的参数,可以看到我们这里添加了 -n 参数,dest 相当于存储命令行参数值的变量,提取这个变量的时候我们要用到,比如上面 Demo 中的 options.m_name。type 表示我们输入的类型,这里是 str。help 是用来说明参数的,和 description 一样在我们输出命令行帮助信息时会显示出来。
三、实验步骤
通过前面的学习,我们已经了解了如何解压一个带密码的 Zip 文件。我们今天要实验的内容是 暴力破解 Zip 文件,基本思路就是我们不断去读取密码字典尝试解压带密码的 Zip 文件,如果成功则表示这个密码正确,失败则继续读取密码字典中的密码并尝试解压缩,直到解压缩成功或者密码字典中的密码都尝试一遍。
我们先写一个函数专门用于解压缩 Zip 文件,这个压缩函数有三个参数 zipFile、password,savePath。含义如下:
zipFile 表示一个 ZipFile 对象。
password 表示解压 ZipFile 的密码。
savePath 表示解压后文件存储的路径。
这个函数在尝试密码之后会返回一个布尔值,如果解压成功会返回 True,如果失败则会返回 False。
def tryZipPwd(zipFile, password, savePath):
try:
zipFile.extractall(path=savePath, pwd=password.encode('utf-8'))
print('[+] Zip File decompression success,password: %s' % (password))
return True
except:
print('[-] Zip File decompression failed,password: %s' % (password))
return False
这段代码和我们之前演示的 Demo 基本上是一样的,只是做了一下简单封装,方便我们不断尝试密码。
现在我们来创建一个 ZipFile 对象,并循环读取密码字典文件中的每一行 密码,最后调用我们之前写的解压缩 Zip 文件的函数,根据返回值判断是否找到密码,如果找到则退出循环,否则继续尝试解压密码。
with zipfile.ZipFile(zFilePath) as zFile:
with open(pwdFilePath) as f:
for pwd in f.readlines():
p,f = os.path.split(zFilePath)
dirName = f.split('.')[0]
dirPath = join(p, dirName)
try:
os.mkdir(dirPath)
except:
pass
ok = tryZipPwd(zFile, pwd.strip('\n'), dirPath)
if ok:
break
这里有一点需要注意,我们在读取每一行密码的同时一定要去掉换行符 \n,因为我们在读取的时候会连 \n 一起读取出来,如果直接去尝试密码肯定不会尝试成功。
最后我们来实现参数解析功能,首先分析一下我们都需要哪些参数! 通过解压 Zip 文件的函数来看我们需要知道 密码 和 存储路径 这两个参数,而密码则是从密码字典文件中读取出来的,所以我们需要在程序运行时添加 密码文件路径 和 文件存储路径 这两个参数。
# 这里用描述创建了 ArgumentParser 对象
parser = argparse.ArgumentParser(description='Brute Crack Zip')
# 添加 - H 命令 dest 可以理解为咱们解析时获取 - H 参数后面值的变量名, help 是这个命令的帮助信息
parser.add_argument('-f', dest='zFile', type=str, help='The zip file path.')
parser.add_argument('-w', dest='pwdFile', type =str, help='Password dictionary file.')
至此我们的核心代码就基本写完了,现在我们来整合一下我们的代码处理一些细节问题。
import zipfile
import argparse
import os
from os.path import *
def tryZipPwd(zipFile, password, savePath):
try:
zipFile.extractall(path=savePath, pwd=password.encode('utf-8'))
print('[+] Zip File decompression success,password: %s' % (password))
return True
except:
print('[-] Zip File decompression failed,password: %s' % (password))
return False
def main():
# 这里用描述创建了 ArgumentParser 对象
parser = argparse.ArgumentParser(description='Brute Crack Zip')
# 添加 - H 命令 dest 可以理解为咱们解析时获取 - H 参数后面值的变量名, help 是这个命令的帮助信息
parser.add_argument('-f', dest='zFile', type=str, help='The zip file path.')
parser.add_argument('-w', dest='pwdFile', type =str, help='Password dictionary file.')
zFilePath = None
pwdFilePath = None
try:
options = parser.parse_args()
zFilePath = options.zFile
pwdFilePath = options.pwdFile
except:
print(parser.parse_args(['-h']))
exit(0)
if zFilePath == None or pwdFilePath == None:
print(parser.parse_args(['-h']))
exit(0)
with zipfile.ZipFile(zFilePath) as zFile:
with open(pwdFilePath) as f:
for pwd in f.readlines():
p,f = split(zFilePath)
dirName = f.split('.')[0]
dirPath = join(p, dirName)
try:
os.mkdir(dirPath)
except:
pass
ok = tryZipPwd(zFile, pwd.strip('\n'), dirPath)
if ok:
break
if __name__ == '__main__':
main()

在代码整合之后我们处理了程序启动中命令行参数没有输入的情况,如果命令行参数不全我们的程序将输出帮助信息,并退出程序。
最后我们创建一个用于测试的密码字典 pwd.txt:
vim pwd.txt
这里我随便写了几个密码,同学们可以使用网上找到的密码字典或者密码字典生成器生成的密码字典

现在我们来测试一下程序的运行效果吧!

可以看到程序确实找到了 Zip 文件的解压密码,至此我们的实验就结束了!同学们可以根据这次实验的内容进行改进,比如:批量破解 Zip 文件的密码。
四、实验总结
通过本次实验我们掌握了 Zip 文件暴力破解 的方法,这种方法的成功率比较依赖密码字典文件。虽然这只是一种初级的方法不过确实有的时候是非常有效的,通常情况下我们在遇到加密的 Zip 文件我们首先会尝试这种方法,如果实在破解不了,那就算了吧!Zip 的加密形式还是比较复杂的,想要通过技术手段破解确实很难!所以说不要看本次实验比较简单就觉得这种方式不适用,其实这种方式还是很值得大家学习并掌握的。


被折叠的 条评论
为什么被折叠?



