diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..77b8381 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +Sabri 'pwnsdx' Haddouche +David 'deekayen' Norman +Tobin 'Brobin' Brown +Nadav 'nadavge' Geva <> +Raúl 'rsrdesarrollo' Sampedro +Mads 'MadsRC' Christensen diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..caf6f47 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +PREFIX = /usr/local +BINPREFIX = $(PREFIX)/bin +MANPREFIX = /usr/share/man +ETCPREFIX = $(PREFIX)/etc/usbkill + +install: + cp usbkill.py $(BINPREFIX)/usbkill.py + mkdir -p $(ETCPREFIX) + cp settings.ini $(ETCPREFIX)/settings.ini + cp doc/man1/usbkill.1 $(MANPREFIX)/man1/ + cp doc/man5/usbkill-settings.ini.5 $(MANPREFIX)/man5/ + +uninstall: + rm -rf $(BINPREFIX)/usbkill.py + rm -rf $(ETCPREFIX) + rm -rf $(MANPREFIX)/man1/usbkill.1 + rm -rf $(MANPREFIX)/man/usbkill-settings.ini.5 diff --git a/doc/man1/usbkill.1 b/doc/man1/usbkill.1 new file mode 100644 index 0000000..512d34c --- /dev/null +++ b/doc/man1/usbkill.1 @@ -0,0 +1,110 @@ +.TH usbkill 1 "1.0-rc.3 (June 2014)" "usbkill" "usbkill manual" + +.SH NAME +usbkill - anti-forensic kill-switch +.SH SYNOPSIS +.B usbkill +.I "[OPTION]" +.SH DESCRIPTION +usbkill is an anti-forensic kill-switch that waits for a change on your +USB ports and then immediately shuts down your computer. + +Some reasons to use this tool: + +* In case the police or other thugs come busting in (or steal your laptop +from you when you are at a public library as happened to Ross). The police +commonly uses a « mouse jiggler » to keep the screensaver and sleep mode +from activating. +.P +* You don’t want someone to retrieve documents (such as private keys) from +your computer or install malware/backdoors via USB. +.P +* You want to improve the security of your (Full Disk Encrypted) home or +corporate server (e.g. Your Raspberry). +.P +.B "[!] Important:" +Make sure to use (partial) disk encryption! Otherwise they will get in +anyway. + +.B "Tip:" +Additionally, you may use a cord to attach a USB key to your +wrist. Then insert the key into your computer and start +.I usbkill. +If they steal your computer, the USB will be removed and the computer +shuts down immediately. + +.SS Feature List +* Compatible with Linux, *BSD and OS X. +.P +* Shutdown the computer when there is USB activity. +.P +* Customizable. Define which commands should be executed just before shut +down. +.P +* Ability to whitelist a USB device. +.P +* Ability to change the check interval (default: 250ms). +.P +* Ability to melt the program on shut down. +.P +* Works with sleep mode (OS X). +.P +* No dependency except srm iff you want +.I usbkill +to delete files/folders +for you. +.P +* Sensible defaults. + +.SH OPTIONS + +.TP +\f3-h --help\f1 +Show help message, exit. +.TP +\f3--version\f1 +Show version of the program, exit. +.TP +\f3--no-shut-down\f1 +If a malicious change on the USB ports is detected, +execute all the (destructive) commands you defined in settings.ini, +but don’t turn off the computer. +.TP +\f3--cs\f1 +Copy program folder settings.ini to /etc/usbkill/settings.ini. + +.SH PLATFORMS +.TP +.I usbkill +is known to work on Linux, *BSD and OSX. + +.SH FILES +.TP +.IP "/usr/local/etc/usbkill/settings.ini" +Configuration file for +.I usbkill. +Use this to define log file placement, device whitelist etc. + +.SH BUGS +.TP +None that we know of. + +.SH AUTHORS +.I usbkill +was written by +.B hephaest0s . +See file +.I AUTHORS +for a list of people contributing to this project. +.P +The +.I git +repository of +.I usbkill +can be found at +.BI https://github.com/hephaest0s/usbkill +.P +This manual page was written by Mads 'MadsRC' Christensen . + +.SH SEE ALSO +.BR usbkill-settings.ini (5) diff --git a/doc/man5/usbkill-settings.ini.5 b/doc/man5/usbkill-settings.ini.5 new file mode 100644 index 0000000..3487d43 --- /dev/null +++ b/doc/man5/usbkill-settings.ini.5 @@ -0,0 +1,116 @@ +.TH usbkill-settings-ini 5 "1.0-rc.3 (June 2014)" "settings.ini" "usbkill manual" +.SH NAME +settings.ini - usbkill configuration file +.SH SYNOPSIS +.B /usr/local/etc/usbkill/settings.ini +.SH DESCRIPTION +.I usbkill(1) +reads configuration data from +.B /usr/local/etc/settings.ini +.P +The possible settings, case-sensitive, are: +.SS whitelist = [] +Whitelist command lists the USB ids that you want whitelisted. How to get +the correct usbid for your trusted USB device? +.P +.B BSD/Linux +.P +run "lsusb", the usbid will looks like this: +.B 0123:9abc +.P +.B Mac OS X +.P +run "system_profiler SPUSBDataType" in the terminal and find the +Vendor/Product ID, it will looks like this: +.P + > Product ID: 0x8403 +.P + > Vendor ID: 0x05ac (Apple Inc.) +.P +Take the 4 characters after the 0x and merge them (Vendor ID first), it +will look like: +.B 05ac:8403 +.P +Other parties can copy your trusted usbid to another usb device! +Use whitelist command and single space separation as follows: +.P +.B whitelist = ["4c2a:d2b0", "0b2d:a2c4"] +.P +To allow multiple (2 and 4) USBs with same id: +[("4c2a:d2b0":2), ("0b2d:a2c4":4)] + +.SS sleep = 0.25 +Allow for a certain amount of sleep time between checks, e.g. 0.25 seconds + +.SS double_usbid_detection = True +Perform USB id copy detection? +This option does not work on all platforms, and can therefore be turned +off. + +.SS log_file = /var/log/usbkill/usbkill.log +Log file location + +.SS melt_usbkill = False +Remove log (folder) and settings (folder) and usbkill program (folder) +upon kill? +This might be usefull if you only encrypt portions of your disk (home +folder or volumes). +Make sure to sync the system (using do_sync=True) if this is a critical +feature for you. +(True/False) + +.SS remove_file_command = srm + use srm to remove files. + try srm --help or [x] to see what options are available + [x] http://srm.sourceforge.net/srm.html + Example: remove_file_command = srm -zlf + +.SS files_to_remove = [] +What files should be removed upon a kill? +Provide absolute paths to the files (paths that start with '/' or '~'). +Use " not ' to define the strings, e.g.: +files_to_remove = ["~/Desktop/contacts.txt", +"~/Desktop/dpr_journal.txt"] + +.SS folders_to_remove = [ ] +What folders should be removed upon a kill? +Provide absolute paths to the files (paths that start with '/' or '~'). +Content in folders will be removed recursively +Use " not ' to define the strings, e.g.: +folders_to_remove = ["~/Desktop/sensitive/", +"~/Desktop/dpr_journal_entries/"] + +.SS do_sync = True +Should usbkill sync the file system for you? +This should not be a problem on most computers. +Sync will save some of your work to disk before killing your computer. + +.SS kill_commands = [ ] +Custom kill commands that can not be specified using above described +mechanisms. +This is where you want to release volumes, etc. +These commands will run in order and as root, as the last commands. +Sync should be activated once more if you want to sync +Use " not ' to define the strings, e.g.: +kill_commands = [ "bash ~/scripts/destroy.sh", "sync" ] + +.SH FILES +.B /usr/local/etc/usbkill/settings.ini + +.SH AUTHORS +.I usbkill +was written by +.B hephaest0s . +See file +.B AUTHORS +for a list of people +contributing to this project. + +The git repository of usbkill can be found at +.I https://github.com/hephaest0s/usbkill + +This manual page was written by Mads 'MadsRC' Christensen + +.SH SEE ALSO +.B usbkill(1) + diff --git a/usbkill.py b/usbkill.py index 358b5f8..767930e 100644 --- a/usbkill.py +++ b/usbkill.py @@ -42,20 +42,20 @@ DEVICE_RE = [ re.compile(".+ID\s(?P\w+:\w+)"), re.compile("0x([0-9a-z]{4})") ] # Set the settings filename here -SETTINGS_FILE = '/etc/usbkill/settings.ini' +SETTINGS_FILE = '/usr/local/etc/usbkill/settings.ini' help_message = """ usbkill is a simple program with one goal: quickly shutdown the computer when a USB is inserted or removed. Events are logged in /var/log/usbkill/kills.log You can configure a whitelist of USB ids that are acceptable to insert and the remove. The USB id can be found by running the command 'lsusb'. -Settings can be changed in /etc/usbkill/settings +Settings can be changed in /usr/local/etc/usbkill/settings In order to be able to shutdown the computer, this program needs to run as root. Options: -h --help: Show this help --version: Print usbkill version and exit - --cs: Copy program folder settings.ini to /etc/usbkill/settings.ini + --cs: Copy program folder settings.ini to /usr/local/etc/usbkill/settings.ini --no-shut-down: Execute all the (destructive) commands you defined in settings.ini, but don't turn off the computer """ @@ -88,11 +88,11 @@ def __add__(self, other): def log(settings, msg): log_file = settings['log_file'] - + contents = '\n{0} {1}\nCurrent state:\n'.format(str(datetime.now()), msg) with open(log_file, 'a+') as log: log.write(contents) - + # Log current USB state if CURRENT_PLATFORM.startswith("DARWIN"): os.system("system_profiler SPUSBDataType >> " + log_file) @@ -101,7 +101,7 @@ def log(settings, msg): def shred(settings): shredder = settings['remove_file_command'] - + # List logs and settings to be removed if settings['melt_usbkill']: settings['folders_to_remove'].append(os.path.dirname(settings['log_file'])) @@ -112,23 +112,23 @@ def shred(settings): else: settings['files_to_remove'].append(os.path.realpath(__file__)) settings['files_to_remove'].append(usbkill_folder + "/settings.ini") - + # Remove files and folders for _file in settings['files_to_remove'] + settings['folders_to_remove']: os.system(shredder + _file) - + def kill_computer(settings): # Log what is happening: if not settings['melt_usbkill']: # No need to spend time on logging if logs will be removed log(settings, "Detected a USB change. Dumping the list of connected devices and killing the computer...") - + # Shred as specified in settings shred(settings) - + # Execute kill commands in order. for command in settings['kill_commands']: os.system(command) - + if settings['do_sync']: # Sync the filesystem to save recent changes os.system("sync") @@ -136,7 +136,7 @@ def kill_computer(settings): # If syncing is risky because it might take too long, then sleep for 5ms. # This will still allow for syncing in most cases. sleep(0.05) - + if settings['shut_down']: # Use argument --no-shut-down to prevent a shutdown. # Finally poweroff computer immediately if CURRENT_PLATFORM.startswith("DARWIN"): @@ -148,7 +148,7 @@ def kill_computer(settings): else: # Linux-based systems - Will shutdown os.system("poweroff -f") - + # Exit the process to prevent executing twice (or more) all commands sys.exit(0) @@ -168,29 +168,29 @@ def check_inside(result, devices): try: result["Built-in_Device"] except KeyError: - + # Check if vendor_id/product_id is available for this one try: assert "vendor_id" in result and "product_id" in result # Append to the list of devices devices.append(DEVICE_RE[1].findall(result["vendor_id"])[0] + ':' + DEVICE_RE[1].findall(result["product_id"])[0]) except AssertionError: {} - + # Check if there is items inside try: # Looks like, do the while again for result_deep in result["_items"]: # Check what's inside the _items array check_inside(result_deep, devices) - + except KeyError: {} - + # Run the loop devices = [] for result in df[0]["_items"]: check_inside(result, devices) return devices - + def lsusb(): # A Python version of the command 'lsusb' that returns a list of connected usbids if CURRENT_PLATFORM.startswith("DARWIN"): @@ -203,9 +203,9 @@ def lsusb(): def program_present(program): if sys.version_info[0] == 3: # Python3 - from shutil import which + from shutil import which return which(program) != None - + else: """ Test if an executable exist in Python2 @@ -224,7 +224,7 @@ def is_exe(fpath): if is_exe(exe_file): return True return False - + def load_settings(filename): # Libraries that are only needed in this function: from json import loads as jsonloads @@ -260,7 +260,7 @@ def get_setting(name, gtype=''): # Read all lines of settings file config.read(filename) - + # Build settings settings = dict({ 'sleep_time' : get_setting('sleep', 'FLOAT'), @@ -276,14 +276,14 @@ def get_setting(name, gtype=''): }) return settings - + def loop(settings): # Main loop that checks every 'sleep_time' seconds if computer should be killed. # Allows only whitelisted usb devices to connect! # Does not allow usb device that was present during program start to disconnect! start_devices = lsusb() acceptable_devices = start_devices + settings['whitelist'] - + # Write to logs that loop is starting: msg = "[INFO] Started patrolling the USB ports every " + str(settings['sleep_time']) + " seconds..." log(settings, msg) @@ -311,7 +311,7 @@ def loop(settings): if settings['double_usbid_detection'] and count > current_devices[device]: # Count of a usbid device is lower than at program start (not enough devices) kill_computer(settings) - + sleep(settings['sleep_time']) def startup_checks(): @@ -325,26 +325,26 @@ def startup_checks(): # Check arguments args = sys.argv[1:] - + # Check for help if '-h' in args or '--help' in args: sys.exit(help_message) - + if '--version' in args: print('usbkill', __version__) sys.exit(0) - + copy_settings = False if '--cs' in args: args.remove('--cs') copy_settings = True - + shut_down = True if '--no-shut-down' in args: print("[NOTICE] Ready to execute all the (potentially destructive) commands, but NOT shut down the computer.") args.remove('--no-shut-down') shut_down = False - + # Check all other args if len(args) > 0: sys.exit("\n[ERROR] Argument not understood. Can only understand -h\n") @@ -365,7 +365,7 @@ def startup_checks(): if not os.path.isdir("/etc/usbkill/"): os.mkdir("/etc/usbkill/") - # On first time use copy settings.ini to /etc/usebkill/settings.ini + # On first time use copy settings.ini to /usr/local/etc/usebkill/settings.ini # If dev-mode, always copy and don't remove old settings if not os.path.isfile(SETTINGS_FILE) or copy_settings: sources_path = os.path.dirname(os.path.realpath(__file__)) + '/' @@ -374,45 +374,45 @@ def startup_checks(): print("[NOTICE] Copying setting.ini to " + SETTINGS_FILE ) os.system("cp " + sources_path + "settings.ini " + SETTINGS_FILE) if not copy_settings: - os.remove(sources_path + "settings.ini") - + os.remove(sources_path + "settings.ini") + # Load settings settings = load_settings(SETTINGS_FILE) settings['shut_down'] = shut_down - + # Make sure no spaces a present in paths to be wiped. for name in settings['folders_to_remove'] + settings['files_to_remove']: if ' ' in name: msg += "[ERROR][WARNING] '" + name + "'as specified in your settings.ini contains a space.\n" sys.exit(msg) - + # Make sure srm is present if it will be used. if settings['melt_usbkill'] or len(settings['folders_to_remove'] + settings['files_to_remove']) > 0: if not program_present('srm'): sys.exit("[ERROR] usbkill configured to destroy data, but srm not installed.\n") if not settings['remove_file_command'].startswith('srm'): sys.exit("[ERROR] remove_file_command should start with `srm'. srm should be used for automated data overwrite.\n") - + # Make sure there is a logging folder log_folder = os.path.dirname(settings['log_file']) if not os.path.isdir(log_folder): os.mkdir(log_folder) - + return settings if __name__=="__main__": # Run startup checks and load settings settings = startup_checks() - + # Define exit handler now that settings are loaded... def exit_handler(signum, frame): print("\n[INFO] Exiting because exit signal was received\n") log(settings, "[INFO] Exiting because exit signal was received") sys.exit(0) - + # Register handlers for clean exit of program for sig in [signal.SIGINT, signal.SIGTERM, signal.SIGQUIT, ]: signal.signal(sig, exit_handler) - + # Start main loop loop(settings)