Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 28 additions & 30 deletions pkg/server/dns_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,31 @@ func toQType(ttype uint16) (rtype string) {
return
}

func (h *DNSServer) storeInteraction(uniqueID, fullID, qtype, requestMsg, responseMsg, remoteAddr string) {
correlationID := uniqueID[:h.options.CorrelationIdLength]
interaction := &Interaction{
Protocol: "dns",
UniqueID: uniqueID,
FullId: fullID,
QType: qtype,
RawRequest: requestMsg,
RawResponse: responseMsg,
RemoteAddress: remoteAddr,
Timestamp: time.Now(),
}
data, err := jsoniter.Marshal(interaction)
if err != nil {
gologger.Warning().Msgf("Could not encode dns interaction: %s\n", err)
} else {
gologger.Debug().Msgf("DNS Interaction: \n%s\n", string(data))
if err := h.options.Storage.AddInteraction(correlationID, data); err != nil {
gologger.Warning().Msgf("Could not store dns interaction: %s\n", err)
}
}
}

// handleInteraction handles an interaction for the DNS server
func (h *DNSServer) handleInteraction(domain string, w dns.ResponseWriter, r *dns.Msg, m *dns.Msg) {
var uniqueID, fullID string

requestMsg := r.String()
responseMsg := m.String()

Expand Down Expand Up @@ -348,14 +369,15 @@ func (h *DNSServer) handleInteraction(domain string, w dns.ResponseWriter, r *dn
}

if foundDomain != "" {
host, _, _ := net.SplitHostPort(w.RemoteAddr().String())
qtype := toQType(r.Question[0].Qtype)
if h.options.ScanEverywhere {
chunks := stringsutil.SplitAny(requestMsg, ".\n\t\"'")
for _, chunk := range chunks {
for part := range stringsutil.SlideWithLength(chunk, h.options.GetIdLength()) {
normalizedPart := strings.ToLower(part)
if h.options.isCorrelationID(normalizedPart) {
uniqueID = normalizedPart
fullID = part
h.storeInteraction(normalizedPart, part, qtype, requestMsg, responseMsg, host)
}
}
}
Expand All @@ -365,40 +387,16 @@ func (h *DNSServer) handleInteraction(domain string, w dns.ResponseWriter, r *dn
for partChunk := range stringsutil.SlideWithLength(part, h.options.GetIdLength()) {
normalizedPartChunk := strings.ToLower(partChunk)
if h.options.isCorrelationID(normalizedPartChunk) {
fullID = part
fullID := part
if i+1 <= len(parts) {
fullID = strings.Join(parts[:i+1], ".")
}
uniqueID = normalizedPartChunk
h.storeInteraction(normalizedPartChunk, fullID, qtype, requestMsg, responseMsg, host)
}
}
}
}
}

if uniqueID != "" {
correlationID := uniqueID[:h.options.CorrelationIdLength]
host, _, _ := net.SplitHostPort(w.RemoteAddr().String())
interaction := &Interaction{
Protocol: "dns",
UniqueID: uniqueID,
FullId: fullID,
QType: toQType(r.Question[0].Qtype),
RawRequest: requestMsg,
RawResponse: responseMsg,
RemoteAddress: host,
Timestamp: time.Now(),
}
data, err := jsoniter.Marshal(interaction)
if err != nil {
gologger.Warning().Msgf("Could not encode dns interaction: %s\n", err)
} else {
gologger.Debug().Msgf("DNS Interaction: \n%s\n", string(data))
if err := h.options.Storage.AddInteraction(correlationID, data); err != nil {
gologger.Warning().Msgf("Could not store dns interaction: %s\n", err)
}
}
}
}

// CustomRecordConfig represents a custom DNS record configuration
Expand Down
30 changes: 30 additions & 0 deletions pkg/server/server_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package server

import (
"strings"
"testing"

"github.com/projectdiscovery/interactsh/pkg/settings"
stringsutil "github.com/projectdiscovery/utils/strings"
"github.com/rs/xid"
"github.com/stretchr/testify/require"
)

Expand All @@ -12,3 +15,30 @@ func TestGetURLIDComponent(t *testing.T) {
random := options.getURLIDComponent("c6rj61aciaeutn2ae680cg5ugboyyyyyn.interactsh.com")
require.Equal(t, "c6rj61aciaeutn2ae680cg5ugboyyyyyn", random, "could not get correct component")
}

func TestIsCorrelationID(t *testing.T) {
options := Options{CorrelationIdLength: settings.CorrelationIdLengthDefault, CorrelationIdNonceLength: settings.CorrelationIdNonceLengthDefault}

t.Run("exact length match", func(t *testing.T) {
id := strings.Repeat("a", options.CorrelationIdLength) + strings.Repeat("b", options.CorrelationIdNonceLength)
require.True(t, options.isCorrelationID(id))
})

t.Run("shorter than expected", func(t *testing.T) {
require.False(t, options.isCorrelationID("tooshort"))
})

t.Run("sliding window finds embedded ID", func(t *testing.T) {
shortNonce := Options{CorrelationIdLength: settings.CorrelationIdLengthDefault, CorrelationIdNonceLength: 4}
validID := xid.New().String() + "abcd"
longer := ".." + validID + ".." // non-alphanumeric padding prevents spurious matches
found := false
for chunk := range stringsutil.SlideWithLength(longer, shortNonce.GetIdLength()) {
if shortNonce.isCorrelationID(chunk) {
found = true
break
}
}
require.True(t, found, "sliding window should find embedded correlation ID")
})
}
61 changes: 31 additions & 30 deletions pkg/server/smtp_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,32 @@ func (h *SMTPServer) ListenAndServe(tlsConfig *tls.Config, smtpAlive, smtpsAlive
}
}

func (h *SMTPServer) storeInteraction(uniqueID, fullID, dataString, from, remoteAddr string) {
correlationID := uniqueID[:h.options.CorrelationIdLength]
interaction := &Interaction{
Protocol: "smtp",
UniqueID: uniqueID,
FullId: fullID,
RawRequest: dataString,
SMTPFrom: from,
RemoteAddress: remoteAddr,
Timestamp: time.Now(),
}
data, err := jsoniter.Marshal(interaction)
if err != nil {
gologger.Warning().Msgf("Could not encode smtp interaction: %s\n", err)
} else {
gologger.Debug().Msgf("%s\n", string(data))
if err := h.options.Storage.AddInteraction(correlationID, data); err != nil {
gologger.Warning().Msgf("Could not store smtp interaction: %s\n", err)
}
}
}

// defaultHandler is a handler for default collaborator requests
func (h *SMTPServer) defaultHandler(remoteAddr net.Addr, from string, to []string, data []byte) error {
atomic.AddUint64(&h.options.Stats.Smtp, 1)

var uniqueID, fullID string

dataString := string(data)
gologger.Debug().Msgf("New SMTP request: %s %s %s %s\n", remoteAddr, from, to, dataString)

Expand Down Expand Up @@ -122,40 +142,21 @@ func (h *SMTPServer) defaultHandler(remoteAddr net.Addr, from string, to []strin

for _, addr := range to {
if len(addr) > h.options.GetIdLength() && strings.Contains(addr, "@") {
host, _, _ := net.SplitHostPort(remoteAddr.String())
parts := strings.Split(addr[strings.LastIndex(addr, "@")+1:], ".")
for i, part := range parts {
if h.options.isCorrelationID(part) {
uniqueID = part
fullID = part
if i+1 <= len(parts) {
fullID = strings.Join(parts[:i+1], ".")
for partChunk := range stringsutil.SlideWithLength(part, h.options.GetIdLength()) {
normalizedPartChunk := strings.ToLower(partChunk)
if h.options.isCorrelationID(normalizedPartChunk) {
fullID := part
if i+1 <= len(parts) {
fullID = strings.Join(parts[:i+1], ".")
}
h.storeInteraction(normalizedPartChunk, fullID, dataString, from, host)
}
}
}
}
}
if uniqueID != "" {
host, _, _ := net.SplitHostPort(remoteAddr.String())

correlationID := uniqueID[:h.options.CorrelationIdLength]
interaction := &Interaction{
Protocol: "smtp",
UniqueID: uniqueID,
FullId: fullID,
RawRequest: dataString,
SMTPFrom: from,
RemoteAddress: host,
Timestamp: time.Now(),
}
data, err := jsoniter.Marshal(interaction)
if err != nil {
gologger.Warning().Msgf("Could not encode smtp interaction: %s\n", err)
} else {
gologger.Debug().Msgf("%s\n", string(data))
if err := h.options.Storage.AddInteraction(correlationID, data); err != nil {
gologger.Warning().Msgf("Could not store smtp interaction: %s\n", err)
}
}
}
return nil
}