├── code ├── img └── banner.png ├── requirements.txt ├── go.mod ├── install.sh ├── printcolors.py ├── LICENSE ├── README.md ├── go.sum ├── scan ├── .gitignore ├── main.go └── scan.py /code: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xadhrit/d9scan/HEAD/img/banner.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.9.3 2 | requests==2.26.0 3 | urllib3==1.26.6 4 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module main.go 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/google/gopacket v1.1.19 // indirect 7 | golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ "$OSTYPE" == "linux-gnu" || "darwin" || "cygwin" || "msys" || "freebsd" ]]; 4 | then 5 | echo -e "Donwloading requirements\n" 6 | python3 -m pip install -r requirements.txt && python3 scan.py -h 7 | 8 | else 9 | echo -e "Donwloading requirements\n" 10 | python -m pip install -r requirements.txt && python scan.py -h 11 | 12 | fi 13 | 14 | exit 0 15 | 16 | -------------------------------------------------------------------------------- /printcolors.py: -------------------------------------------------------------------------------- 1 | """enable some pretty colors 2 | colors module 3 | 4 | """ 5 | 6 | import sys 7 | 8 | if sys.platform.lower().startswith(('os','win','darwin','ios')): 9 | end = red = white = green = yellow = run = bad = good = info = que = '' 10 | 11 | else: 12 | white = '\033[97m' 13 | blue = '\033[94m' 14 | green = '\033[92m' 15 | red = '\033[91m' 16 | yellow = '\033[93m' 17 | end = '\033[0m' 18 | bold = '\033[1m' 19 | back = '\033[7;91m' 20 | info = '\033[93m[!]\033[0m' 21 | que = '\033[94m[?]\033[0m' 22 | bad = '\033[91m[-]\033[0m' 23 | good = '\033[92m[+]\033[0m' 24 | run = '\033[97m[~]\033[0m' 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ADHRIT. (github.com/xadhrit) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # d9scan 2 | ### Python Network Scanner with Backdoor Detection on Network 3 | 4 | d9scan is a script written in Python3 that allows port scanning, Backdoor Detection on networks. The program is interactive and simply requires you to run it to begin. Obtain open ports , asks for option which script you want to run. All scripts are backed by NMAP. 5 | 6 | 7 |

8 | d9scan 9 |

10 | 11 | ``` 12 | **Usage** 13 | 14 | ./d9scan~$ python3 scan.py 15 | 16 | 17 | ``` 18 | 19 | or 20 | 21 | ``` 22 | ~$ chmod +x scan.sh 23 | ~$ ./scan.sh 24 | 25 | ``` 26 | 27 | **Scripts** 28 | 29 | ```bash 30 | > nmap -v -A scan 31 | > http-malware-host Detection (recommanded malware detection) 32 | > http-dlink-backdoor Detection (dlink backdoor detection) 33 | > ftp-proftpd-backdoor Detection (ftp proftpd detection runs on port 21) 34 | 35 | ``` 36 | 37 | ## Requirements 38 | Python3 must be installed on your system in order to function 39 | Install bs4 via pip using `pip install bs4` 40 | 41 | or 42 | 43 | ``` 44 | chmod +x install.sh 45 | 46 | ./install.sh 47 | ``` 48 | 49 | ## Installation 50 | 51 | **Install via Git** 52 | 53 | ```bash 54 | git clone https://github.com/xadhrit/d9scan.git 55 | ``` 56 | 57 | ```bash 58 | sudo ln -s $(pwd)/scan.py /usr/local/bin/scan 59 | ``` 60 | 61 | **SYN protection Detection** 62 | 63 | ``` 64 | go run main.go 65 | ``` 66 | 67 | ## LICENSE 68 | *Distributed under MIT LICENSE* 69 | 70 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 2 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 3 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 4 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 5 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 6 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 7 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 8 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 9 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 10 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 11 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= 12 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 13 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 14 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 15 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 16 | -------------------------------------------------------------------------------- /scan: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | CYAN="\e[36m" 4 | GREEN="\e[32m" 5 | ENDCOLOR="\e[0m" 6 | 7 | echo -e "${GREEN}" 8 | pyfiglet d9scan 9 | 10 | printf "${CYAN} d9scan from shell :) \n\n" 11 | printf "Enter target's domain or IP : " 12 | read IP 13 | 14 | function options(){ 15 | echo -e "${ENDCOLOR}----------------- Choose One option -----------------------${GREEN} " 16 | echo -e " 1 for http-malware-host scan" 17 | echo -e " 2 for http-dlink-backdoor scan" 18 | echo -e " 3 for ftp-proftpd-backdoor scan" 19 | echo -e " 4 for all " 20 | echo -e " 5 Exit " 21 | read OPTION 22 | 23 | 24 | if [[ $OPTION == '1' ]] ; 25 | then 26 | echo -e "${GREEN} nmap -sv --script=http-malware-host ${IP} \n" 27 | nmap -sV --script=http-malware-host $IP 28 | elif [[ $OPTION == '2' ]] ; 29 | then 30 | echo -e "${GREEN} nmap -sV --script http-dlink-backdoor ${IP}\n " 31 | nmap -sV --script http-dlink-backdoor $IP 32 | elif [[ $OPTION == '3' ]]; 33 | then 34 | echo -e "${GREEN} nmap --script ftp-proftpd-backdoor -p 21 ${IP}\n " 35 | nmap --script ftp-proftpd-backdoor -p 21 $IP 36 | elif [[ $OPTION == '4' ]] ; 37 | then 38 | echo -e "${CYAN} Running all Scripts\n " 39 | nmap -sV --script=http-malware-host $IP 40 | nmap -sV --script http-dlink-backdoor $IP 41 | nmap --script ftp-proftpd-backdoor -p 21 $IP 42 | elif [[ $OPTION == '5' ]]; 43 | then 44 | exit 0 45 | else 46 | printf "Invalid Option, Exiting..... \n" 47 | exit 0 48 | fi 49 | 50 | } 51 | echo -e "${GREEN} nmap -v -A ${IP}" 52 | nmap -v -A $IP 53 | options 54 | exit 55 | -------------------------------------------------------------------------------- /.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 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # Tool specific extensions 132 | *.grep 133 | *.nmap 134 | *.xml 135 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // port scanning through syn-flood protections 2 | /* 3 | For ensure if a service exist on a port : 4 | if you receive any additional packets from the target after you've established a connection. 5 | 1. Capture the packets 6 | 2. Check if they are trasmitted with a TCP flag (CWR,ECE,URG, ACK, PSH, RST, SYN, FIN) 7 | */ 8 | 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | "log" 14 | "net" 15 | "os" 16 | "strings" 17 | "time" 18 | 19 | "github.com/google/gopacket" 20 | "github.com/google/gopacket/pcap" 21 | ) 22 | 23 | var ( 24 | snaplen = int32(320) 25 | promise = true 26 | timeout = pcap.BlockForever 27 | filter = "tcp[13] == 0x11 ot tcp[13] == 0x10 or tcp[13] == 0x18" 28 | /* 29 | only looking for 30 | * ACK && FIN : 0x11 31 | * ACK: 0x10 32 | * ACK and PSH 0x18 33 | */ 34 | devFound = false 35 | results = make(map[string]int) 36 | ) 37 | 38 | func capture(targetDev, target string) { 39 | handle, err := pcap.OpenLive(targetDev, snaplen, promise, timeout) 40 | 41 | if err != nil { 42 | log.Panicln(err) 43 | } 44 | 45 | defer handle.Close() 46 | 47 | if err := handle.SetBPFFilter(filter); err != nil { 48 | log.Panicln(err) 49 | } 50 | 51 | source := gopacket.NewPacketSource(handle, handle.LinkType()) 52 | 53 | fmt.Println("Capturing packets") 54 | for packet := range source.Packets() { 55 | networkLayer := packet.NetworkLayer() 56 | if networkLayer == nil { 57 | continue 58 | } 59 | 60 | transportLayer := packet.TransportLayer() 61 | if transportLayer == nil { 62 | continue 63 | } 64 | 65 | sourceHost := networkLayer.NetworkFlow().Src().String() 66 | sourcePort := transportLayer.TransportFlow().Src().String() 67 | 68 | if sourceHost != target { 69 | continue 70 | } 71 | 72 | results[sourcePort] += 1 73 | } 74 | } 75 | 76 | func explode (portString string) ([]string , error){ 77 | ret := make([]string, 0) 78 | 79 | ports := strings.Split(portString, ",") 80 | for _, port := range ports { 81 | port := strings.TrimSpace(port) 82 | ret = append(ret, port) 83 | } 84 | 85 | return ret, nil 86 | } 87 | 88 | 89 | func main() { 90 | if len(os.Args) != 4 { 91 | log.Fatalln("Usage: main.go ") 92 | } 93 | 94 | devices, err := pcap.FindAllDevs() 95 | 96 | if err != nil { 97 | log.Panicln(err) 98 | } 99 | 100 | targetDevice := os.Args[1] 101 | 102 | for _, device := range devices { 103 | if device.Name == targetDevice { 104 | devFound = true 105 | } 106 | } 107 | 108 | if !devFound { 109 | log.Panicf("Device named %s' does not exist\n ", targetDevice) 110 | } 111 | 112 | ip := os.Args[2] 113 | 114 | go capture(targetDevice, ip) 115 | 116 | time.Sleep(1 * time.Second) 117 | 118 | ports, err := explode(os.Args[3]) 119 | 120 | if err != nil { 121 | log.Panicln(err) 122 | } 123 | 124 | for _, port := range ports { 125 | target := fmt.Sprintf("%s %s", ip, port) 126 | 127 | fmt.Println("Trying ", target) 128 | 129 | e, err := net.DialTimeout("tcp", target, 1000*time.Millisecond) 130 | 131 | if err != nil { 132 | continue 133 | } 134 | 135 | e.Close() 136 | } 137 | 138 | time.Sleep(2 * time.Second) 139 | 140 | for port, probability := range results { 141 | if probability >= 1 { 142 | fmt.Println("port %s open (probability: %d)\n", port, probability) 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /scan.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | """ 4 | d9scan - by Adhrit 5 | https://github.com/xadhrit/d9scan 6 | 7 | """ 8 | 9 | import socket 10 | import os 11 | import time 12 | import sys 13 | import argparse 14 | import subprocess 15 | import requests 16 | from printcolors import * 17 | from datetime import datetime 18 | from urllib.parse import urljoin 19 | from bs4 import BeautifulSoup as bs 20 | 21 | # Main Function 22 | def main(): 23 | socket.setdefaulttimeout(0.30) 24 | #argument parser 25 | parser = argparse.ArgumentParser(description='Network Scanning with d9scan') 26 | parser.add_argument('target', type=str, help='Domain or IP address of Target') 27 | args = parser.parse_args() 28 | target = args.target 29 | 30 | # Start scan with clear terminal 31 | subprocess.call('clear', shell=True) 32 | 33 | #welcome d9scan poison banner. 34 | 35 | print(""" 36 | 37 | @@@@@@@@ @@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ 38 | @@@@@@@@ @@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@@ @@@@ @@@ 39 | @@! @@@ @@! @@@ !@@ !@@ @@! @@@ @@!@!@@@ 40 | !@! @!@ !@! @!@ !@! !@! !@! @!@ !@!!@!@! 41 | @!@ !@! !!@!!@!! !!@@!! !@! @!@!@!@! @!@ !!@! 42 | !@! !!! !!@!!! !!@!!! !!! !!!@!!!! !@! !!! 43 | !!: !!! !!! !:! :!! !!: !!! !!: !!! 44 | :!: !:! !:! !:! :!: :!: !:! :!: !:! 45 | :::: :: ::::: :: :::: :: ::: ::: :: ::: :: :: 46 | :: : : : : : :: : : :: :: : : : : :: : """) 47 | print(" \n") 48 | print("%s\t\td9scan - Network Scanner with Backdoor Detection + SYN protection filter scanning "%(yellow)) 49 | 50 | time.sleep(1) 51 | print("\n") 52 | #target = input("Enter your target IP address or URL here: ") 53 | error = ("%sInvalid Input"%red) 54 | try: 55 | t_ip = socket.gethostbyname(target) 56 | except (UnboundLocalError, socket.gaierror): 57 | print("\n%s%sInvalid format. Please use a correct IP or web address\n"%(bad, red)) 58 | sys.exit() 59 | 60 | 61 | print("Scanning target : {} - {} ".format(target,t_ip), end='') 62 | print(" | Time started: "+ str(datetime.now())) 63 | 64 | t1 = datetime.now() 65 | 66 | 67 | def generalscan(target): 68 | 69 | s = "nmap -v -A {}".format(target) 70 | os.mkdir(target) 71 | os.chdir(target) 72 | print("%s"%(green)) 73 | os.system(s) 74 | 75 | 76 | generalscan(target) 77 | t2 = datetime.now() 78 | total = t2 - t1 79 | #print("Port scan completed in "+str(total)) 80 | print("^" * 60) 81 | print("%s Recommended Nmap scan:"%white) 82 | print("-" * 60) 83 | 84 | #print("%snmap -p{ports} -sV -sC -T4 -Pn -oA {ip} {ip}".format(ports=",".join(discovered_ports), ip=target)%blue) 85 | 86 | outfile = "nmap -sV --script=http-malware-host {ip}".format(ip=target) 87 | print(outfile) 88 | print("-" * 60) 89 | backdoor = "nmap -sV --script http-dlink-backdoor {ip}".format(ip=target) 90 | ftpbackdoor = "nmap --script ftp-proftpd-backdoor -p 21 {ip}".format(ip=target) 91 | t3 = datetime.now() 92 | total1 = t3 - t1 93 | 94 | 95 | #Nmap Integration 96 | 97 | def automate(): 98 | choice = '0' 99 | while choice =='0': 100 | print("Would you like to run Nmap or quit to terminal?") 101 | 102 | print("%s0 = Run suggested Nmap scan"%green) 103 | print("%s1 = Run Ftp backdoor Detection "%green) 104 | print("%s2 = Run http-dlink BackDoor Detection"%green) 105 | print("%s3 = Run another d9 scan"%green) 106 | print("%s4 = Exit to terminal"%green) 107 | 108 | choice = input("Option Selection: ") 109 | if choice == "0": 110 | try: 111 | #print(yellow+outfile) 112 | os.mkdir(target) 113 | os.chdir(target) 114 | os.system(outfile) 115 | t3 = datetime.now() 116 | total1 = t3 - t1 117 | print("-" * 60) 118 | print("Malware Detection scan completed in "+str(total1)) 119 | print("") 120 | print("%sPress 1 to go back or enter to quit..."% white) 121 | input() 122 | except FileExistsError as e: 123 | print(e) 124 | exit() 125 | elif choice == "1": 126 | try: 127 | #print(white+ftpbackdoor) 128 | os.mkdir(target) 129 | os.chdir(target) 130 | os.system(ftpbackdoor) 131 | t3 = datetime.now() 132 | total1 = t3-t1 133 | print("Ftp Backdoor Scan completed in "+str(total1)) 134 | print("%sPress 2 to go back and enter to quit..."%white) 135 | uinput = input() 136 | if uinput == '2': 137 | automate() 138 | elif uinput(): 139 | exit() 140 | else: 141 | sys.exit(0) 142 | except FileExistsError as e: 143 | print(e) 144 | exit() 145 | elif choice == "2": 146 | try: 147 | #print(red+backdoor) 148 | os.mkdir(target) 149 | os.chdir(target) 150 | os.system(backdoor) 151 | t3 = datetime.now() 152 | total1 = t3-t1 153 | print("Combined scan completed in " + str(total1)) 154 | print("%s Press 3 to go back and enter to quit..."%white) 155 | uinput = input() 156 | if uinput == '3': 157 | automate() 158 | elif uinput(): 159 | exit() 160 | else: 161 | sys.exit(0) 162 | except FileExistsError as e: 163 | print(e) 164 | exit() 165 | elif choice =="3": 166 | main() 167 | elif choice =="4": 168 | sys.exit() 169 | else: 170 | print("%sPlease make a valid selection"%yellow) 171 | automate() 172 | automate() 173 | 174 | if __name__ == '__main__': 175 | try: 176 | main() 177 | except KeyboardInterrupt: 178 | print("\n%sGoodbye!"%red) 179 | quit() 180 | --------------------------------------------------------------------------------