def CiscoIOSImageFileParser(filename, options): global oMD5Database image = naft_uf.File2Data(filename) if image == None: print('Error reading %s' % filename) return oIOSImage = naft_iipf.cIOSImage(image) oIOSImage.Print() if options.md5db: md5hash = hashlib.md5(image).hexdigest() filenameCSV, filenameDB = oMD5Database.Find(md5hash) if filenameCSV == None: print('File not found in md5 database') else: print('File found in md5 database %s %s' % (filenameCSV, filenameDB)) if options.verbose: for oSectionHeader in oIOSImage.oELF.sections: print(' %2d %-7s %d %d %08X %10d %s' % (oSectionHeader.nameIndex, oSectionHeader.nameIndexString, oSectionHeader.type, oSectionHeader.flags, oSectionHeader.offset, oSectionHeader.size, repr(oSectionHeader.sectionData[0:8]))) if options.extract: naft_uf.Data2File(oIOSImage.imageUncompressed, oIOSImage.imageUncompressedName) if options.idapro: naft_uf.Data2File(oIOSImage.ImageUncompressedIDAPro(), oIOSImage.imageUncompressedName)
def Parse(self): self.error = '' self.coredump = naft_uf.File2Data(self.coredumpFilename) if self.coredump == None: self.error = 'Error reading coredump %s' % self.coredumpFilename return indexRegionsMetaData = self.coredump.find(cCiscoMagic.STR_REGIONS) if indexRegionsMetaData < 0: self.error = 'Magic sequence %s not found' % binascii.b2a_hex(cCiscoMagic.STR_REGIONS).upper() return if self.coredump[indexRegionsMetaData + 4:indexRegionsMetaData + 4 + 4] != '\x00\x00\x00\x05': self.error = 'Unexpected data found: %s' % binascii.b2a_hex(self.coredump[indexRegionsMetaData + 4:indexRegionsMetaData + 4 + 4]) return addresses = struct.unpack('>IIII', self.coredump[indexRegionsMetaData + 20:indexRegionsMetaData + 20 + 4 * 4]) indexHeap = self.coredump.find(cCiscoMagic.STR_BLOCK_BEGIN, addresses[3] - addresses[0]) if indexHeap < 0: self.error = 'Magic sequence %s not found' % binascii.b2a_hex(cCiscoMagic.STR_BLOCK_BEGIN).upper() return self.address = addresses[0] self.size = len(self.coredump) addressBegin = self.address addressEnd = self.address + self.size regionsCalculation = map(lambda x, y : (x, y), ('begin', 'text', 'data', 'bss'), addresses) regionsCalculation.append(('heap', addresses[0] + indexHeap)) regionsCalculation.append(('end', addressEnd)) indices = range(len(regionsCalculation)) for index, value in enumerate(indices): address = regionsCalculation[value][1] if address < addressBegin or address > addressEnd: del indices[index] regionsCalculation[value] = (regionsCalculation[value][0], regionsCalculation[value][1], None, None) for index, value in enumerate(indices[:-1]): length = regionsCalculation[indices[index + 1]][1] - regionsCalculation[value][1] regionsCalculation[value] = (regionsCalculation[value][0], regionsCalculation[value][1], length, regionsCalculation[value][1] - addressBegin) self.regions = regionsCalculation[:-1]
def ExtractIPPacketsFromFile(filenamePCAP, filenamesRawData, options): naft_uf.LogLine('Start') if options.ouitxt == '': oFrames = naft_pfef.cFrames() else: oFrames = naft_pfef.cFrames(options.ouitxt) countProcessedFiles = 0 for filenameRawData in filenamesRawData: if options.buffer: naft_uf.LogLine('Buffering file %s' % filenameRawData) oBufferFile = naft_uf.cBufferFile(filenameRawData, options.buffersize * 1024 * 1024, options.bufferoverlapsize * 1024 * 1024) while oBufferFile.Read(): naft_uf.LogLine('Processing buffer 0x%x size %d MB %d%%' % (oBufferFile.index, len(oBufferFile.buffer) / 1024 / 1024, oBufferFile.Progress())) naft_uf.LogLine('Searching for IPv4 packets') naft_pfef.ExtractIPPackets(oFrames, oBufferFile.index, oBufferFile.buffer, options.options, options.duplicates, True, filenameRawData) naft_uf.LogLine('Searching for ARP Ethernet frames') naft_pfef.ExtractARPFrames(oFrames, oBufferFile.index, oBufferFile.buffer, options.duplicates, True, filenameRawData) if oBufferFile.error == MemoryError: naft_uf.LogLine('Data is too large to fit in memory, use smaller buffer') elif oBufferFile.error: naft_uf.LogLine('Error reading file') countProcessedFiles += 1 else: naft_uf.LogLine('Reading file %s' % filenameRawData) rawData = naft_uf.File2Data(filenameRawData) if rawData == None: naft_uf.LogLine('Error reading file') if rawData == MemoryError: naft_uf.LogLine('File is too large to fit in memory') else: naft_uf.LogLine('Searching for IPv4 packets') naft_pfef.ExtractIPPackets(oFrames, 0, rawData, options.options, options.duplicates, True, filenameRawData) naft_uf.LogLine('Searching for ARP Ethernet frames') naft_pfef.ExtractARPFrames(oFrames, 0, rawData, options.duplicates, True, filenameRawData) countProcessedFiles += 1 if countProcessedFiles > 0: naft_uf.LogLine('Writing PCAP file %s' % filenamePCAP) if not oFrames.WritePCAP(filenamePCAP): naft_uf.LogLine('Error writing PCAP file') naft_uf.LogLine('Number of identified frames: %5d' % oFrames.countFrames) naft_uf.LogLine('Number of identified packets: %5d' % oFrames.countPackets) naft_uf.LogLine('Number of frames in PCAP file: %5d' % len(oFrames.frames)) if options.template: naft_uf.LogLine('Writing 010 template file %s' % options.template) if not oFrames.Write010Template(options.template): naft_uf.LogLine('Error writing 010 template file') naft_uf.LogLine('Done')
def IOSCWStrings(coredumpFilename, options): if options.raw: coredump = naft_uf.File2Data(coredumpFilename) if coredump == None: print('Error reading file %s' % coredumpFilename) else: IOSCWStringsSub(coredump) else: oIOSCoreDump = naft_impf.cIOSCoreDump(coredumpFilename) if oIOSCoreDump.error != '': print(oIOSCoreDump.error) return addressData, memoryData = oIOSCoreDump.RegionDATA() if memoryData == None: print('Data region not found') return IOSCWStringsSub(memoryData)
def IOSFrames(coredumpFilename, filenameIOMEM, filenamePCAP, options): oIOSCoreDump = naft_impf.cIOSCoreDump(coredumpFilename) if oIOSCoreDump.error != '': print(oIOSCoreDump.error) return addressHeap, memoryHeap = oIOSCoreDump.RegionHEAP() if memoryHeap == None: print('Heap region not found') return oIOSMemoryParserHeap = naft_impf.cIOSMemoryParser(memoryHeap) oIOSMemoryParserHeap.ResolveNames(oIOSCoreDump) dataIOMEM = naft_uf.File2Data(filenameIOMEM) oIOSMemoryParserIOMEM = naft_impf.cIOSMemoryParser(dataIOMEM) addressIOMEM = oIOSMemoryParserIOMEM.baseAddress if addressIOMEM == None: print('Error parsing IOMEM') return oFrames = naft_pfef.cFrames() print(naft_impf.cIOSMemoryBlockHeader.ShowHeader) for oIOSMemoryBlockHeader in oIOSMemoryParserHeap.Headers: if oIOSMemoryBlockHeader.AllocNameResolved == '*Packet Header*': frameAddress = struct.unpack( '>I', oIOSMemoryBlockHeader.GetData()[40:44])[0] frameSize = struct.unpack( '>H', oIOSMemoryBlockHeader.GetData()[72:74])[0] if frameSize <= 1: frameSize = struct.unpack( '>H', oIOSMemoryBlockHeader.GetData()[68:70])[0] if frameAddress != 0 and frameSize != 0: print(oIOSMemoryBlockHeader.ShowLine()) naft_uf.DumpBytes( dataIOMEM[frameAddress - addressIOMEM:frameAddress - addressIOMEM + frameSize], frameAddress) oFrames.AddFrame( frameAddress - addressIOMEM, dataIOMEM[frameAddress - addressIOMEM:frameAddress - addressIOMEM + frameSize], True) oFrames.WritePCAP(filenamePCAP)
def IOSCheckText(coredumpFilename, imageFilename, options): returnString = '' oIOSCoreDump = naft_impf.cIOSCoreDump(coredumpFilename) if oIOSCoreDump.error != '': returnString += (oIOSCoreDump.error) + '<br>' return returnString else: textAddress, textCoredump = oIOSCoreDump.RegionTEXT() if textCoredump == None: returnString += ( 'Error extracting text region from coredump %s<br>' % coredumpFilename) return returnString sysdescrCoredump = '' dataAddress, dataCoredump = oIOSCoreDump.RegionDATA() if dataCoredump != None: oCWStrings = naft_impf.cCiscoCWStrings(dataCoredump) if oCWStrings.error == '' and 'CW_SYSDESCR' in oCWStrings.dCWStrings: sysdescrCoredump = oCWStrings.dCWStrings['CW_SYSDESCR'] image = naft_uf.File2Data(imageFilename) if image == None: returnString += ('Error reading image %s' % imageFilename) return returnString oIOSImage = naft_iipf.cIOSImage(image) if oIOSImage.error != 0: return sysdescrImage = '' if oIOSImage.oCWStrings != None and oIOSImage.oCWStrings.error == '' and 'CW_SYSDESCR' in oIOSImage.oCWStrings.dCWStrings: sysdescrImage = oIOSImage.oCWStrings.dCWStrings['CW_SYSDESCR'] if sysdescrCoredump != '' or sysdescrImage != '': if sysdescrCoredump == sysdescrImage: returnString += ('CW_SYSDESCR are identical:<br>') returnString += (sysdescrCoredump) + '<br>' elif sysdescrCoredump == sysdescrImage.replace('-MZ', '-M', 1): returnString += ('CW_SYSDESCR are equivalent:<br>') returnString += (sysdescrCoredump) + '<br>' else: returnString += ('CW_SYSDESCR are different:<br>') returnString += (sysdescrCoredump) + '<br>' returnString += '<br>' returnString += (sysdescrImage) + '<br>' returnString += '<br>' oELF = naft_iipf.cELF(oIOSImage.imageUncompressed) if oELF.error != 0: returnString += ('ELF parsing error %d.' % oELF.error) return returnString countSectionExecutableInstructions = 0 countSectionSRELOC = 0 for oSectionHeader in oELF.sections: if oSectionHeader.flags & 4: # SHF_EXECINSTR executable instructions textSectionData = oSectionHeader.sectionData countSectionExecutableInstructions += 1 if oSectionHeader.nameIndexString == 'sreloc': countSectionSRELOC += 1 if countSectionExecutableInstructions != 1: returnString += ( 'Error executable sections in image: found %d sections, expected 1' % countSectionExecutableInstructions) return returnString if countSectionSRELOC != 0: returnString += ( 'Error found %d sreloc section in image: checktext command does not support relocation' % countSectionSRELOC) return returnString start = textAddress & 0xFF # to be further researched textImage = textSectionData[start:start + len(textCoredump)] if len(textCoredump) != len(textImage): returnString += ('the text region is longer than the text section<br>') returnString += ('len(textCoredump) = %d<br>' % len(textCoredump)) returnString += ('len(textImage) = %d<br>' % len(textImage)) countBytesDifferent = 0 shortestLength = min(len(textCoredump), len(textImage)) for iIter in range(shortestLength): if textCoredump[iIter] != textImage[iIter]: if countBytesDifferent == 0: returnString += ( 'text region and section are different starting 0x%08X in coredump (iter = 0x%08X)<br>' % ((textAddress + iIter), iIter)) countBytesDifferent += 1 if countBytesDifferent == 0: returnString += ('text region and section are identical <br>') else: returnString += ('number of different bytes: %d (%.2f%%)<br>' % (countBytesDifferent, (countBytesDifferent * 100.0) / shortestLength)) return returnString
def CiscoIOSImageFileScanner(filewildcard, options): if options.resume == None: filenames = GlobFilelist(filewildcard, options) countFilenames = len(filenames) counter = 1 if options.log != None: f = open(options.log, 'w') f.close() else: fPickle = open(options.resume, 'rb') filenames, countFilenames, counter = pickle.load(fPickle) fPickle.close() print('Pickle file loaded') while len(filenames) > 0: filename = filenames[0] try: line = [str(counter), str(countFilenames), filename] image = naft_uf.File2Data(filename) if image == None: line.extend(['Error reading']) else: oIOSImage = naft_iipf.cIOSImage(image) if oIOSImage.oCWStrings != None and oIOSImage.oCWStrings.error == '': line.extend([ naft_uf.cn( vn(oIOSImage.oCWStrings.dCWStrings, 'CW_VERSION')), naft_uf.cn( vn(oIOSImage.oCWStrings.dCWStrings, 'CW_FAMILY')) ]) else: line.extend([naft_uf.cn(None), naft_uf.cn(None)]) line.extend([ str(len(image)), '%.2f' % Entropy(image), str(oIOSImage.error), str(oIOSImage.oELF.error), str(oIOSImage.oELF.countSections), str(naft_uf.cn(oIOSImage.oELF.stringTableIndex)), naft_uf.cn(oIOSImage.checksumCompressed, '0x%08X'), str(oIOSImage.checksumCompressed != None and oIOSImage.checksumCompressed == oIOSImage.calculatedChecksumCompressed), naft_uf.cn(oIOSImage.checksumUncompressed, '0x%08X'), str(oIOSImage.checksumUncompressed != None and oIOSImage.checksumUncompressed == oIOSImage.calculatedChecksumUncompressed), naft_uf.cn(oIOSImage.imageUncompressedName), naft_uf.cn(oIOSImage.embeddedMD5) ]) if options.md5db: md5hash = hashlib.md5(image).hexdigest() filenameCSV, filenameDB = oMD5Database.Find(md5hash) line.extend([ md5hash, naft_uf.cn(filenameCSV), naft_uf.cn(filenameDB) ]) strLine = ';'.join(line) print(strLine) if options.log != None: f = open(options.log, 'a') f.write(strLine + '\n') f.close() counter += 1 filenames = filenames[1:] except KeyboardInterrupt: print('KeyboardInterrupt') PickleData([filenames, countFilenames, counter]) return except: traceback.print_exc() PickleData([filenames, countFilenames, counter]) return