/
exchange_enum.go
executable file
·110 lines (93 loc) · 2.99 KB
/
exchange_enum.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
//usr/bin/env go run "$0" "$@"; exit "$?"
package main
import (
"crypto/tls"
"fmt"
"metasploit/module"
"msmail"
"net/http"
"strconv"
"strings"
"sync"
)
func main() {
metadata := &module.Metadata{
Name: "Exchange email enumeration",
Description: "Error-based user enumeration for Office 365 integrated email addresses",
Authors: []string{"poptart", "jlarose", "Vincent Yiu", "grimhacker", "Nate Power", "Nick Powers", "clee-r7"},
Date: "2018-11-06",
Type: "single_scanner",
Privileged: false,
References: []module.Reference{},
Options: map[string]module.Option{
"RHOSTS": {Type: "string", Description: "Target endpoint", Required: true, Default: "outlook.office365.com"},
"EMAIL": {Type: "string", Description: "Single email address to do identity test against", Required: false, Default: ""},
"EMAIL_FILE": {Type: "string", Description: "Path to file containing list of email addresses", Required: false, Default: ""},
}}
module.Init(metadata, run_exchange_enum)
}
func run_exchange_enum(params map[string]interface{}) {
email := params["EMAIL"].(string)
emailFile := params["EMAIL_FILE"].(string)
threads, e := strconv.Atoi(params["THREADS"].(string))
ip := params["rhost"].(string)
if e != nil {
module.LogError("Unable to parse 'Threads' value using default (5)")
threads = 5
}
if threads > 100 {
module.LogInfo("Threads value too large, setting max(100)")
threads = 100
}
if email == "" && emailFile == "" {
module.LogError("Expected 'EMAIL' or 'EMAIL_FILE' field to be populated")
return
}
var validUsers []string
if email != "" {
validUsers = o365enum(ip, []string{email}, threads)
}
if emailFile != "" {
validUsers = o365enum(ip, msmail.ImportUserList(emailFile), threads)
}
msmail.ReportValidUsers(ip, validUsers)
}
func o365enum(ip string, emaillist []string, threads int) []string {
limit := threads
var wg sync.WaitGroup
queue := make(chan string)
//limit := 100
/*Keep in mind you, nothing has been added to handle successful auths
so the password for auth attempts has been hardcoded to something
that is not likely to be correct.
*/
pass := "Summer2018876"
URI := "https://" + ip + "/Microsoft-Server-ActiveSync"
var validemails []string
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
for i := 0; i < limit; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
for email := range queue {
responseCode := msmail.WebRequestBasicAuth(URI, email, pass, tr)
if strings.Contains(email, "@") && responseCode == 401 {
module.LogGood(email + " - 401")
validemails = append(validemails, email)
} else if strings.Contains(email, "@") && responseCode == 404 {
module.LogError(fmt.Sprintf("%s - %d", email, responseCode))
} else {
module.LogError(fmt.Sprintf("Unusual Response: %s - %d", email, responseCode))
}
}
}(i)
}
for i := 0; i < len(emaillist); i++ {
queue <- emaillist[i]
}
close(queue)
wg.Wait()
return validemails
}