@@ -4,67 +4,55 @@ import (
44 "crypto/tls"
55 "net"
66 "strings"
7- "sync/atomic"
87 "time"
98
10- "git.mills.io/prologic/smtpd "
9+ "github.com/emersion/go-smtp "
1110 "github.com/projectdiscovery/gologger"
1211 stringsutil "github.com/projectdiscovery/utils/strings"
1312)
1413
1514// SMTPServer is a smtp server instance that listens both
1615// TLS and Non-TLS based servers.
1716type SMTPServer struct {
18- options * Options
19- smtpServer smtpd.Server
20- smtpsServer smtpd.Server
17+ options * Options
18+ backend * interactshBackend
19+ smtpServer * smtp.Server
20+ smtpsServer * smtp.Server
21+ smtpAutoTLSServer * smtp.Server
2122}
2223
2324// NewSMTPServer returns a new TLS & Non-TLS SMTP server.
2425func NewSMTPServer (options * Options ) (* SMTPServer , error ) {
2526 server := & SMTPServer {options : options }
27+ server .backend = & interactshBackend {srv : server }
2628
27- authHandler := func (remoteAddr net.Addr , mechanism string , username []byte , password []byte , shared []byte ) (bool , error ) {
28- return true , nil
29- }
30- rcptHandler := func (remoteAddr net.Addr , from string , to string ) bool {
31- return true
32- }
33- server .smtpServer = smtpd.Server {
34- Addr : formatAddress (options .ListenIP , options .SmtpPort ),
35- AuthHandler : authHandler ,
36- HandlerRcpt : rcptHandler ,
37- Hostname : options .Domains [0 ],
38- Appname : "interactsh" ,
39- Handler : smtpd .Handler (server .defaultHandler ),
40- }
41- server .smtpsServer = smtpd.Server {
42- Addr : formatAddress (options .ListenIP , options .SmtpsPort ),
43- AuthHandler : authHandler ,
44- HandlerRcpt : rcptHandler ,
45- Hostname : options .Domains [0 ],
46- Appname : "interactsh" ,
47- Handler : smtpd .Handler (server .defaultHandler ),
29+ newEmersionServer := func (addr string , tlsConfig * tls.Config ) * smtp.Server {
30+ s := smtp .NewServer (server .backend )
31+ s .Addr = addr
32+ s .Domain = options .Domains [0 ]
33+ s .AllowInsecureAuth = true
34+ s .TLSConfig = tlsConfig
35+ return s
4836 }
37+
38+ server .smtpServer = newEmersionServer (formatAddress (options .ListenIP , options .SmtpPort ), nil )
39+ server .smtpsServer = newEmersionServer (formatAddress (options .ListenIP , options .SmtpsPort ), nil )
40+ server .smtpAutoTLSServer = newEmersionServer (formatAddress (options .ListenIP , options .SmtpAutoTLSPort ), nil )
4941 return server , nil
5042}
5143
5244// ListenAndServe listens on smtp and/or smtps ports for the server.
5345func (h * SMTPServer ) ListenAndServe (tlsConfig * tls.Config , smtpAlive , smtpsAlive chan bool ) {
54- go func () {
55- if tlsConfig == nil {
56- return
57- }
58- srv := & smtpd.Server {Addr : formatAddress (h .options .ListenIP , h .options .SmtpAutoTLSPort ), Handler : h .defaultHandler , Appname : "interactsh" , Hostname : h .options .Domains [0 ]}
59- srv .TLSConfig = tlsConfig
60-
61- smtpsAlive <- true
62- err := srv .ListenAndServe ()
63- if err != nil {
64- gologger .Error ().Msgf ("Could not serve smtp with tls on port %d: %s\n " , h .options .SmtpAutoTLSPort , err )
65- smtpsAlive <- false
66- }
67- }()
46+ if tlsConfig != nil {
47+ h .smtpAutoTLSServer .TLSConfig = tlsConfig
48+ go func () {
49+ smtpsAlive <- true
50+ if err := h .smtpAutoTLSServer .ListenAndServeTLS (); err != nil {
51+ gologger .Error ().Msgf ("Could not serve smtp with tls on port %d: %s\n " , h .options .SmtpAutoTLSPort , err )
52+ smtpsAlive <- false
53+ }
54+ }()
55+ }
6856
6957 smtpAlive <- true
7058 go func () {
@@ -75,21 +63,23 @@ func (h *SMTPServer) ListenAndServe(tlsConfig *tls.Config, smtpAlive, smtpsAlive
7563 }()
7664 if err := h .smtpsServer .ListenAndServe (); err != nil {
7765 gologger .Error ().Msgf ("Could not serve smtp on port %d: %s\n " , h .options .SmtpsPort , err )
78- smtpAlive <- false
66+ smtpsAlive <- false
7967 }
8068}
8169
82- // defaultHandler is a handler for default collaborator requests
70+ // defaultHandler is kept for unit tests that exercise storage without
71+ // standing up a TCP listener.
8372func (h * SMTPServer ) defaultHandler (remoteAddr net.Addr , from string , to []string , data []byte ) error {
84- atomic .AddUint64 (& h .options .Stats .Smtp , 1 )
85-
86- dataString := string (data )
87- gologger .Debug ().Msgf ("New SMTP request: %s %s %s %s\n " , remoteAddr , from , to , dataString )
73+ return h .deliverSMTP (remoteAddr , from , to , data )
74+ }
8875
76+ // storeSMTPRecipients persists SMTP interactions for correlation ids found
77+ // in the recipient addresses.
78+ func (h * SMTPServer ) storeSMTPRecipients (remoteAddr net.Addr , from , rawRequest string , recipients []string ) {
8979 host , _ , _ := net .SplitHostPort (remoteAddr .String ())
9080
9181 if h .options .RootTLD {
92- for _ , addr := range to {
82+ for _ , addr := range recipients {
9383 for _ , domain := range h .options .Domains {
9484 if ! stringsutil .HasSuffixI (addr , domain ) {
9585 continue
@@ -99,7 +89,7 @@ func (h *SMTPServer) defaultHandler(remoteAddr net.Addr, from string, to []strin
9989 Protocol : "smtp" ,
10090 UniqueID : address ,
10191 FullId : address ,
102- RawRequest : dataString ,
92+ RawRequest : rawRequest ,
10393 SMTPFrom : from ,
10494 RemoteAddress : host ,
10595 Timestamp : time .Now (),
@@ -112,7 +102,7 @@ func (h *SMTPServer) defaultHandler(remoteAddr net.Addr, from string, to []strin
112102 // captured a single uniqueID/fullID and stored it once after the loop, so
113103 // later false-positive labels could overwrite the legitimate match and
114104 // the interaction would be persisted under an unregistered id (issue #1362).
115- for _ , addr := range to {
105+ for _ , addr := range recipients {
116106 if len (addr ) <= h .options .GetIdLength () || ! strings .Contains (addr , "@" ) {
117107 continue
118108 }
@@ -130,12 +120,11 @@ func (h *SMTPServer) defaultHandler(remoteAddr net.Addr, from string, to []strin
130120 Protocol : "smtp" ,
131121 UniqueID : normalizedPart ,
132122 FullId : fullID ,
133- RawRequest : dataString ,
123+ RawRequest : rawRequest ,
134124 SMTPFrom : from ,
135125 RemoteAddress : host ,
136126 Timestamp : time .Now (),
137127 }, normalizedPart [:h .options .CorrelationIdLength ])
138128 }
139129 }
140- return nil
141130}
0 commit comments