Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added possibility to read users and passwords from two separate files… #72

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ For more background and information, check out my Troopers 2019 talk, Fun with L
## Usage
Kerbrute has three main commands:
* **bruteuser** - Bruteforce a single user's password from a wordlist
* **bruteforce** - Read username:password combos from a file or stdin and test them
* **bruteforce** - Read username:password combos from a file or stdin or usernames and passwords line by line from two files and test them
* **passwordspray** - Test a single password against a list of users
* **userenum** - Enumerate valid domain usernames via Kerberos

Expand Down Expand Up @@ -50,7 +50,7 @@ Usage:
kerbrute [command]

Available Commands:
bruteforce Bruteforce username:password combos, from a file or stdin
bruteforce Bruteforce username:password combos, from one or two files or stdin
bruteuser Bruteforce a single user's password from a wordlist
help Help about any command
passwordspray Test a single password against a list of users
Expand Down Expand Up @@ -138,9 +138,27 @@ Version: dev (43f9ca1) - 03/06/19 - Ronnie Flathers @ropnop
```

### Brute Force
This mode simply reads username and password combinations (in the format `username:password`) from a file or from `stdin` and tests them with Kerberos PreAuthentication. It will skip any blank lines or lines with blank usernames/passwords. This will generate both event IDs [4768 - A Kerberos authentication ticket (TGT) was requested](https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4768) and [4771 - Kerberos pre-authentication failed](https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4771)
This mode simply reads username and password combinations (in the format `username:password`) from a file or from `stdin` or usernames and passwords line by line from two files and tests them with Kerberos PreAuthentication. It will skip any blank lines or lines with blank usernames/passwords. This will generate both event IDs [4768 - A Kerberos authentication ticket (TGT) was requested](https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4768) and [4771 - Kerberos pre-authentication failed](https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4771)
```
$ cat combos.lst | ./kerbrute -d lab.ropnop.com bruteforce -
$ cat combos.lst | ./kerbrute -d lab.ropnop.com bruteforce

__ __ __
/ /_____ _____/ /_ _______ __/ /____
/ //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
/ ,< / __/ / / /_/ / / / /_/ / /_/ __/
/_/|_|\___/_/ /_.___/_/ \__,_/\__/\___/

Version: dev (n/a) - 05/11/19 - Ronnie Flathers @ropnop

2019/05/11 18:40:56 > Using KDC(s):
2019/05/11 18:40:56 > pdc01.lab.ropnop.com:88

2019/05/11 18:40:56 > [+] VALID LOGIN: [email protected]:Password1234
2019/05/11 18:40:56 > Done! Tested 7 logins (1 successes) in 0.114 seconds



$ ./kerbrute -d lab.ropnop.com bruteforce users.txt passwords.txt

__ __ __
/ /_____ _____/ /_ _______ __/ /____
Expand Down
99 changes: 72 additions & 27 deletions cmd/bruteforce.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ import (

// bruteuserCmd represents the bruteuser command
var bruteForceCmd = &cobra.Command{
Use: "bruteforce [flags] <user_pw_file>",
Short: "Bruteforce username:password combos, from a file or stdin",
Long: `Will read username and password combos from a file or stdin (format username:password) and perform a bruteforce attack using Kerberos Pre-Authentication by requesting at TGT from the KDC. Any succesful combinations will be displayed.
Use: "bruteforce [flags] <user_pw_file> or <user_name_file> <password_file>",
Short: "Bruteforce username:password combos, from one or two files or stdin",
Long: `Will read username and password combos from a file or stdin (format username:password) or usernames and passwords line by line from two files and perform a bruteforce attack using Kerberos Pre-Authentication by requesting at TGT from the KDC. Any succesful combinations will be displayed.
If no domain controller is specified, the tool will attempt to look one up via DNS SRV records.
A full domain is required. This domain will be capitalized and used as the Kerberos realm when attempting the bruteforce.
WARNING: failed guesses will count against the lockout threshold`,
Args: cobra.ExactArgs(1),
Args: cobra.RangeArgs(0, 2),
PreRun: setupSession,
Run: bruteForceCombos,
}
Expand All @@ -29,7 +29,7 @@ func init() {
}

func bruteForceCombos(cmd *cobra.Command, args []string) {
combolist := args[0]
argscount := len(args)
stopOnSuccess = false

combosChan := make(chan [2]string, threads)
Expand All @@ -38,18 +38,36 @@ func bruteForceCombos(cmd *cobra.Command, args []string) {
var wg sync.WaitGroup
wg.Add(threads)

var userfile *os.File
var scanner *bufio.Scanner
if combolist != "-" {
file, err := os.Open(combolist)
if err != nil {
logger.Log.Error(err.Error())
return
}
defer file.Close()
scanner = bufio.NewScanner(file)
} else {
scanner = bufio.NewScanner(os.Stdin)
}
switch argscount {
case 0:
scanner = bufio.NewScanner(os.Stdin)
case 1:
file, err := os.Open(args[0])
if err != nil {
logger.Log.Error(err.Error())
return
}
defer file.Close()
scanner = bufio.NewScanner(file)
case 2:
var err error
userfile, err = os.Open(args[0])
if err != nil {
logger.Log.Error(err.Error())
return
}
defer userfile.Close()

file, err := os.Open(args[1])
if err != nil {
logger.Log.Error(err.Error())
return
}
defer file.Close()
scanner = bufio.NewScanner(file)
}

for i := 0; i < threads; i++ {
go makeBruteComboWorker(ctx, combosChan, &wg)
Expand All @@ -67,17 +85,44 @@ Scan:
if comboline == "" {
continue
}
username, password, err := util.FormatComboLine(comboline)
if err != nil {
logger.Log.Debug("[!] Skipping: %q - %v", comboline, err.Error())
continue
}
time.Sleep(time.Duration(delay) * time.Millisecond)
combosChan <- [2]string{username, password}
}
}
close(combosChan)
wg.Wait()
if userfile != nil {
_, err := userfile.Seek(0, 0)
if err != nil {
logger.Log.Error(err.Error())
break Scan
}
userscanner := bufio.NewScanner(userfile)
for userscanner.Scan() {
select {
case <-ctx.Done():
break Scan
default:
userline := userscanner.Text()
if userline == "" {
continue
}
username, err := util.FormatUsername(userline)
if err != nil {
logger.Log.Debug("[!] Skipping user: %q - %v", userline, err.Error())
continue
}
time.Sleep(time.Duration(delay) * time.Millisecond)
combosChan <- [2]string{username, comboline}
}
}
} else {
username, password, err := util.FormatComboLine(comboline)
if err != nil {
logger.Log.Debug("[!] Skipping: %q - %v", comboline, err.Error())
continue
}
time.Sleep(time.Duration(delay) * time.Millisecond)
combosChan <- [2]string{username, password}
}
}
}
close(combosChan)
wg.Wait()

finalCount := atomic.LoadInt32(&counter)
finalSuccess := atomic.LoadInt32(&successes)
Expand Down