Skip to content

Commit 20800f9

Browse files
committed
Add smtp module
1 parent 5bd393e commit 20800f9

File tree

5 files changed

+177
-0
lines changed

5 files changed

+177
-0
lines changed

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ module GoMapEnum
33
go 1.16
44

55
require (
6+
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e
67
github.com/fatih/color v1.13.0
8+
github.com/nodauf/net-smtp v0.0.0-20220123142515-ae3aa26fb163
79
github.com/spf13/cobra v1.2.1
10+
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
811
)

go.sum

+6
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
3737
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
3838
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
3939
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
40+
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e h1:ZU22z/2YRFLyf/P4ZwUYSdNCWsMEI0VeyrFoI2rAhJQ=
41+
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
4042
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
4143
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
4244
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@@ -192,6 +194,8 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
192194
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
193195
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
194196
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
197+
github.com/nodauf/net-smtp v0.0.0-20220123142515-ae3aa26fb163 h1:ibyr4sPQNrPAK4fGuJxdIyX8tC8ytoTe/ryoQ5YpIRk=
198+
github.com/nodauf/net-smtp v0.0.0-20220123142515-ae3aa26fb163/go.mod h1:bpKTQ3KO0V60W040bsyRGv/w7HxFYDQHGmBwgB4copE=
195199
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
196200
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
197201
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -248,6 +252,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
248252
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
249253
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
250254
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
255+
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
256+
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
251257
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
252258
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
253259
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=

src/cmd/enum/smtp.go

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package enum
2+
3+
import (
4+
"GoMapEnum/src/logger"
5+
"GoMapEnum/src/modules/smtp"
6+
"GoMapEnum/src/orchestrator"
7+
8+
"github.com/spf13/cobra"
9+
)
10+
11+
var smtpOptions smtp.Options
12+
13+
// smtpCmd represents the smtp command
14+
var smtpCmd = &cobra.Command{
15+
Use: "smtp",
16+
Short: "Enumerate email address by connection to the smtp port of the target.",
17+
Long: `
18+
Credits: https://github.com/cytopia/smtp-user-enum`,
19+
Example: `go run main.go userenum smtp -u users -t mail.contoso.com -o validUsers`,
20+
Run: func(cmdCli *cobra.Command, args []string) {
21+
log := logger.New("Enumeration", "SMTP", smtpOptions.Target)
22+
log.SetLevel(level)
23+
log.Info("Starting the module SMTP")
24+
smtpOptions.Log = log
25+
smtpOptions.Proxy = proxy
26+
27+
orchestratorOptions := orchestrator.Orchestrator{}
28+
orchestratorOptions.PreActionUserEnum = smtp.PrepareSMTPConnections
29+
orchestratorOptions.UserEnumFunc = smtp.UserEnum
30+
orchestratorOptions.PostActionUserEnum = smtp.CloseSMTPConnections
31+
validUsers = orchestratorOptions.UserEnum(&smtpOptions)
32+
33+
},
34+
}
35+
36+
func init() {
37+
38+
smtpCmd.Flags().StringVarP(&smtpOptions.Domain, "domain", "d", "", "Targeted domain ")
39+
smtpCmd.Flags().StringVarP(&smtpOptions.Mode, "mode", "m", "", "RCPT, VRFY, EXPN (default: RCPT)")
40+
smtpCmd.Flags().StringVarP(&smtpOptions.Users, "user", "u", "", "Username or file containing the usernames")
41+
smtpCmd.Flags().StringVarP(&smtpOptions.Target, "target", "t", "", "Host pointing to the OWA service")
42+
smtpCmd.Flags().IntVar(&smtpOptions.Thread, "thread", 2, "Number of threads")
43+
smtpCmd.MarkFlagRequired("user")
44+
smtpCmd.MarkFlagRequired("target")
45+
smtpCmd.MarkFlagRequired("domain")
46+
}

src/modules/smtp/struct.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package smtp
2+
3+
import (
4+
"GoMapEnum/src/utils"
5+
6+
smtp "github.com/nodauf/net-smtp"
7+
)
8+
9+
// Options for o365 module
10+
type Options struct {
11+
Target string
12+
Domain string
13+
Mode string
14+
utils.BaseOptions
15+
16+
connectionsPool chan *smtp.Client
17+
}
18+
19+
func (options *Options) GetBaseOptions() *utils.BaseOptions {
20+
return &options.BaseOptions
21+
}

src/modules/smtp/userEnum.go

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package smtp
2+
3+
import (
4+
"GoMapEnum/src/utils"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
"time"
9+
10+
smtp "github.com/nodauf/net-smtp"
11+
)
12+
13+
func PrepareSMTPConnections(optionsInterface *interface{}) {
14+
options := (*optionsInterface).(*Options)
15+
options.connectionsPool = make(chan *smtp.Client, options.Thread)
16+
var nbConnectionsRequired int
17+
nbConnectionsRequired = options.Thread
18+
if len(options.UsernameList) < options.Thread {
19+
nbConnectionsRequired = len(options.UsernameList)
20+
}
21+
options.Log.Debug("Preparing a pool of " + strconv.Itoa(nbConnectionsRequired) + " connections")
22+
for i := 1; i <= nbConnectionsRequired; i++ {
23+
client, err := smtp.Dial(options.Target + ":25")
24+
if err != nil {
25+
options.Log.Error("Failed to establish a connection " + err.Error())
26+
continue
27+
}
28+
err = client.Hello(utils.RandomString(6))
29+
if err != nil {
30+
fmt.Println("hello" + err.Error())
31+
}
32+
err = client.Mail(utils.RandomString(6) + "@" + options.Domain)
33+
if err != nil {
34+
fmt.Println("mail" + err.Error())
35+
}
36+
options.connectionsPool <- client
37+
}
38+
}
39+
40+
func UserEnum(optionsInterface *interface{}, username string) bool {
41+
options := (*optionsInterface).(*Options)
42+
valid := false
43+
smtpConnection := <-options.connectionsPool
44+
switch strings.ToLower(options.Mode) {
45+
case "rcpt", "":
46+
err := smtpConnection.Rcpt(username)
47+
if err == nil {
48+
options.Log.Success(username)
49+
valid = true
50+
} else {
51+
options.Log.Debug(username + " => " + err.Error())
52+
options.Log.Fail(username)
53+
}
54+
case "vrfy":
55+
err := smtpConnection.Verify(username)
56+
if err == nil {
57+
options.Log.Success(username)
58+
valid = true
59+
} else {
60+
options.Log.Debug(username + " => " + err.Error())
61+
options.Log.Fail(username)
62+
}
63+
case "expn":
64+
err := smtpConnection.Expand(username)
65+
if err == nil {
66+
options.Log.Success(username)
67+
valid = true
68+
} else {
69+
code := strings.Split(err.Error(), " ")[0]
70+
options.Log.Debug(username + " => " + err.Error())
71+
options.Log.Fail(username)
72+
// If the command is not implemented no need to pursue
73+
if code == "502" {
74+
CloseSMTPConnections(optionsInterface)
75+
options.Log.Fatal("The command is not implemented. No need to pursue using this method.")
76+
}
77+
fmt.Println(code)
78+
}
79+
default:
80+
CloseSMTPConnections(optionsInterface)
81+
options.Log.Fatal("Unrecognised mode: " + options.Mode + ". Only RCPT, VRFY and EXPN are supported.")
82+
}
83+
84+
options.connectionsPool <- smtpConnection
85+
return valid
86+
}
87+
88+
func CloseSMTPConnections(optionsInterface *interface{}) {
89+
options := (*optionsInterface).(*Options)
90+
options.Log.Debug("Closing the pool of connections")
91+
for i := 1; i <= options.Thread; i++ {
92+
select {
93+
case smtpConnection := <-options.connectionsPool:
94+
smtpConnection.Close()
95+
case <-time.After(1 * time.Second):
96+
options.Log.Debug("Something went wrong0 A connection seems already closed")
97+
}
98+
99+
}
100+
close(options.connectionsPool)
101+
}

0 commit comments

Comments
 (0)