This is a python script that can be used to fuzz PKZip files.
a2bdb33bcb41c294dc85b483289846e5c47e3a42a7557fc3c7123a4a4f56c006
#####################
# zipfuzz.py #
# #
# DATE #
# 12/11/2015 #
# #
# DESCRIPTION #
# Simple script for fuzzing zip files #
# #
# AUTHOR Andrea Sindoni --- @invictus1306 #
#####################
from struct import *
from optparse import OptionParser
import random
import sys
class Crand:
@staticmethod
def randomBytes(n):
return bytearray(random.getrandbits(8) for i in range(n))
@staticmethod
def random_localFileHeader(val, length):
random_index = []
for i in range(0,length):
index = random.randrange(0,len(val))
if index not in random_index:
random_index.append(index)
return random_index
@staticmethod
def getRandNumber(structLen):
return random.randrange(0,len(structLen))
@staticmethod
def getSeed():
return random.randrange(0, 9223372036854775807)
class Cpack:
def __init__(self, valDict, valLoc):
self.valDict = valDict
self.valLoc = valLoc
def packHeader4byte(self, index):
global content
if index in self.valLoc:
f, s, t, q = Crand().randomBytes(4)
content += pack('4B', f, s, t, q)
else:
content += pack('I', self.valDict[index])
def packHeaderHbyte(self, index):
global content
if index in self.valLoc:
f, s = Crand().randomBytes(2)
content += pack('2B', f, s)
else:
content += pack('H', self.valDict[index])
def packHeader2byte(self, index):
global content
if index in self.valLoc:
f, s = Crand().randomBytes(2)
content += pack('2B', f, s)
else:
content += pack('2B', *self.valDict[index])
def packHeadernbyte(self, index, len):
global content
if index in self.valLoc:
lst = []
len = random.randrange(0, 255)
lst = Crand().randomBytes(len)
sub = tuple(lst)
content += pack(str(len) + 'B', *sub)
else:
content += pack(str(len) + 'B', *self.valDict[index])
class ClocalHeader:
def __init__(self, dictLocalFileHeader, locFileHeadList):
self.dictLocalFileHeader = dictLocalFileHeader
self.locFileHeadList = locFileHeadList
def fuzzLocalHeader(self, signature):
global content
content += pack('4B', *signature)
packElem = Cpack(self.dictLocalFileHeader, self.locFileHeadList)
[packElem.packHeader2byte(i) for i in range(0, 4)]
[packElem.packHeader4byte(i) for i in range(5, 7)]
[packElem.packHeaderHbyte(i) for i in range(8, 9)]
packElem.packHeadernbyte(10, len(self.dictLocalFileHeader[10]))
packElem.packHeadernbyte(11, len(self.dictLocalFileHeader[11]))
packElem.packHeadernbyte(12, len(self.dictLocalFileHeader[12]))
class CcentralDir:
def __init__(self, dictCentralDir, centrDirList):
self.dictCentralDir = dictCentralDir
self.centrDirList = centrDirList
def fuzzCentralDir(self, signature):
global content
content += pack('4B', *signature)
packElem = Cpack(self.dictCentralDir, self.centrDirList)
[packElem.packHeader2byte(i) for i in range(0, 5)]
[packElem.packHeader4byte(i) for i in range(6, 8)]
[packElem.packHeaderHbyte(i) for i in range(9, 11)]
[packElem.packHeader2byte(i) for i in range(12, 13)]
[packElem.packHeader4byte(i) for i in range(14, 15)]
packElem.packHeadernbyte(16, len(self.dictCentralDir[16]))
packElem.packHeadernbyte(17, len(self.dictCentralDir[17]))
packElem.packHeadernbyte(18, len(self.dictCentralDir[18]))
class CendOfCentralDir:
def __init__(self, dictEndOfCentralDir, endOfcentrDirList):
self.dictEndOfCentralDir = dictEndOfCentralDir
self.endOfcentrDirList = endOfcentrDirList
def fuzzendOfCentralDir(self, endOfCentralDirSig):
global content
content += pack('4B', *endOfCentralDirSig)
packElem = Cpack(self.dictEndOfCentralDir, self.endOfcentrDirList)
[packElem.packHeader2byte(i) for i in range(0, 3)]
[packElem.packHeader4byte(i) for i in range(4, 5)]
packElem.packHeaderHbyte(6)
packElem.packHeadernbyte(7, len(self.dictEndOfCentralDir[7]))
class CfileManag:
def setInputFilename(self, fileName):
self.fileName = fileName
def getInputFileName(self):
return self.fileName
def createFile(self, fileNameOut):
with open(fileNameOut, mode='wb') as file:
print content
writeContent = file.write(content)
def main():
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
help="input ZIP file", metavar="FILE")
parser.add_option("-s", "--seed",
type="int", dest="SEED",
help="input for seed value")
(options, args) = parser.parse_args()
if len(sys.argv[1:]) == 0:
print "No argument given!\n"
parser.print_help()
sys.exit()
if options.filename:
fileElem = CfileManag()
fileElem.setInputFilename(options.filename)
else:
sys.exit()
if options.SEED:
seed = options.SEED
else:
seed = Crand().getSeed()
fileName = fileElem.getInputFileName()
random.seed(seed)
with open(fileName, mode='rb') as file:
fileContent = file.read()
# local header
signature = unpack('4B', fileContent[0:4])
version = unpack('2B', fileContent[4:6])
flags = unpack('2B', fileContent[6:8])
compression = unpack('2B', fileContent[8:10])
modTime = unpack('2B', fileContent[10:12])
modDate = unpack('2B', fileContent[12:14])
crc32 = unpack('I', fileContent[14:18])[0]
compressSize = unpack('I', fileContent[18:22])[0]
uncompressSize = unpack('I', fileContent[22:26])[0]
fileNameLen = unpack('H', fileContent[26:28])[0]
extraFieldLen = unpack('H', fileContent[28:30])[0]
endFileName = 30 + fileNameLen
endExtraField = endFileName + extraFieldLen
fileName = unpack(str(fileNameLen)+'B', fileContent[30:endFileName])
extraField = unpack(str(extraFieldLen)+'B', fileContent[endFileName:endExtraField])
# file data
if (compressSize!=0):
endCompSize = endExtraField + compressSize
data = unpack(str(compressSize)+'B', fileContent[endExtraField:endCompSize])
# no data descriptor
# Central directory structure
centralDirectorySig = fileContent.find('\x50\x4b\x01\x02')
if (centralDirectorySig != -1):
endCentrDir = centralDirectorySig + 4
CDsignature = unpack('4B', fileContent[centralDirectorySig:endCentrDir])
endCDversion = endCentrDir + 2
CDversion = unpack('2B', fileContent[endCentrDir:endCDversion])
endCDversionNeed = endCDversion + 2
CDversionNeed = unpack('2B', fileContent[endCDversion:endCDversionNeed])
endCDbitFlag = endCDversionNeed + 2
CDbitFlag = unpack('2B', fileContent[endCDversionNeed:endCDbitFlag])
endCDcompression = endCDbitFlag + 2
CDcompression = unpack('2B', fileContent[endCDbitFlag:endCDcompression])
endCDmodTime = endCDcompression + 2
CDmodTime = unpack('2B', fileContent[endCDcompression:endCDmodTime])
endCDmodDate = endCDmodTime + 2
CDmodDate = unpack('2B', fileContent[endCDmodTime:endCDmodDate])
endCDcrc32 = endCDmodDate + 4
CDcrc32 = unpack('I', fileContent[endCDmodDate:endCDcrc32])[0]
endCDcompressSize = endCDcrc32 + 4
CDcompressSize = unpack('I', fileContent[endCDcrc32:endCDcompressSize])[0]
endCDuncompressSize = endCDcompressSize + 4
CDuncompressSize = unpack('I', fileContent[endCDcompressSize:endCDuncompressSize])[0]
endCDfileNameLen = endCDuncompressSize + 2
CDfileNameLen = unpack('H', fileContent[endCDuncompressSize:endCDfileNameLen])[0]
endCDextraFieldLen = endCDfileNameLen + 2
CDextraFieldLen = unpack('H', fileContent[endCDfileNameLen:endCDextraFieldLen])[0]
endCDfileCommLen = endCDextraFieldLen + 2
CDfileCommLen = unpack('H', fileContent[endCDextraFieldLen:endCDfileCommLen])[0]
endCDdiskNumStart = endCDfileCommLen + 2
CDdiskNumStart = unpack('2B', fileContent[endCDfileCommLen:endCDdiskNumStart])
endCDintFileAttr = endCDdiskNumStart + 2
CDintFileAttr = unpack('2B', fileContent[endCDdiskNumStart:endCDintFileAttr])
endCDextFileAttr = endCDintFileAttr + 4
CDextFileAttr = unpack('I', fileContent[endCDintFileAttr:endCDextFileAttr])[0]
endCDrelOffset = endCDextFileAttr + 4
CDrelOffset = unpack('I', fileContent[endCDextFileAttr:endCDrelOffset])[0]
endCDFileName = endCDrelOffset + CDfileNameLen
CDFileName = unpack(str(CDfileNameLen) + 'B', fileContent[endCDrelOffset:endCDFileName])
endCDExtraField = endCDFileName + CDextraFieldLen
CDExtraField = unpack(str(CDextraFieldLen) + 'B', fileContent[endCDFileName:endCDExtraField])
endCDFileComment = endCDExtraField + CDfileCommLen
CDFileComment = unpack(str(CDfileCommLen) + 'B', fileContent[endCDExtraField:endCDFileComment])
# end of central directory structure
endOfCentralDirSig = fileContent.find('\x50\x4b\x05\x06')
if (endOfCentralDirSig != -1):
endECD = endOfCentralDirSig + 4
EDCsignature = unpack('4B', fileContent[endOfCentralDirSig:endECD])
endECDdiskNumber = endECD + 2
ECDdiskNumber = unpack('2B', fileContent[endECD:endECDdiskNumber])
endECDcentDirStartDisk = endECDdiskNumber + 2
ECDcentDirStartDisk = unpack('2B', fileContent[endECDdiskNumber:endECDcentDirStartDisk])
endECDcentDirStartDiskOff = endECDcentDirStartDisk + 2
ECDcentDirStartDiskOff = unpack('2B', fileContent[endECDcentDirStartDisk:endECDcentDirStartDiskOff])
endECDnumEntry = endECDcentDirStartDiskOff + 2
ECDnumEntry = unpack('2B', fileContent[endECDcentDirStartDiskOff:endECDnumEntry])
endECDcentrDirSize = endECDnumEntry + 4
ECDcentrDirSize = unpack('I', fileContent[endECDnumEntry:endECDcentrDirSize])[0]
endECDcentrDirOff = endECDcentrDirSize + 4
ECDcentrDirOff = unpack('I', fileContent[endECDcentrDirSize:endECDcentrDirOff])[0]
endECDcommLen = endECDcentrDirOff + 2
ECDcommLen = unpack('H', fileContent[endECDcentrDirOff:endECDcommLen])[0]
endECDzipComment = endECDcommLen + ECDcommLen
ECDzipComment = unpack(str(ECDcommLen) + 'B', fileContent[endECDcommLen:endECDzipComment])
localFileHeader = [version, flags, compression, modTime, modDate, crc32, compressSize, uncompressSize, fileNameLen, extraFieldLen, fileName, extraField, data]
centralDirectoryStruct = [CDversion, CDversionNeed, CDbitFlag, CDcompression, CDmodTime, CDmodDate, CDcrc32, CDcompressSize, CDuncompressSize, CDfileNameLen, CDextraFieldLen, CDfileCommLen, CDdiskNumStart, CDintFileAttr, CDextFileAttr, CDrelOffset, CDFileName, CDExtraField, CDFileComment]
endOfCentralDirectoyStruct = [ECDdiskNumber, ECDcentDirStartDisk, ECDcentDirStartDiskOff, ECDnumEntry, ECDcentrDirSize, ECDcentrDirOff, ECDcommLen, ECDzipComment]
locFileHeadList = Crand().random_localFileHeader(localFileHeader, Crand().getRandNumber(localFileHeader))
centrDirList = Crand().random_localFileHeader(centralDirectoryStruct, Crand().getRandNumber(centralDirectoryStruct))
endOfcentrDirList = Crand().random_localFileHeader(endOfCentralDirectoyStruct, Crand().getRandNumber(endOfCentralDirectoyStruct))
dictLocalFileHeader = { 0 : version,
1 : flags,
2 : compression,
3 : modTime,
4 : modDate,
5 : crc32,
6 : compressSize,
7 : uncompressSize,
8 : fileNameLen,
9 : extraFieldLen,
10 : fileName,
11 : extraField,
12 : data
}
dictCentralDir = { 0 : CDversion,
1 : CDversionNeed,
2 : CDbitFlag,
3 : CDcompression,
4 : CDmodTime,
5 : CDmodDate,
6 : CDcrc32,
7 : CDcompressSize,
8 : CDuncompressSize,
9 : CDfileNameLen,
10 : CDextraFieldLen,
11 : CDfileCommLen,
12 : CDdiskNumStart,
13 : CDintFileAttr,
14 : CDextFileAttr,
15 : CDrelOffset,
16 : CDFileName,
17 : CDExtraField,
18 : CDFileComment
}
dictEndOfCentralDir = { 0 : ECDdiskNumber,
1 : ECDcentDirStartDisk,
2 : ECDcentDirStartDiskOff,
3 : ECDnumEntry,
4 : ECDcentrDirSize,
5 : ECDcentrDirOff,
6 : ECDcommLen,
7 : ECDzipComment
}
global content
content = ''
callLocHead = ClocalHeader(dictLocalFileHeader, locFileHeadList)
callLocHead.fuzzLocalHeader(signature)
callCentrDir = CcentralDir(dictCentralDir, centrDirList)
callCentrDir.fuzzCentralDir(CDsignature)
callEndOfCentrDir = CendOfCentralDir(dictEndOfCentralDir, endOfcentrDirList)
callEndOfCentrDir.fuzzendOfCentralDir(EDCsignature)
fileElem.createFile("fuzzed.zip")
if __name__ == "__main__":
main()