def hide_file(self, hfile, image, param = {}): hf = None dirs1 = self.fs.get_list_of_files(FLAG_DIRECTORY|FLAG_REGULAR) dirs2 = self.fs.get_list_of_files(FLAG_DIRECTORY|FLAG_SYSTEM) dirs = dirs1+[dirs2[0]] try: newdir = param["directory"] internalpath = newdir+"/"+os.path.basename(hfile.name) targetfile = self.fs.fs_mountpoint + internalpath hf = internalpath except KeyError: try: dpr = choice(dirs) if dpr.filename != "/.": targetdir=dpr.filename else: targetdir="" internalpath = targetdir+"/"+os.path.basename(hfile.name) targetfile = self.fs.fs_mountpoint + internalpath hf = internalpath except IndexError: raise ForensicError("No directory for hiding") finally: if self.fs.mount_image() != 0: raise ForensicError("Mount failed") dpath = os.path.dirname(targetfile) if not os.path.exists(dpath): try: os.makedirs(dpath) except IOError: raise ForensicError("Unable to create directory %s" % dpath) try: tfile = open(targetfile, "w") tfile.write(hfile.read()) tfile.close() except IOError: errlog("Unable to write") try: tfile.close() except IOError: pass self.fs.dismount_image() raise ForensicError("Unable to write") finally: self.fs.dismount_image() return dict(instruction=hf,path=internalpath,newfile=True)
def hide_file(self, hfile, image, param={}): files = self.fs.get_list_of_files(FLAG_REGULAR) hr = None try: itr = 0 while True: c = choice(files) itr = itr + 1 if image.check_trivial_usage_status(c.filename) == False: break if itr > 20: raise ForensicError("Cannot find unused trivial files") chosenfile = c.filename except IndexError: errlog("No files to target") raise ForensicError("no files to target") if self.fs.mount_image() != 0: raise ForensicError("Mount failed") targetfile = self.fs.fs_mountpoint + chosenfile try: tfile = open(targetfile, "a") tfile.write(hfile.read()) tfile.close() try: result_file = hfile.name.rsplit("/", 1)[1] except IndexError: result_file = hfile.name hr = chosenfile + "+" + result_file except IOError: errlog("Unable to write") try: tfile.close() except IOError: pass self.fs.dismount_image() raise ForensicError("Unable to write") finally: self.fs.dismount_image() if chosenfile.find("/./") == 0: chosenfile = chosenfile[2:] try: if param["delete"] == "True": return dict(instruction=hr + " DELETED", path=chosenfile, todelete=[targetfile]) except KeyError: return dict(instruction=hr, path=chosenfile)
def delete_container(self): try: a=check_output([self.chelper.binary, "lxc", "lxc-destroy"], shell=False) except CalledProcessError as e: print e raise ForensicError("delete_container")
def fat_vbr_init(self, vbr): self.f_sectorsize, = struct.unpack("<H", vbr[11:13]) self.f_clustersize = self.f_sectorsize * struct.unpack("B", vbr[13])[0] self.f_reserved, = struct.unpack("<H", vbr[14:16]) self.f_numberoffats, = struct.unpack("B", vbr[16]) self.f_rootentries, = struct.unpack("<H", vbr[17:19]) _small_sector, = struct.unpack("<H", vbr[19:21]) _large_sector, = struct.unpack("<I", vbr[32:36]) self.f_numofsectors = _small_sector if _small_sector > 0 else _large_sector _small_fat, = struct.unpack("<H", vbr[22:24]) _large_fat, = struct.unpack("<I", vbr[36:40]) self.f_fatsize = _small_fat if _small_fat > 0 else _large_fat self.f_rootstart = self.f_reserved + self.f_numberoffats * self.f_fatsize self.f_datastart = self.f_rootstart + (self.f_rootentries * 32) / self.f_sectorsize self.f_slack = [] self.f_filelist = [] self.f_entrylist = [] self.f_numofclusters = self.f_numofsectors / struct.unpack( "B", vbr[13])[0] fstype_string, = struct.unpack("5s", vbr[54:59]) if fstype_string == "FAT12": self.fs_fstype = "FAT12" if fstype_string == "FAT16": self.fs_fstype = "FAT16" if self.fs_fstype == "": fstype_string, = struct.unpack("5s", vbr[82:87]) if fstype_string == "FAT32": self.fs_fstype = "FAT32" else: raise ForensicError("Unknown FAT FS type")
def send_file(self,src): try: a=check_output([self.chelper.binary, "lxc", "copy_file",src], shell=False) except CalledProcessError as e: format_exc() raise ForensicError("send_file")
def write_location(self, position, data): try: wh = open(self.fs_filename, "r+b") wh.seek(position) wh.write(data) wh.close() except IOError: raise ForensicError("Cannot write to image")
def prepare_container(self): try: a=check_output([self.chelper.binary, "lxc", "lxc-destroy"], shell=False) a=check_output([self.chelper.binary, "lxc", "lxc-create"], shell=False) sleep (3) a=check_output([self.chelper.binary, "lxc", "lxc-attach", "nowait", "silent", "Xvfb", ":0", "-screen", "0", "1024x768x24"], shell=False) sleep (3) except CalledProcessError as e: print e raise ForensicError("exec_file") except CalledProcessError as e: print e raise ForensicError("prepare_container")
def find_file_by_path(self, path): if len(path) > 2: if path[:2] == "//": path = path[1:] for f in self.f_entrylist: s = f.get_file_name() if s == path: return f emessage = "File not found: " + path raise ForensicError(emessage)
def fs_finalise(self): pass try: rmft = self.f_mft[0].mft_data(None, 1024 * 5, 1024) wloc = self.f_clustersize * self.f_mft2 + 1024 * 5 """ $MftMirr has root directory entry if cluster size over 4096. """ if self.f_clustersize > 4096: self.write_location(wloc, rmft) except ForensicError: raise ForensicError("Unable to fix $MftMirr")
def hide_file(self, hfile, image, param={}): hf = None dirs1 = self.fs.get_list_of_files(FLAG_DIRECTORY | FLAG_REGULAR) dirs2 = self.fs.get_list_of_files(FLAG_DIRECTORY | FLAG_SYSTEM) dirs = dirs1 + [dirs2[0]] try: givendir = param["directory"] internalpath = givendir + "/" + os.path.basename(hfile.name) targetfile = self.fs.fs_mountpoint + internalpath hf = internalpath except KeyError: try: dpr = choice(dirs) if dpr.filename != "/.": targetdir = dpr.filename else: targetdir = "" internalpath = targetdir + "/" + os.path.basename(hfile.name) targetfile = self.fs.fs_mountpoint + internalpath hf = internalpath except IndexError: raise ForensicError("No directory for hiding") try: if self.fs.mount_image() != 0: raise ForensicError("Mount failed") tf = open(targetfile, "w") tf.write(hfile.read()) tf.close() #os.remove(targetfile) if self.fs.dismount_image() != 0: raise ForensicError("Dismount failed") except IOError: errlog("cannot write file") raise ForensicError("Cannot write file") if internalpath.find("/./") == 0: internalpath = internalpath[2:] return dict(instruction=hf, todelete=[targetfile])
def init_fat(self, clusters): self.ftb = [] self.maxclus = clusters - 1 ctmp = 0 for ctmp in range(0, clusters): cv = self.get_cluster_value(ctmp) if cv == -1: print ctmp raise ForensicError("Cluster out of bounds") else: self.ftb.append(cv) pass
def get_surface_status(self, candidate, datasize): numofclusters = self.f_size / (self.f_clustersize / self.f_sectorsize) - 1 required = int(datasize / self.f_clustersize) + 1 if candidate < 0 or candidate > numofclusters - required - 1: print candidate, datasize, numofclusters, required raise ForensicError("get_cluster_status: this should not happen") all_free = True for i in range(candidate, candidate + required): if self.get_cluster_status(i) == 1: all_free = False return all_free
def hide_file(self, hfile, image, param={}): mark_used = False try: if param["mark_used"] == "True": mark_used = True except KeyError: pass try: buf = hfile.read() except IOError: raise ForensicError("cannot read secret file") """ Locate enough unallocated space """ spc = self.fs.locate_unallocated_space(len(buf)) if spc == -1: raise ForensicError("Not enough unallcoated space") self.fs.write_location(spc, buf) for c in xrange(int(spc / self.fs.f_clustersize), int((spc + len(buf)) / self.fs.f_clustersize)): self.fs.set_cluster_status(c, 1, mark_used) hf = "location: " + str(spc) + ",length: " + str(len(buf)) return dict(instruction=hf)
def hide_file(self, hfile, image, param = {}): slack = self.fs.get_file_slack() hf = "" if slack == None: errlog("Not enough slack space") raise ForensicError("Not enough slack space") available_slack = 0 for i in slack: if i[2] == 0: available_slack = available_slack + i[1] try: buf = hfile.read() except IOError: raise ForensicError("cannot read secret file") if available_slack < len(buf): raise ForensicError("Not enough slack") bytes_written = 0 bytes_remaining = len(buf) for i in slack: if i[2] != 0: continue if bytes_remaining <= i[1]: self.fs.write_location(i[0],buf[bytes_written:]) hf = hf+","+str(i[0])+":"+str(bytes_remaining) self.fs.register_used_file_slack(i[0],bytes_remaining) if hf.find(",") == 0: hf = hf[1:] return dict(instruction=hf) self.fs.write_location(i[0],buf[bytes_written:bytes_written+i[1]]) self.fs.register_used_file_slack(i[0], i[1]) hf = hf+","+str(i[0])+":"+str(i[1]) bytes_written += i[1] bytes_remaining -= i[1] """ this should never be reached """ raise ForensicError ("This should not happen")
def hide_file(self,hfile,image,param = {}): if self.fs.fs_fstype != "ntfs": raise ForensicError("Alternate data streams work only on NTFS") files = self.fs.get_list_of_files(FLAG_REGULAR) stream_name = "ads" hr = None """ if stream name has been provided, use it, otherwise default to ads""" try: stream_name = param["streamname"] except KeyError: pass try: itr = 0 while True: c = choice(files) itr = itr + 1 if image.check_trivial_usage_status(c.filename) == False: break if itr > 20: raise ForensicError("Cannot find unused trivial files") except IndexError: raise ForensicError("No regular files for ADS") targetfile = self.fs.fs_mountpoint + c.filename + ":" + stream_name if self.fs.mount_image() != 0: raise ForensicError("Cannot mount image") try: wf = open(targetfile,"w") buf = hfile.read() wf.write(buf) wf.close() hr = c.filename+":"+stream_name except IOError: try: wf.close() except IOError: pass finally: raise ForensicError("Cannot write to file") if self.fs.dismount_image() != 0: raise ForensicError("Cannot dismount image") rp = c.filename if rp.find("/./") == 0: rp = rp[2:] if hr.find("/./") == 0: hr = hr[2:] return dict(instruction=hr,path=rp)
def find_file_by_path(self, name): """ Non-deleted file """ for fkey in self.fs_filelist.keys(): if self.fs_filelist[fkey].get_file_name() == name: return self.fs_filelist[fkey].get_link() """ Deleted file """ """ Try to find the corresponding MFT record. pathlist returns "", first, second, etc """ #print >>sys.stderr, "looking for:",name try: path, plainname = name.rsplit("/", 1) pathlist = path.split("/") currdir = 5 for p in pathlist[1:]: #print >>sys.stderr, "path:",p dir_contents = self._return_dir_items_by_mft(currdir) for i in dir_contents: #print >>sys.stderr, " ",i.get_file_name() if i.get_file_name() == p: currdir = i.m_mftnumber break parent = currdir except ValueError: parent = 5 plainname = name #print >>sys.stderr, "File in root:", name #print >>sys.stderr, "parent mft:", parent, plainname finaldir = self._return_dir_items_by_mft(parent) for f in finaldir: #print >>sys.stderr,"qqq:",f.get_file_name() if f.get_file_name() == plainname: return f #for f in self.f_mft: # print >>sys.stderr,"*",f.get_file_name() emesg = "File not found by path:" + name raise ForensicError(emesg)
def hide_file(self, hfile, image, param={}): extensions = [ "jpg", "com", "zip", "xlsx", "doc", "xls", "exe", "dll", "pdf", "rar" ] hf = None dirs1 = self.fs.get_list_of_files(FLAG_DIRECTORY | FLAG_REGULAR) dirs2 = self.fs.get_list_of_files(FLAG_DIRECTORY | FLAG_SYSTEM) """ Process all directories and the root directory """ try: if param["notroot"] == "True": dirs = dirs1 else: dirs = dirs1 + [dirs2[0]] except KeyError: dirs = dirs1 + [dirs2[0]] try: short_targetdir = choice(dirs).filename internalpath = short_targetdir + "/" + os.path.basename(hfile.name) targetfile = self.fs.fs_mountpoint + internalpath targetdir = self.fs.fs_mountpoint + short_targetdir except IndexError: errlog("No directory for hiding") raise ForensicError("No directory for hiding") try: if self.fs.mount_image() != 0: raise ForensicError("Mount failed") tf = open(targetfile, "w") tf.write(hfile.read()) tf.close() """ find extension """ try: mfn, ext = targetfile.rsplit(".", 1) except ValueError: mfn = targetfile ext = "" try: m2, e2 = internalpath.rsplit(".", 1) except ValueError: m2 = targetfile """ remove this extension from the list if it is there """ try: extensions.remove(ext) except ValueError: pass """ count extensions in target directory """ exti = {} dirt = os.listdir(targetdir) for f in dirt: try: fn, e = f.rsplit(".", 1) try: exti[e] += 1 except KeyError: exti[e] = 1 except ValueError: continue """ choose extension """ try: ext_to_use = max(exti, key=exti.get) except ValueError: ext_to_use = choice(extensions) finally: if ext_to_use == ext: ext_to_use = choice(extensions) try: ext_to_use = param["use"] except KeyError: pass new_filename = mfn + "." + ext_to_use os.rename(targetfile, new_filename) hf = m2 + "." + ext_to_use if self.fs.dismount_image() != 0: raise ForensicError("Dismount failed") except IOError: errlog("cannot write file") try: tf.close() except IOError: pass self.fs.dismount_image() raise ForensicError("Cannot write file") if m2.find("/./") == 0: m2 = m2[2:] if hf.find("/./") == 0: hf = hf[2:] try: if param["delete"] == "True": return dict(instruction=hf + " DELETED", path=m2 + "." + ext_to_use, todelete=[new_filename]) except KeyError: return dict(instruction=hf, path=m2 + "." + ext_to_use)
def hide_file(self, hfile, image, param={}): extensions = ["jpg", "bmp", "wav", "au"] files = self.fs.get_list_of_files(FLAG_REGULAR) dirs2 = self.fs.get_list_of_files(FLAG_DIRECTORY | FLAG_SYSTEM) """ Process all directories and the root directory """ try: passphrase = param["passphrase"] except KeyError: passphrase = "foo" tmpdir = "/tmp/" + str(uuid.uuid4()) tfname = os.path.basename(hfile.name) tmppath = tmpdir + "/" + tfname try: os.mkdir(tmpdir) except: raise ForensicError("steganography: cannot create tmp dir") try: yfile = open(tmppath, "w") yfile.write(hfile.read()) yfile.close() except: os.rmdir(tmpdir) raise ForensicError("steganography: cannot write to %s" % tmppath) """ Get a list of candidate files of suitable type """ cfiles = image.find_trivial_files_by_ext(extensions) """ try to steghide """ try: if self.fs.mount_image() != 0: os.remove(tmppath) os.rmdir(tmpdir) raise ForensicError("Steganography: mount failed") while True: c = choice(cfiles) if image.check_trivial_usage_status(c) == False: targetfile = self.fs.fs_mountpoint + c result = call([ "/usr/bin/steghide", "embed", "-p", passphrase, "-q", "-ef", tmppath, "-cf", targetfile, "-e", "none" ], shell=False) if result == 0: break cfiles.remove(c) except IndexError: os.remove(tmppath) os.rmdir(tmpdir) raise ForensicError("No suitable files for steganography") except OSError: os.remove(tmppath) os.rmdir(tmpdir) raise ForensicError("steghide does not exist") try: os.remove(tmppath) os.rmdir(tmpdir) except: raise ForensicError("steganography: cannot remove temp files") if self.fs.dismount_image() != 0: raise ForensicError("Steganography: dismount failed") instr = "%s inside %s, passphrase %s" % (tfname, c, passphrase) try: if param["delete"] == "True": return dict(instruction=instr + " DELETED", todelete=[self.fs.fs_mountpoint + c], path=c) else: return dict(instruction=instr, path=c) except KeyError: return dict(instruction=instr, path=c)
def hide_url(self, trivial_urls=[], secret_urls=[], amount=1, trivial_searches=[], secret_searches=[], param={}): self.get_file("/tmp/forge.TMP") fi = open("/tmp/forge.TMP", "a") for u in trivial_urls: if u.num_clicks < 1: fi.write("b.open_page(\"%s\")" % u.url) fi.write("\n") else: fi.write("b.do_n_clicks(\"%s\", %d,random=False)" % (u.url, u.num_clicks)) fi.write("\n") for u in secret_urls: if u.num_clicks < 1: fi.write("b.open_page(\"%s\")" % u.url) fi.write("\n") else: fi.write("b.do_n_clicks(\"%s\", %d,random=False)" % (u.url, u.num_clicks)) fi.write("\n") fi.write ("b.close()") fi.write("\n") fi.close() tmpdir = "/tmp/Forge."+uuid.uuid4().hex try: os.mkdir(tmpdir) except: raise ForensicError("make temp dir") self.prepare_container() self.send_file("/tmp/forge.TMP") resl=[] i=0 while i < amount: i += 1 result_path = self.exec_file() if result_path == "None": resl.append(dict(status="Fail", fname=None,size=0)) else: try: rloc = check_output([self.chelper.binary,"lxc", "copy_result", self.chelper.rootdir+result_path, tmpdir], shell=False).rstrip() except: raise ForensicError("copy results"); try: historysize = str(int(os.path.getsize(rloc)/1000000)+8)+"M" except: raise ForensicError("Cannot stat results") resl.append(dict(status="OK", fname=rloc, size=historysize)) self.delete_container() return dict(status=0,message="",results=resl,tdir=tmpdir)
def return_unnamed_data(self): try: return self.m_qdata[None] except KeyError: raise ForensicError("Cannot locate unnamed data attribute");
def query_std_time(self): for f in self.m_attributes: if isinstance(f,_NTFSAttributeStandard): return f.a_time raise ForensicError("Standard time attribute not found")
def query_fname_time(self): for f in self.m_attributes: if isinstance(f,_NTFSAttributeFileName): return f.a_time raise ForensicError("Filename time attribute not found")
def locate_unallocated_space(self, datasize): required = int(datasize / self.f_clustersize) + 1 q = self.f_fat.find_consecutive_empty(required) if q == -1: raise ForensicError("Not enough unallocated space") return self.locate_cluster(q)
def get_file(self, dst): try: copyfile(self.chelper.wsrc, dst) except: raise ForensicError("get_file")