@@ -43,6 +43,8 @@ type Client struct {
4343 matchedTemplates gcache.Cache [string , bool ]
4444 // interactshURLs is a stored cache to track multiple interactsh markers
4545 interactshURLs gcache.Cache [string , string ]
46+ // processedInteractions is a cache for interactions already processed
47+ processedInteractions gcache.Cache [string , bool ]
4648
4749 eviction time.Duration
4850 pollDuration time.Duration
@@ -61,16 +63,18 @@ func New(options *Options) (*Client, error) {
6163 interactionsCache := gcache.New [string , []* server.Interaction ](defaultMaxInteractionsCount ).LRU ().Build ()
6264 matchedTemplateCache := gcache.New [string , bool ](defaultMaxInteractionsCount ).LRU ().Build ()
6365 interactshURLCache := gcache.New [string , string ](defaultMaxInteractionsCount ).LRU ().Build ()
66+ processedInteractionsCache := gcache.New [string , bool ](defaultMaxInteractionsCount ).LRU ().Build ()
6467
6568 interactClient := & Client {
66- eviction : options .Eviction ,
67- interactions : interactionsCache ,
68- matchedTemplates : matchedTemplateCache ,
69- interactshURLs : interactshURLCache ,
70- options : options ,
71- requests : requestsCache ,
72- pollDuration : options .PollDuration ,
73- cooldownDuration : options .CooldownPeriod ,
69+ eviction : options .Eviction ,
70+ interactions : interactionsCache ,
71+ matchedTemplates : matchedTemplateCache ,
72+ interactshURLs : interactshURLCache ,
73+ processedInteractions : processedInteractionsCache ,
74+ options : options ,
75+ requests : requestsCache ,
76+ pollDuration : options .PollDuration ,
77+ cooldownDuration : options .CooldownPeriod ,
7478 }
7579 return interactClient , nil
7680}
@@ -165,6 +169,10 @@ func (c *Client) processInteractionForRequest(interaction *server.Interaction, d
165169 data .Event .InternalEvent ["interactsh_ip" ] = interaction .RemoteAddress
166170 data .Event .Unlock ()
167171
172+ if ! c .shouldProcessInteraction (interaction ) {
173+ return false
174+ }
175+
168176 if data .Operators != nil {
169177 result , matched = data .Operators .Execute (data .Event .InternalEvent , data .MatchFunc , data .ExtractFunc , c .options .Debug || c .options .DebugRequest || c .options .DebugResponse )
170178 } else {
@@ -276,6 +284,7 @@ func (c *Client) Close() bool {
276284 c .interactions .Purge ()
277285 c .matchedTemplates .Purge ()
278286 c .interactshURLs .Purge ()
287+ c .processedInteractions .Purge ()
279288
280289 return c .matched .Load ()
281290}
@@ -468,6 +477,38 @@ func (c *Client) setHostname(hostname string) {
468477 c .hostname = hostname
469478}
470479
480+ func (c * Client ) shouldProcessInteraction (interaction * server.Interaction ) bool {
481+ key := interactionCacheKey (interaction )
482+ if key == "" {
483+ return true
484+ }
485+
486+ c .Lock ()
487+ defer c .Unlock ()
488+
489+ if _ , err := c .processedInteractions .Get (key ); err == nil {
490+ return false
491+ }
492+ _ = c .processedInteractions .SetWithExpire (key , true , defaultInteractionDuration )
493+
494+ return true
495+ }
496+
497+ func interactionCacheKey (interaction * server.Interaction ) string {
498+ if interaction == nil {
499+ return ""
500+ }
501+
502+ uniqueID := strings .ToLower (interaction .UniqueID )
503+ if uniqueID == "" {
504+ return ""
505+ }
506+
507+ protocol := strings .ToLower (interaction .Protocol )
508+
509+ return uniqueID + ":" + protocol
510+ }
511+
471512// GetHostname returns the configured interactsh server hostname.
472513func (c * Client ) GetHostname () string {
473514 return c .getHostname ()
0 commit comments