From a20c041f3ed6b6a5bef0b9a83a10340a617042ba Mon Sep 17 00:00:00 2001 From: Imanol-Mikel Barba Sabariego Date: Tue, 25 Oct 2016 16:57:34 +0200 Subject: [PATCH] winreg module implemented. winvol var implemented. mount python module implemented. FAT volume listing implemented. NTFS volume listing improved. --- .idea/workspace.xml | 308 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------------------------------------------------------------------- README.md | 8 ++++++++ __pycache__/mount.cpython-34.pyc | Bin 0 -> 788 bytes __pycache__/runcmd.cpython-34.pyc | Bin 391 -> 0 bytes __pycache__/tomb.cpython-34.pyc | Bin 522 -> 0 bytes __pycache__/winver.cpython-34.pyc | Bin 0 -> 2506 bytes digger.py | 14 ++++++++++---- modules/__pycache__/info.cpython-34.pyc | Bin 929 -> 0 bytes modules/__pycache__/mft.cpython-34.pyc | Bin 1120 -> 0 bytes modules/__pycache__/winreg.cpython-34.pyc | Bin 1002 -> 0 bytes modules/info.py | 1 + modules/winreg.py | 48 +++++++++++++++++++++++++++++++++++++++++++----- mount.py | 18 ++++++++++++++++++ scripts/list_fat.sh | 15 +++++++++++++++ tomb.py | 8 ++++---- vars/__pycache__/ntfsvol.cpython-34.pyc | Bin 1587 -> 0 bytes vars/__pycache__/winvol.cpython-34.pyc | Bin 0 -> 2598 bytes vars/ntfsvol.py | 21 +++++++++++++-------- vars/winvol.py | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ winver.py | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 20 files changed, 448 insertions(+), 137 deletions(-) create mode 100644 README.md create mode 100644 __pycache__/mount.cpython-34.pyc create mode 100644 __pycache__/winver.cpython-34.pyc create mode 100644 mount.py create mode 100755 scripts/list_fat.sh create mode 100644 vars/__pycache__/winvol.cpython-34.pyc create mode 100644 vars/winvol.py create mode 100644 winver.py diff --git a/.idea/workspace.xml b/.idea/workspace.xml index e165abe..0819298 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,12 +2,17 @@ - - + + + + + - + + + @@ -32,112 +37,114 @@ - - + + - - + + - + - - + + - - + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + - + - - + + - + - - + + - - - - - + + + - - + + - - + + - + - - + + - - + + - + - - - - - - - - - - - - + + - - - + + + + + @@ -163,14 +170,20 @@ @@ -181,10 +194,10 @@ DEFINITION_ORDER - @@ -255,6 +268,20 @@ + + + @@ -519,27 +549,27 @@ - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -582,92 +612,138 @@ - + - - + + + + + + + + + + + + - + - - + + - + - - + + - + - - + + - + + + + + + + + + + + + + + + + + - - + + - + - + - - + + - + - - + + + + + + + + + + + + - + - - + + - + - + - - + + - + - + - - + + - + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..7886218 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +REQUIRED PACKAGES +------------------ + +* python3 +* python3-dialog +* sleuthkit +* pev +* ntfs-3g \ No newline at end of file diff --git a/__pycache__/mount.cpython-34.pyc b/__pycache__/mount.cpython-34.pyc new file mode 100644 index 0000000..6c1c495 Binary files /dev/null and b/__pycache__/mount.cpython-34.pyc differ diff --git a/__pycache__/runcmd.cpython-34.pyc b/__pycache__/runcmd.cpython-34.pyc index 488d527..bb6fe47 100644 Binary files a/__pycache__/runcmd.cpython-34.pyc and b/__pycache__/runcmd.cpython-34.pyc differ diff --git a/__pycache__/tomb.cpython-34.pyc b/__pycache__/tomb.cpython-34.pyc index 9e5e46e..5ed0401 100644 Binary files a/__pycache__/tomb.cpython-34.pyc and b/__pycache__/tomb.cpython-34.pyc differ diff --git a/__pycache__/winver.cpython-34.pyc b/__pycache__/winver.cpython-34.pyc new file mode 100644 index 0000000..87f089a Binary files /dev/null and b/__pycache__/winver.cpython-34.pyc differ diff --git a/digger.py b/digger.py index 6d3f122..43175d8 100644 --- a/digger.py +++ b/digger.py @@ -7,6 +7,7 @@ import os import sys import subprocess as sp import tomb +import traceback sys.path.append('modules') sys.path.append('vars') @@ -31,9 +32,12 @@ def getModules(): return choiceList def prepareModule(moduleName): - module = __import__(moduleName).getInstance() - module.getVars() - return module + try: + module = __import__(moduleName).getInstance() + module.getVars() + return module + except Exception as e: + raise Exception("[" + moduleName + "] " + str(e)) locale.setlocale(locale.LC_ALL, '') d = Dialog(dialog="dialog",autowidgetsize=True) @@ -42,7 +46,7 @@ d.set_background_title("Gravedigger") moduleList = getModules() code,value = d.inputbox("Input computer's name") if code == d.OK: - tomb.__MACHINE_NAME__ = value + tomb._MACHINE_NAME= value d.set_background_title("Gravedigger - " + value) code, tags = d.checklist("Select modules to execute", choices=moduleList + [("all","Execute all modules",False)], @@ -65,6 +69,7 @@ if code == d.OK: module.run() except Exception as e: print("Exception raised while running " + module.name + ": " + str(e)) + traceback.print_exc() code, tag = d.menu("All modules finished execution",choices=[("Poweroff","Shutdown the computer"), ("Reboot","Reboot the computer"), @@ -78,5 +83,6 @@ if code == d.OK: except Exception as e: print("Exception raised while preparing module: " + str(e)) + traceback.print_exc() diff --git a/modules/__pycache__/info.cpython-34.pyc b/modules/__pycache__/info.cpython-34.pyc index b7b63fa..6d588e3 100644 Binary files a/modules/__pycache__/info.cpython-34.pyc and b/modules/__pycache__/info.cpython-34.pyc differ diff --git a/modules/__pycache__/mft.cpython-34.pyc b/modules/__pycache__/mft.cpython-34.pyc index d021b14..1e185af 100644 Binary files a/modules/__pycache__/mft.cpython-34.pyc and b/modules/__pycache__/mft.cpython-34.pyc differ diff --git a/modules/__pycache__/winreg.cpython-34.pyc b/modules/__pycache__/winreg.cpython-34.pyc index 2c4d4be..18cc46a 100644 Binary files a/modules/__pycache__/winreg.cpython-34.pyc and b/modules/__pycache__/winreg.cpython-34.pyc differ diff --git a/modules/info.py b/modules/info.py index a0b25ba..98c7ff1 100644 --- a/modules/info.py +++ b/modules/info.py @@ -17,4 +17,5 @@ class INFOModule(Module): def run(self): path = tomb.getPath() + self.name + "/" os.mkdir(path) + #TODO #getinfo diff --git a/modules/winreg.py b/modules/winreg.py index b55581f..73000ab 100644 --- a/modules/winreg.py +++ b/modules/winreg.py @@ -1,7 +1,9 @@ from module import Module -from runcmd import runProcess import tomb import os +import winver +from runcmd import runProcess +from mount import mount,umount def getInstance(): return RegistryModule() @@ -11,13 +13,49 @@ class RegistryModule(Module): def __init__(self): self.name = "winreg" self.description = "Extracts Windows Registry files" - self.requiredVars = ["ntfsvol"] + self.requiredVars = ["winvol"] self.vars = {} def run(self): path = tomb.getPath() + self.name + "/" os.mkdir(path) - for vol in self.vars['ntfsvol'].value: - pass - #runstuff + for vol in self.vars['winvol'].value: + mntpoint = "/mnt/" + mntid = mount("/dev/" + vol) + mntpoint += mntid + files = [] + windir = winver.getWindowsDirectory(mntpoint) + if windir == None: + raise Exception("No Windows installation present") + version = winver.getWindowsVersion(mntpoint) + profiles = winver.getUserProfiles(mntpoint) + if version <= winver._WIN_ME: + #9x + files = [windir + "USER.DAT",windir + "SYSTEM.DAT"] + if(len(profiles) > 0): + for profile in profiles: + if(os.path.isfile(profile + "USER.DAT")): + files += [profile + "USER.DAT"] + if version == winver._WIN_ME: + #ME + files += [windir + "CLASSES.DAT"] + + elif version > winver._WIN_ME: + #NT + files += [windir + "/System32/config/SAM" ] + files += [windir + "/System32/config/SECURITY"] + files += [windir + "/System32/config/SOFTWARE"] + files += [windir + "/System32/config/SYSTEM"] + files += [windir + "/System32/config/DEFAULT"] + for profile in profiles: + files += [profile + "/NTUSER.DAT"] + if version > winver._WIN_NT and version < winver._WIN_VISTA: + #2k XP 2k3 + files += [profile + "/Local Settings/Application Data/Microsoft/Windows/UsrClass.dat"] + else: + #Vista+ + files += [profile + "/AppData/Local/Microsoft/Windows/UsrClass.dat"] + print(files) + runProcess(["tar","-czvf",path + "winreg_" + vol + ".tar.gz"] + files) + umount(mntid) diff --git a/mount.py b/mount.py new file mode 100644 index 0000000..259d1b8 --- /dev/null +++ b/mount.py @@ -0,0 +1,18 @@ +import uuid +import os +from runcmd import runProcess + +def mount(device): + mountID = str(uuid.uuid4()) + os.mkdir("/mnt/" + mountID) + output, code = runProcess(["mount","-o","ro",device,"/mnt/" + mountID]) + if code != 0: + raise Exception("Unable to mount " + device) + return mountID + + +def umount(mountID): + output, code = runProcess(["umount","/mnt/" + mountID]) + if code != 0: + raise Exception("Unable to umount " + mountID) + os.rmdir("/mnt/" + mountID) \ No newline at end of file diff --git a/scripts/list_fat.sh b/scripts/list_fat.sh new file mode 100755 index 0000000..ec907f5 --- /dev/null +++ b/scripts/list_fat.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Outputs, separated by newlines, the list of FAT volumes present on this computer + +for disk in $(cat /proc/partitions | awk -F " " '{print $NF}' | tail -n+3); do + HEADER=$(dd if="/dev/$disk" bs=1 skip=82 count=5 2> /dev/null) + if [[ $HEADER == "FAT32" ]]; then + echo $disk + else + HEADER=$(dd if="/dev/$disk" bs=1 skip=54 count=5 2> /dev/null) + if [[ $HEADER == "FAT16" || $HEADER == "FAT12" ]]; then + echo $disk + fi + fi +done \ No newline at end of file diff --git a/tomb.py b/tomb.py index f8d04ac..61bf0d0 100644 --- a/tomb.py +++ b/tomb.py @@ -1,13 +1,13 @@ import os -__ROOT_PATH__ = "/bones/" -__MACHINE_NAME__ = "JOHN_DOE" +_ROOT_PATH = "/bones/" +_MACHINE_NAME = "JOHN_DOE" def __getTomb__(): - return __MACHINE_NAME__ + return _MACHINE_NAME def getPath(): - path = __ROOT_PATH__ + __getTomb__() + "/" + path = _ROOT_PATH + __getTomb__() + "/" if not os.path.exists(path): os.makedirs(path) return path \ No newline at end of file diff --git a/vars/__pycache__/ntfsvol.cpython-34.pyc b/vars/__pycache__/ntfsvol.cpython-34.pyc index e54105b..ccd6034 100644 Binary files a/vars/__pycache__/ntfsvol.cpython-34.pyc and b/vars/__pycache__/ntfsvol.cpython-34.pyc differ diff --git a/vars/__pycache__/winvol.cpython-34.pyc b/vars/__pycache__/winvol.cpython-34.pyc new file mode 100644 index 0000000..fe22bc8 Binary files /dev/null and b/vars/__pycache__/winvol.cpython-34.pyc differ diff --git a/vars/ntfsvol.py b/vars/ntfsvol.py index e0715c3..2cbb478 100644 --- a/vars/ntfsvol.py +++ b/vars/ntfsvol.py @@ -15,18 +15,23 @@ class NTFSVol(Modulevar): def getNTFSVolumes(self): result = runProcess("scripts/list_ntfs.sh") - volumes = result[0].decode("utf-8").splitlines() - print(volumes) - choices = [] - for vol in volumes: - choices.append((vol,"",False)) - return choices + resultlst =result[0].decode("utf-8").splitlines() + volumes = [] + for res in resultlst: + output,code = runProcess(["ntfslabel","/dev/" + res]) + volumes.append((res,output.decode("utf-8"))) + return volumes def query(self): d = Dialog(dialog="dialog", autowidgetsize=True) d.set_background_title("[" + self.parentModule + "] Setting variable: ntfsvol") - volumeList = self.getNTFSVolumes() - code, vols = d.checklist("Select NTFS volumes to extract the MFT", + volumes = self.getNTFSVolumes() + if(len(volumes) == 0): + raise Exception("[" + self.name + "] No Windows Volumes found") + volumeList = [] + for vol in volumes: + volumeList.append((vol[0],vol[1], False)) + code, vols = d.checklist("Select NTFS volumes", choices=volumeList, title="Module selection") if code == d.OK: diff --git a/vars/winvol.py b/vars/winvol.py new file mode 100644 index 0000000..722b7c0 --- /dev/null +++ b/vars/winvol.py @@ -0,0 +1,63 @@ +from modulevar import Modulevar +from dialog import Dialog +from runcmd import runProcess +import winver +from mount import mount,umount + +def getInstance(modname): + return WinVol(modname) + +class WinVol(Modulevar): + + def __init__(self,modname): + self.name = "winvol" + self.parentModule = modname + self.description = "Windows Volume" + self.value = None + + def getNTFSVolumes(self): + result = runProcess("scripts/list_ntfs.sh") + resultlst =result[0].decode("utf-8").splitlines() + volumes = [] + for res in resultlst: + output,code = runProcess(["ntfslabel","/dev/" + res]) + volumes.append((res,output.decode("utf-8"))) + return volumes + + def getFATVolumes(self): + result = runProcess("scripts/list_fat.sh") + resultlst =result[0].decode("utf-8").splitlines() + volumes = [] + for res in resultlst: + output,code = runProcess(["dosfslabel","/dev/" + res]) + volumes.append((res,output.decode("utf-8"))) + return volumes + + def getWindowsVolumes(self): + volumes = self.getNTFSVolumes() + self.getFATVolumes() + winvols = [] + for volume in volumes: + mntpoint = "/mnt/" + mntid = mount("/dev/" + volume[0]) + mntpoint += mntid + if(winver.getWindowsDirectory(mntpoint) != None): + winvols.append(volume) + umount(mntid) + return winvols + + def query(self): + d = Dialog(dialog="dialog", autowidgetsize=True) + d.set_background_title("[" + self.parentModule + "] Setting variable: winvol") + volumes = self.getWindowsVolumes() + if(len(volumes) == 0): + raise Exception("[" + self.name + "] No Windows Volumes found") + volumeList = [] + for vol in volumes: + volumeList.append((vol[0],vol[1], False)) + code, vols = d.checklist("Select Windows volumes", + choices=volumeList, + title="Module selection") + if code == d.OK: + self.value = vols + else: + raise Exception("[" + self.name + "] Operation Cancelled") \ No newline at end of file diff --git a/winver.py b/winver.py new file mode 100644 index 0000000..e69d95a --- /dev/null +++ b/winver.py @@ -0,0 +1,81 @@ +import os +from runcmd import runProcess +import re + +_WIN_9x = 0 +_WIN_ME = 1 +_WIN_NT = 2 +_WIN_2k = 3 +_WIN_XP = 4 +_WIN_2k3 = 5 +_WIN_VISTA = 6 +_WIN_2k8 = 6 +_WIN_7 = 7 +_WIN_2k8R2 = 7 +_WIN_8 = 8 +_WIN_2k12 = 8 +_WIN_81 = 9 +_WIN_2k12R2 = 9 +_WIN_10 = 10 + + + +def getWindowsVersion(path): + if(os.path.isfile(getWindowsDirectory(path) + "/System32/ntdll.dll")): + output,code = runProcess(["pev","-p",getWindowsDirectory(path) + "/System32/ntdll.dll"]) + version = output.decode("utf-8") + if re.match("(3|4)\.",version) != None: + return _WIN_NT + elif re.match("5\.0",version) != None: + return _WIN_2k + elif re.match("5\.1", version) != None: + return _WIN_XP + elif re.match("5\.2", version) != None: + return _WIN_2k3 + elif re.match("6\.0", version) != None: + return _WIN_VISTA + elif re.match("6\.1", version) != None: + return _WIN_7 + elif re.match("6\.2", version) != None: + return _WIN_8 + elif re.match("6\.3", version) != None: + return _WIN_81 + elif re.match("10\.", version) != None: + return _WIN_10 + else: + if(os.path.isfile(getWindowsDirectory(path) + "/CLASSES.DAT")): + return _WIN_ME + return _WIN_9x + +def getWindowsDirectory(path): + result,code = runProcess(["find",path,"-xdev","-iname","explorer.exe","-print","-quit"]) + if(result.decode("utf-8") == ""): + return None + matches = result.decode("utf-8").splitlines() + #WARNING: ONLY CONSIDERING FIRST MATCH + #TODO: Improve + return os.path.dirname(os.path.realpath(matches[0])) + +def getUserProfiles(path): + version = getWindowsVersion(path) + if version < _WIN_XP: + profilepath = getWindowsDirectory(path) + "/Profiles" + if (os.path.exists(profilepath)): + return [profilepath + prof for prof in os.listdir(profilepath)] + return [] + elif version == _WIN_XP: + profilepath = path + "/Documents and Settings" + if (os.path.exists(profilepath)): + return [profilepath + prof for prof in os.listdir(profilepath)] + return [] + else: + profiles = [] + profilepath = path + "/Users" + print(profilepath) + if (os.path.exists(profilepath)): + for elem in os.listdir(profilepath): + if(os.path.isdir(profilepath + "/" + elem)): + profiles.append(profilepath + "/" + elem) + + return profiles + pass \ No newline at end of file -- libgit2 0.22.2