├── audio └── duck.mp3 ├── README.md ├── .gitignore └── patitohunter.py /audio/duck.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/curiozity/patitohunter/HEAD/audio/duck.mp3 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # patitohunter 2 | 3 | Patito Hunter es una simple herramienta desarrollada en Python para GNU Linux para detectar y bloquear USB Rubber Ducky, conocidos familiarmente como "patito". 4 | 5 | Dependencias: pyusb y pyudev (librerías obligatorias) 6 | 7 | Más información: http://hacking-etico.com/2016/03/14/patito-hunter/ 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | 55 | # Sphinx documentation 56 | docs/_build/ 57 | 58 | # PyBuilder 59 | target/ 60 | 61 | #Ipython Notebook 62 | .ipynb_checkpoints 63 | -------------------------------------------------------------------------------- /patitohunter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | __author__ = "Miguel A. Arroyo - @miguel_arroyo76" 3 | __version__ = "0.1" 4 | __banner__ = """ 5 | _____ _ _ _ _ _ _ 6 | | __ \ | | (_)| | | | | | | | 7 | | |__) |__ _ | |_ _ | |_ ___ | |__| | _ _ _ __ | |_ ___ _ __ 8 | | ___// _` || __|| || __|/ _ \ | __ || | | || '_ \ | __|/ _ \| '__| 9 | | | | (_| || |_ | || |_| (_) | | | | || |_| || | | || |_| __/| | 10 | |_| \__,_| \__||_| \__|\___/ |_| |_| \__,_||_| |_| \__|\___||_| 11 | 12 | 14th March 2016 13 | """ 14 | __credit__ = __banner__ + " Version: " + __version__ + "\n By " + __author__ 15 | 16 | import sys 17 | import usb.core 18 | import usb.util 19 | import pyudev 20 | from pygame import mixer 21 | 22 | def get_connected_devices(): # Return a list with connected devices 23 | return [(hex(device.idVendor), hex(device.idProduct)) for device in usb.core.find(find_all=True)] 24 | 25 | def play_audio(): 26 | mixer.init() 27 | mixer.music.load('audio/duck.mp3') 28 | mixer.music.play() 29 | 30 | def check_for_badusb(cfg, intf, dev, interface): 31 | if cfg.bNumInterfaces == 1 and intf.bInterfaceClass == 3 and intf.bInterfaceSubClass == 1: 32 | print "Atention! Probably a BadUsb" 33 | print "Device not mounted! Disconnect the device!" 34 | play_audio() 35 | else: 36 | usb.util.release_interface(dev, interface) # Release the device 37 | dev.attach_kernel_driver(interface) # Reattach the device to the OS Kernel 38 | 39 | def analyse_configurations(dev, interface): 40 | for cfg in dev: 41 | print "Number of interfaces: ", cfg.bNumInterfaces 42 | intf = usb.util.find_descriptor(cfg, bInterfaceNumber=0) 43 | print "Interface Class: ", intf.bInterfaceClass 44 | if intf.bInterfaceClass == 3: 45 | print "Device Type: HID" 46 | print "Interface SubClass: ", intf.bInterfaceSubClass 47 | if intf.bInterfaceSubClass == 1: 48 | print "Protocol: Boot Protocol" 49 | check_for_badusb(cfg, intf, dev, interface) 50 | 51 | def inspect_added_usb(initial_devices): 52 | idV, idP = list(set(get_connected_devices()) - set(initial_devices))[0] 53 | dev = usb.core.find(idVendor=int(idV, 16), idProduct=int(idP, 16)) 54 | interface = 0 55 | if dev.is_kernel_driver_active(interface) is True: 56 | print 57 | print "New USB device connected:" 58 | print "Vendor: ", idV 59 | print "Product: ", idP 60 | dev.detach_kernel_driver(interface) # Detaching Kernel driver 61 | usb.util.claim_interface(dev, interface) # Claiming the device 62 | analyse_configurations(dev, interface) 63 | 64 | def main(): 65 | initial_devices = get_connected_devices() 66 | 67 | monitor = pyudev.Monitor.from_netlink(pyudev.Context()) 68 | monitor.filter_by(subsystem='usb') #Filtering only for usb devices 69 | monitor.start() 70 | 71 | for usb in iter(monitor.poll, None): 72 | if usb.action == "add": 73 | inspect_added_usb(initial_devices) 74 | 75 | if __name__ == '__main__': 76 | print __credit__ 77 | main() --------------------------------------------------------------------------------