├── README.md └── usbwatchdog.py /README.md: -------------------------------------------------------------------------------- 1 | # usbWatchdog 2 | 3 | # What is it? 4 | 5 | usbWatchdog monitors for changes with your USB ports. If a change is detected, it will execute various commands, before wiping the RAM and shutting down the machine. 6 | 7 | # Requirements 8 | 9 | sdmem (apt-get install secure-delete) 10 | 11 | - Python packages: 12 | 13 | argparse 14 | 15 | xxtea 16 | 17 | pyudev 18 | 19 | pip3 install xxtea pyudev argparse 20 | 21 | # Usage 22 | 23 | python3 usbwatchdog.py -e (file containing names of files to encrypt) | -d (file containing names of files to decrypt) | -n (file containing names of files to delete) 24 | 25 | # About 26 | 27 | Encryption is handled by the xxtea package - it may not be the most secure encryption in the world, but it's infinitely faster than trying to AES encrypt your data in a hurry before shutting down. Time is of the essence, and we couldn't afford to wait for a more secure encryption method. Use at your own risk. 28 | 29 | Memory wiping is handled by secure-delete, again with the fastest options available (-llf). This is the least secure option for secure-delete but, again, speed is everything and we don't have ten minutes to wait while it writes it with random garbage. 30 | 31 | The nuclear option is there to make sure your shit is gone before shutdown. That simple. Requires a list of filenames - won't work with a list of directories (yet.) 32 | 33 | # Why? What can it be used for? 34 | 35 | The why is simple - proof of concept. This was a mental exercise for myself to see if I could even do it. I wrote the basic program in an afternoon. 36 | 37 | As for the uses - use your imagination. If someone gets a hold of your machine and tries to install something from a usb drive, or use a Rubber Ducky on it, or even tries to copy your data onto a flash drive, this will shut that down fast. 38 | 39 | If your machine is encrypted or has a BIOS password, this should stop them in their tracks. 40 | 41 | # Future plans/ideas/possibilities 42 | 43 | I'm also interested in including the ability to use a paired Bluetooth device instead of a usb device - so if your device is paired to your machine, and the device (or you with the device) are removed from the immediate area the machine wipes and shuts down. 44 | 45 | If you have any ideas or suggestions, let me know. 46 | -------------------------------------------------------------------------------- /usbwatchdog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import os 5 | import subprocess 6 | from getpass import getpass 7 | 8 | try: 9 | import pyudev 10 | except: 11 | print(' [-] Requires pyudev - please install (pip3 install puyudev)') 12 | exit(1) 13 | try: 14 | import xxtea 15 | except: 16 | print(' [-] Requires xxtea - please install (pip3 install pyudev)') 17 | exit(1) 18 | 19 | 20 | def intro(): 21 | print(""" _______ __________ ____ __. _____________________________ 22 | \ \ ____\______ \ |/ _| / _____/\_ _____/\_ ___ \\ 23 | / | \ / _ \| _/ < \_____ \ | __)_ / \ \/ 24 | / | ( <_> ) | \ | \ / \ | \\ \____ 25 | \____|__ /\____/|____|_ /____|__ \/_______ //_______ / \______ / 26 | \/ \/ \/ \/ \/ \/ 27 | \n""") 28 | print('usbWatchdog.py - (c) 2017 NoRKSEC - no rights reserved\n') 29 | 30 | 31 | def cls(): 32 | os.system("cls" if os.name == "nt" else "clear") 33 | 34 | 35 | def panicButton(): 36 | subprocess.call("sdmem -llf", shell="TRUE") 37 | os.popen("shutdown -h now") 38 | 39 | 40 | def encryptFile(fname, key): 41 | uKey = bytes(key, encoding='utf-8') 42 | with open(fname, 'r+b') as input: 43 | plaintext = input.read() 44 | ciphertext = xxtea.encrypt(plaintext, uKey) 45 | input.seek(0) 46 | input.write(ciphertext) 47 | input.truncate() 48 | input.close() 49 | 50 | 51 | def decryptFile(fname, key): 52 | uKey = bytes(key, encoding='utf-8') 53 | with open(fname, 'r+b') as input: 54 | ciphertext = input.read() 55 | plaintext = xxtea.decrypt(ciphertext, uKey) 56 | input.seek(0) 57 | input.write(plaintext) 58 | input.truncate() 59 | input.close() 60 | 61 | 62 | def passPrompt(): 63 | global userKey 64 | userKey = getpass(" [*] Enter key: ") 65 | checkKey = getpass(" [*] Re-enter key: ") 66 | verifyKey = False 67 | while verifyKey == False: 68 | if (len(userKey) != 16): 69 | print(' [-] Key must be 16 characters.') 70 | return False 71 | else: 72 | if userKey != checkKey: 73 | print(' [-] Keys do not match.') 74 | return False 75 | else: 76 | return True 77 | 78 | 79 | def watchdog(encFlag, nukeFlag): 80 | print(' [+] Starting usbWatchdog...') 81 | context = pyudev.Context() 82 | 83 | initList = [] 84 | for device in context.list_devices(subsystem='usb'): 85 | initList.append(device) 86 | checkSum = False 87 | while (checkSum == False): 88 | checkList = [] 89 | for device in context.list_devices(subsystem='usb'): 90 | checkList.append(device) 91 | for i in checkList: 92 | if not i in initList: 93 | checkSum = True 94 | else: 95 | pass 96 | for j in initList: 97 | if not j in checkList: 98 | checkSum = True 99 | else: 100 | pass 101 | if (checkSum == True): 102 | print(' [+] Shit is going down, hang on...') 103 | if encFlag == True: 104 | input_file = open(encFile) 105 | for i in input_file.readlines(): 106 | fileName = os.path.expanduser(i).strip('\n') 107 | print(' [*] Attempting to encrypt file: ' + str(fileName)) 108 | if not os.path.isfile(fileName): 109 | print(' [-] Error: file does not exist. Skipping...') 110 | else: 111 | encryptFile(fileName, userKey) 112 | print(' [+] Successfully encrypted file.') 113 | print(' [+] Finished encrypting file list.') 114 | panicButton() 115 | os._exit(1) 116 | elif nukeFlag == True: 117 | input_file = open(nukeFile) 118 | for i in input_file.readlines(): 119 | fileName = os.path.expanduser(i).strip('\n') 120 | print(' [*] Attempting to nuke file: ' + str(fileName)) 121 | if not os.path.isfile(fileName): 122 | print(' [-] Error: file does not exist. Skipping...') 123 | else: 124 | try: 125 | os.remove(fileName) 126 | print(' [+] ' + fileName + ' successfully removed.') 127 | except: 128 | print(' [-] Unable to remove file.') 129 | panicButton() 130 | os._exit(1) 131 | else: 132 | panicButton() 133 | os._exit(1) 134 | 135 | 136 | def main(): 137 | parser = argparse.ArgumentParser(prog='usbwatchdog.py', description='monitor your usb ports for activity and wipe ram/shutdown if anything is plugged in or removed.') 138 | group = parser.add_mutually_exclusive_group() 139 | group.add_argument('-d', '--decrypt', type=str, help='decrypt files from a list, requires directory and filename of list (e.g.: ./files.txt).') 140 | group.add_argument('-e', '--encrypt', type=str, help='encrypt files from a list when watchdog executes, requires directory and filename of list (e.g., ./files.txt) - will ask for encryption key and then start watchdog.') 141 | group.add_argument('-n', '--nuke', type=str, help='deletes files from a list, requires directory and filename of list (e.g., ./files.txt) - the nuclear option, for when you just want everything gone before shutdown.') 142 | args = parser.parse_args() 143 | global encFlag, userKey, encFile, decFile, nukeFlag, nukeFile 144 | encFlag = False 145 | if (args.decrypt == None) and (args.encrypt == None) and (args.nuke == None): 146 | encFlag = False 147 | nukeFlag = False 148 | watchdog(encFlag, nukeFlag) 149 | elif not args.decrypt == None: 150 | decFile = os.path.expanduser(args.decrypt) 151 | if not os.path.isfile(decFile): 152 | print(' [-] Error: File list to decrypt does not exist. Exiting...') 153 | os._exit(1) 154 | else: 155 | verifyKey = False 156 | while verifyKey == False: 157 | userKey = getpass(" [*] Enter 16-character key: ") 158 | if (len(userKey) == 16): 159 | verifyKey = True 160 | else: 161 | print(' [-] Key must be 16 characters long.') 162 | verifyKey = False 163 | input_file = open(decFile) 164 | for i in input_file.readlines(): 165 | fileName = os.path.expanduser(i).strip('\n') 166 | print(' [*] Attempting to decrypt: ' + fileName) 167 | if not os.path.isfile(fileName): 168 | print(' [-] File does not exist. Skipping...') 169 | break 170 | else: 171 | try: 172 | decryptFile(fileName, userKey) 173 | print(' [+] File successfully decrypted.') 174 | except: 175 | print(' [-] Error decrypting file. Is the key correct?') 176 | elif not args.encrypt == None: 177 | encFile = os.path.expanduser(args.encrypt) 178 | if not os.path.isfile(encFile): 179 | print(' [-] File list to encrypt does not exist. Skipping encryption...') 180 | encFlag = False 181 | nukeFlag = False 182 | watchdog(encFlag, nukeFlag) 183 | else: 184 | print(' [*] Establishing key for file encryption. Key entered must be 16 characters long.') 185 | isSame = False 186 | while isSame == False: 187 | isSame = passPrompt() 188 | if isSame == False: 189 | print(' [-] Error with key entered.') 190 | else: 191 | print(' [+] Key set.') 192 | encFlag = True 193 | nukeFlag = False 194 | watchdog(encFlag, nukeFlag) 195 | elif not args.nuke == None: 196 | nukeFile = os.path.expanduser(args.nuke) 197 | if not os.path.isfile(nukeFile): 198 | print(' [-] File list to nuke does not exist. Disarming nuclear option...') 199 | encFlag = False 200 | nukeFlag = False 201 | watchdog(encFlag, nukeFlag) 202 | else: 203 | print(' [+] Nuclear option online - say Goodbye to Moscow.') 204 | encFlag = False 205 | nukeFlag = True 206 | watchdog(encFlag, nukeFlag) 207 | 208 | if __name__ == '__main__': 209 | cls() 210 | intro() 211 | main() 212 | --------------------------------------------------------------------------------