-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathmongoscram.go
142 lines (112 loc) · 2.97 KB
/
mongoscram.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* Copyright (c) 2017, AverageSecurityGuy
# All rights reserved.
Crack a MongoDB SCRAM hash.
Usage:
$ go run mongoscram.go username password_file salt stored_key
*/
package main
import (
"bufio"
"bytes"
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"fmt"
"golang.org/x/crypto/pbkdf2"
"os"
"strings"
"sync"
)
func calculate_scram(pwd, salt []byte) string {
/*
Calculate the MongoDB SCRAM-SHA-1 hash. It varies from the standard
slightly by calculating the MD5 of the password and hex encoding it before
putting it through the PBKDF2 function.
Thanks @StrangeWill for helping me with that.
*/
digested_password := md5.New()
digested_password.Write(pwd)
hex_md5 := hex.EncodeToString(digested_password.Sum(nil))
salted_password := pbkdf2.Key([]byte(hex_md5), salt, 10000, 20, sha1.New)
client_key := hmac.New(sha1.New, salted_password)
client_key.Write([]byte("Client Key"))
stored_key := sha1.New()
stored_key.Write(client_key.Sum(nil))
return base64.StdEncoding.EncodeToString(stored_key.Sum(nil))
}
func verify_scram(user, pwd, salt []byte, stored_key string) {
/*
Verify that the username/password combination matches the stored_key.
*/
var userpass bytes.Buffer
userpass.Write(user)
userpass.WriteString(":mongo:")
userpass.Write(pwd)
hash := calculate_scram(userpass.Bytes(), salt)
if hash == stored_key {
fmt.Printf("%s:%s\n", user, pwd)
}
}
func main() {
if len(os.Args) != 5 {
fmt.Println("Usage: go run mongoscram.go username password_file salt stored_key")
os.Exit(1)
}
name := os.Args[1]
pwd_file := os.Args[2]
salt := os.Args[3]
stored_key := os.Args[4]
threads := 10
//Decode our salt
salt_byte, err := base64.StdEncoding.DecodeString(salt)
if err != nil {
panic("Could not decode salt.")
}
/*
Everything below this point was blatantly stolen from @TheColonial's
excellent gobuster program. https://github.com/OJ/gobuster
Thanks @TheColonial
*/
// Open our password list
wordlist, err := os.Open(pwd_file)
if err != nil {
panic("Failed to open wordlist")
}
// channels used for comms
wordChan := make(chan string, threads)
// Use a wait group for waiting for all threads to finish
processorGroup := new(sync.WaitGroup)
processorGroup.Add(threads)
// Create goroutines for each of the number of threads
// specified.
for i := 0; i < threads; i++ {
go func() {
for {
word := <-wordChan
// Did we reach the end? If so break.
if word == "" {
break
}
// Mode-specific processing
verify_scram([]byte(name), []byte(word), salt_byte, stored_key)
}
// Indicate to the wait group that the thread
// has finished.
processorGroup.Done()
}()
}
defer wordlist.Close()
// Lazy reading of the wordlist line by line
scanner := bufio.NewScanner(wordlist)
for scanner.Scan() {
word := scanner.Text()
// Skip "comment" lines
if strings.HasPrefix(word, "#") == false {
wordChan <- word
}
}
close(wordChan)
processorGroup.Wait()
}