diff --git a/src/modules/smtp/private.go b/src/modules/smtp/private.go new file mode 100644 index 0000000..8ec0467 --- /dev/null +++ b/src/modules/smtp/private.go @@ -0,0 +1,36 @@ +package smtp + +import ( + "GoMapEnum/src/utils" + + smtp "github.com/nodauf/net-smtp" +) + +func (options *Options) prepareOneConnection(client *smtp.Client) error { + + mailFrom := utils.RandomString(6) + "@" + options.Domain + err := client.Mail(mailFrom) + if err != nil { + //options.Log.Error("Mail From command failed with email: " + mailFrom + " and error " + err.Error()) + return err + } + options.Log.Debug("One connection has been successfully prepared") + + return nil +} + +func (options *Options) createNewConnection() *smtp.Client { + client, err := smtp.Dial(options.Target + ":25") + if err != nil { + options.Log.Error("Failed to establish a connection " + err.Error()) + return nil + } + + hello := utils.RandomString(6) + err = client.Hello(hello) + if err != nil { + options.Log.Error("helo command failed with helo " + hello + " and error " + err.Error()) + return nil + } + return client +} diff --git a/src/modules/smtp/struct.go b/src/modules/smtp/struct.go index 364e7e0..603597b 100644 --- a/src/modules/smtp/struct.go +++ b/src/modules/smtp/struct.go @@ -13,8 +13,9 @@ type Options struct { Mode string utils.BaseOptions - all bool - connectionsPool chan *smtp.Client + all bool + connectionsPool chan *smtp.Client + expnNotRecognized bool } func (options *Options) GetBaseOptions() *utils.BaseOptions { diff --git a/src/modules/smtp/userEnum.go b/src/modules/smtp/userEnum.go index 015ffc8..07dd9d7 100644 --- a/src/modules/smtp/userEnum.go +++ b/src/modules/smtp/userEnum.go @@ -1,8 +1,6 @@ package smtp import ( - "GoMapEnum/src/utils" - "fmt" "net" "reflect" "strconv" @@ -32,20 +30,10 @@ func PrepareSMTPConnections(optionsInterface *interface{}) { } options.Log.Debug("Preparing a pool of " + strconv.Itoa(nbConnectionsRequired) + " connections") for i := 1; i <= nbConnectionsRequired; i++ { - client, err := smtp.Dial(options.Target + ":25") - if err != nil { - options.Log.Error("Failed to establish a connection " + err.Error()) - continue - } - err = client.Hello(utils.RandomString(6)) - if err != nil { - fmt.Println("hello" + err.Error()) - } - err = client.Mail(utils.RandomString(6) + "@" + options.Domain) - if err != nil { - fmt.Println("mail" + err.Error()) + client := options.createNewConnection() + if client != nil { + options.connectionsPool <- client } - options.connectionsPool <- client } } @@ -53,6 +41,16 @@ func UserEnum(optionsInterface *interface{}, username string) bool { options := (*optionsInterface).(*Options) valid := false smtpConnection := <-options.connectionsPool + smtpConnection.Reset() + err := options.prepareOneConnection(smtpConnection) + if err != nil && strings.Contains(err.Error(), "connection reset by peer") { + options.Log.Debug("Connection reset. Generating new one") + smtpConnection = options.createNewConnection() + err = options.prepareOneConnection(smtpConnection) + } + if err != nil { + options.Log.Fatal("Failed to prepare a connection. " + err.Error()) + } switch strings.ToLower(options.Mode) { case "rcpt": err := smtpConnection.Rcpt(username) @@ -61,6 +59,11 @@ func UserEnum(optionsInterface *interface{}, username string) bool { valid = true } else { options.Log.Debug(username + " => " + err.Error()) + if strings.Contains(err.Error(), "connection reset by peer") { + smtpConnection.Close() + options.createNewConnection() + return UserEnum(optionsInterface, username) + } options.Log.Fail(username) } case "vrfy": @@ -70,6 +73,11 @@ func UserEnum(optionsInterface *interface{}, username string) bool { valid = true } else { options.Log.Debug(username + " => " + err.Error()) + if strings.Contains(err.Error(), "connection reset by peer") { + smtpConnection.Close() + options.createNewConnection() + return UserEnum(optionsInterface, username) + } options.Log.Fail(username) } case "expn": @@ -80,12 +88,20 @@ func UserEnum(optionsInterface *interface{}, username string) bool { } else { code := strings.Split(err.Error(), " ")[0] options.Log.Debug(username + " => " + err.Error()) + if strings.Contains(err.Error(), "connection reset by peer") { + smtpConnection.Close() + options.createNewConnection() + return UserEnum(optionsInterface, username) + } options.Log.Fail(username) // If the command is not implemented no need to pursue if code == "502" && !options.all { CloseSMTPConnections(optionsInterface) options.Log.Fatal("The command EXPN is not implemented. No need to pursue using this method.") } + if code == "502" && options.all { + options.expnNotRecognized = true + } } case "", "all": @@ -111,15 +127,16 @@ func UserEnum(optionsInterface *interface{}, username string) bool { return true } // EXPN - options.Log.Debug("Enumerate with EXPN") - optionsCopy.Mode = "expn" - newOptionsInterface = reflect.ValueOf(&optionsCopy).Interface() - valid = UserEnum(&newOptionsInterface, username) + if !options.expnNotRecognized { + options.Log.Debug("Enumerate with EXPN") + optionsCopy.Mode = "expn" + newOptionsInterface = reflect.ValueOf(&optionsCopy).Interface() + valid = UserEnum(&newOptionsInterface, username) + } return valid default: options.Log.Fatal("Unrecognised mode: " + options.Mode + ". Only RCPT, VRFY and EXPN are supported.") } - options.connectionsPool <- smtpConnection return valid }