From 6b47e447ae5ed88dac0695820b3558ddb84ebd4a Mon Sep 17 00:00:00 2001 From: Orr Kapel Date: Wed, 5 Nov 2025 16:41:28 +0200 Subject: [PATCH 1/8] added eviction strategy --- README.md | 1 + cmd/interactsh-server/main.go | 14 ++++++++++++++ pkg/options/server_options.go | 1 + pkg/storage/option.go | 17 +++++++++++++---- pkg/storage/storagedb.go | 9 ++++++++- 5 files changed, 37 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c3e2c9c5..9b7911ab 100644 --- a/README.md +++ b/README.md @@ -353,6 +353,7 @@ INPUT: -lip, -listen-ip string public ip address to listen on (default "0.0.0.0") -e, -eviction int number of days to persist interaction data in memory (default 30) -ne, -no-eviction disable periodic data eviction from memory + -es, -eviction-strategy string eviction strategy for interactions (sliding, fixed) (default "sliding") -a, -auth enable authentication to server using random generated token -t, -token string enable authentication to server using given token -acao-url string origin url to send in acao header to use web-client) (default "*") diff --git a/cmd/interactsh-server/main.go b/cmd/interactsh-server/main.go index 0426e95d..40481c25 100644 --- a/cmd/interactsh-server/main.go +++ b/cmd/interactsh-server/main.go @@ -48,6 +48,7 @@ func main() { flagSet.StringVarP(&cliOptions.ListenIP, "listen-ip", "lip", "0.0.0.0", "public ip address to listen on"), flagSet.IntVarP(&cliOptions.Eviction, "eviction", "e", 30, "number of days to persist interaction data in memory"), flagSet.BoolVarP(&cliOptions.NoEviction, "no-eviction", "ne", false, "disable periodic data eviction from memory"), + flagSet.StringVarP(&cliOptions.EvictionStrategy, "eviction-strategy", "es", "sliding", "eviction strategy for interactions (sliding, fixed)"), flagSet.BoolVarP(&cliOptions.Auth, "auth", "a", false, "enable authentication to server using random generated token"), flagSet.StringVarP(&cliOptions.Token, "token", "t", "", "enable authentication to server using given token"), flagSet.StringVar(&cliOptions.OriginURL, "acao-url", "*", "origin url to send in acao header to use web-client)"), // cli flag set to deprecate @@ -218,9 +219,22 @@ func main() { if cliOptions.NoEviction { evictionTTL = -1 } + + // Parse eviction strategy + var evictionStrategy storage.EvictionStrategy + switch strings.ToLower(cliOptions.EvictionStrategy) { + case "fixed": + evictionStrategy = storage.EvictionStrategyFixed + case "sliding": + evictionStrategy = storage.EvictionStrategySliding + default: + gologger.Fatal().Msgf("invalid eviction strategy '%s', must be 'sliding' or 'fixed'\n", cliOptions.EvictionStrategy) + } + var store storage.Storage storeOptions := storage.DefaultOptions storeOptions.EvictionTTL = evictionTTL + storeOptions.EvictionStrategy = evictionStrategy if cliOptions.DiskStorage { if cliOptions.DiskStoragePath == "" { gologger.Fatal().Msgf("disk storage path must be specified\n") diff --git a/pkg/options/server_options.go b/pkg/options/server_options.go index 3001427e..6e05b97f 100644 --- a/pkg/options/server_options.go +++ b/pkg/options/server_options.go @@ -20,6 +20,7 @@ type CLIServerOptions struct { LdapWithFullLogger bool Eviction int NoEviction bool + EvictionStrategy string Responder bool Smb bool SmbPort int diff --git a/pkg/storage/option.go b/pkg/storage/option.go index ce827b8b..04bd0f18 100644 --- a/pkg/storage/option.go +++ b/pkg/storage/option.go @@ -2,10 +2,18 @@ package storage import "time" +type EvictionStrategy int + +const ( + EvictionStrategySliding EvictionStrategy = iota // expire-after-access + EvictionStrategyFixed // expire-after-write +) + type Options struct { - DbPath string - EvictionTTL time.Duration - MaxSize int + DbPath string + EvictionTTL time.Duration + MaxSize int + EvictionStrategy EvictionStrategy } func (options *Options) UseDisk() bool { @@ -13,5 +21,6 @@ func (options *Options) UseDisk() bool { } var DefaultOptions = Options{ - MaxSize: 2500000, + MaxSize: 2500000, + EvictionStrategy: EvictionStrategySliding, } diff --git a/pkg/storage/storagedb.go b/pkg/storage/storagedb.go index 55e6df25..50e3c8b4 100644 --- a/pkg/storage/storagedb.go +++ b/pkg/storage/storagedb.go @@ -38,7 +38,14 @@ func New(options *Options) (*StorageDB, error) { cache.WithMaximumSize(options.MaxSize), } if options.EvictionTTL > 0 { - cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL)) + switch options.EvictionStrategy { + case EvictionStrategyFixed: + cacheOptions = append(cacheOptions, cache.WithExpireAfterWrite(options.EvictionTTL)) + case EvictionStrategySliding: + fallthrough + default: + cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL)) + } } if options.UseDisk() { cacheOptions = append(cacheOptions, cache.WithRemovalListener(storageDB.OnCacheRemovalCallback)) From 2f2071bce67911bf7bb2c9560bbad88109521d16 Mon Sep 17 00:00:00 2001 From: Orr Kapel Date: Mon, 10 Nov 2025 15:58:02 +0200 Subject: [PATCH 2/8] added tests for eviction strategy --- pkg/storage/storagedb_test.go | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/pkg/storage/storagedb_test.go b/pkg/storage/storagedb_test.go index 0d91886b..314fc889 100644 --- a/pkg/storage/storagedb_test.go +++ b/pkg/storage/storagedb_test.go @@ -133,3 +133,49 @@ func doStuffWithOtherCache(cache cache.Cache) { _, _ = cache.GetIfPresent(strconv.Itoa(i)) } } + +func TestSlidingEvictionStrategy(t *testing.T) { + testTTL := 100 * time.Millisecond + smallDelay := 10 * time.Millisecond + mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategySliding}) + require.Nil(t, err) + defer mem.Close() + + err = mem.SetID("test-sliding") + require.Nil(t, err) + + // Access after half TTL - should extend expiration + time.Sleep(testTTL / 2) + _, ok := mem.cache.GetIfPresent("test-sliding") + require.True(t, ok) + + // Still present after original TTL due to sliding window + time.Sleep(testTTL / 2 + smallDelay) + _, ok = mem.cache.GetIfPresent("test-sliding") + require.True(t, ok) + + // Should be expired after full TTL despite access + time.Sleep(testTTL + smallDelay) + _, ok = mem.cache.GetIfPresent("test-sliding") + require.False(t, ok) +} + +func TestFixedEvictionStrategy(t *testing.T) { + testTTL := 100 * time.Millisecond + mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategyFixed}) + require.Nil(t, err) + defer mem.Close() + + err = mem.SetID("test-fixed") + require.Nil(t, err) + + // Access after half TTL - should NOT extend expiration + time.Sleep(testTTL / 2) + _, ok := mem.cache.GetIfPresent("test-fixed") + require.True(t, ok) + + // Should be expired after full TTL despite access + time.Sleep(testTTL / 2 + 10 * time.Millisecond) + _, ok = mem.cache.GetIfPresent("test-fixed") + require.False(t, ok) +} From e1332cebf0185917a8570d19cfda5d026eeb44f6 Mon Sep 17 00:00:00 2001 From: Mzack9999 Date: Mon, 24 Nov 2025 15:10:59 +0400 Subject: [PATCH 3/8] Revert "feat(server) added eviction strategy" --- README.md | 1 - cmd/interactsh-server/main.go | 14 ----------- pkg/options/server_options.go | 1 - pkg/storage/option.go | 17 +++---------- pkg/storage/storagedb.go | 9 +------ pkg/storage/storagedb_test.go | 46 ----------------------------------- 6 files changed, 5 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 9b7911ab..c3e2c9c5 100644 --- a/README.md +++ b/README.md @@ -353,7 +353,6 @@ INPUT: -lip, -listen-ip string public ip address to listen on (default "0.0.0.0") -e, -eviction int number of days to persist interaction data in memory (default 30) -ne, -no-eviction disable periodic data eviction from memory - -es, -eviction-strategy string eviction strategy for interactions (sliding, fixed) (default "sliding") -a, -auth enable authentication to server using random generated token -t, -token string enable authentication to server using given token -acao-url string origin url to send in acao header to use web-client) (default "*") diff --git a/cmd/interactsh-server/main.go b/cmd/interactsh-server/main.go index 40481c25..0426e95d 100644 --- a/cmd/interactsh-server/main.go +++ b/cmd/interactsh-server/main.go @@ -48,7 +48,6 @@ func main() { flagSet.StringVarP(&cliOptions.ListenIP, "listen-ip", "lip", "0.0.0.0", "public ip address to listen on"), flagSet.IntVarP(&cliOptions.Eviction, "eviction", "e", 30, "number of days to persist interaction data in memory"), flagSet.BoolVarP(&cliOptions.NoEviction, "no-eviction", "ne", false, "disable periodic data eviction from memory"), - flagSet.StringVarP(&cliOptions.EvictionStrategy, "eviction-strategy", "es", "sliding", "eviction strategy for interactions (sliding, fixed)"), flagSet.BoolVarP(&cliOptions.Auth, "auth", "a", false, "enable authentication to server using random generated token"), flagSet.StringVarP(&cliOptions.Token, "token", "t", "", "enable authentication to server using given token"), flagSet.StringVar(&cliOptions.OriginURL, "acao-url", "*", "origin url to send in acao header to use web-client)"), // cli flag set to deprecate @@ -219,22 +218,9 @@ func main() { if cliOptions.NoEviction { evictionTTL = -1 } - - // Parse eviction strategy - var evictionStrategy storage.EvictionStrategy - switch strings.ToLower(cliOptions.EvictionStrategy) { - case "fixed": - evictionStrategy = storage.EvictionStrategyFixed - case "sliding": - evictionStrategy = storage.EvictionStrategySliding - default: - gologger.Fatal().Msgf("invalid eviction strategy '%s', must be 'sliding' or 'fixed'\n", cliOptions.EvictionStrategy) - } - var store storage.Storage storeOptions := storage.DefaultOptions storeOptions.EvictionTTL = evictionTTL - storeOptions.EvictionStrategy = evictionStrategy if cliOptions.DiskStorage { if cliOptions.DiskStoragePath == "" { gologger.Fatal().Msgf("disk storage path must be specified\n") diff --git a/pkg/options/server_options.go b/pkg/options/server_options.go index 6e05b97f..3001427e 100644 --- a/pkg/options/server_options.go +++ b/pkg/options/server_options.go @@ -20,7 +20,6 @@ type CLIServerOptions struct { LdapWithFullLogger bool Eviction int NoEviction bool - EvictionStrategy string Responder bool Smb bool SmbPort int diff --git a/pkg/storage/option.go b/pkg/storage/option.go index 04bd0f18..ce827b8b 100644 --- a/pkg/storage/option.go +++ b/pkg/storage/option.go @@ -2,18 +2,10 @@ package storage import "time" -type EvictionStrategy int - -const ( - EvictionStrategySliding EvictionStrategy = iota // expire-after-access - EvictionStrategyFixed // expire-after-write -) - type Options struct { - DbPath string - EvictionTTL time.Duration - MaxSize int - EvictionStrategy EvictionStrategy + DbPath string + EvictionTTL time.Duration + MaxSize int } func (options *Options) UseDisk() bool { @@ -21,6 +13,5 @@ func (options *Options) UseDisk() bool { } var DefaultOptions = Options{ - MaxSize: 2500000, - EvictionStrategy: EvictionStrategySliding, + MaxSize: 2500000, } diff --git a/pkg/storage/storagedb.go b/pkg/storage/storagedb.go index 50e3c8b4..55e6df25 100644 --- a/pkg/storage/storagedb.go +++ b/pkg/storage/storagedb.go @@ -38,14 +38,7 @@ func New(options *Options) (*StorageDB, error) { cache.WithMaximumSize(options.MaxSize), } if options.EvictionTTL > 0 { - switch options.EvictionStrategy { - case EvictionStrategyFixed: - cacheOptions = append(cacheOptions, cache.WithExpireAfterWrite(options.EvictionTTL)) - case EvictionStrategySliding: - fallthrough - default: - cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL)) - } + cacheOptions = append(cacheOptions, cache.WithExpireAfterAccess(options.EvictionTTL)) } if options.UseDisk() { cacheOptions = append(cacheOptions, cache.WithRemovalListener(storageDB.OnCacheRemovalCallback)) diff --git a/pkg/storage/storagedb_test.go b/pkg/storage/storagedb_test.go index 314fc889..0d91886b 100644 --- a/pkg/storage/storagedb_test.go +++ b/pkg/storage/storagedb_test.go @@ -133,49 +133,3 @@ func doStuffWithOtherCache(cache cache.Cache) { _, _ = cache.GetIfPresent(strconv.Itoa(i)) } } - -func TestSlidingEvictionStrategy(t *testing.T) { - testTTL := 100 * time.Millisecond - smallDelay := 10 * time.Millisecond - mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategySliding}) - require.Nil(t, err) - defer mem.Close() - - err = mem.SetID("test-sliding") - require.Nil(t, err) - - // Access after half TTL - should extend expiration - time.Sleep(testTTL / 2) - _, ok := mem.cache.GetIfPresent("test-sliding") - require.True(t, ok) - - // Still present after original TTL due to sliding window - time.Sleep(testTTL / 2 + smallDelay) - _, ok = mem.cache.GetIfPresent("test-sliding") - require.True(t, ok) - - // Should be expired after full TTL despite access - time.Sleep(testTTL + smallDelay) - _, ok = mem.cache.GetIfPresent("test-sliding") - require.False(t, ok) -} - -func TestFixedEvictionStrategy(t *testing.T) { - testTTL := 100 * time.Millisecond - mem, err := New(&Options{EvictionTTL: testTTL, EvictionStrategy: EvictionStrategyFixed}) - require.Nil(t, err) - defer mem.Close() - - err = mem.SetID("test-fixed") - require.Nil(t, err) - - // Access after half TTL - should NOT extend expiration - time.Sleep(testTTL / 2) - _, ok := mem.cache.GetIfPresent("test-fixed") - require.True(t, ok) - - // Should be expired after full TTL despite access - time.Sleep(testTTL / 2 + 10 * time.Millisecond) - _, ok = mem.cache.GetIfPresent("test-fixed") - require.False(t, ok) -} From b9eba1d42c2dc82d56342d92777f43655d065430 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 18:22:43 +0000 Subject: [PATCH 4/8] chore(deps): bump github.com/refraction-networking/utls Bumps [github.com/refraction-networking/utls](https://github.com/refraction-networking/utls) from 1.8.0 to 1.8.2. - [Release notes](https://github.com/refraction-networking/utls/releases) - [Commits](https://github.com/refraction-networking/utls/compare/v1.8.0...v1.8.2) --- updated-dependencies: - dependency-name: github.com/refraction-networking/utls dependency-version: 1.8.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 41332ffc..6afa639d 100644 --- a/go.mod +++ b/go.mod @@ -107,7 +107,7 @@ require ( github.com/projectdiscovery/machineid v0.0.0-20250715113114-c77eb3567582 // indirect github.com/projectdiscovery/mapcidr v1.1.97 // indirect github.com/projectdiscovery/networkpolicy v0.1.34 // indirect - github.com/refraction-networking/utls v1.8.0 // indirect + github.com/refraction-networking/utls v1.8.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect github.com/shirou/gopsutil/v3 v3.24.5 // indirect diff --git a/go.sum b/go.sum index c510b2fb..621a2148 100644 --- a/go.sum +++ b/go.sum @@ -311,8 +311,8 @@ github.com/projectdiscovery/retryablehttp-go v1.3.5/go.mod h1:2ma5Itx44tgfZCtHqn github.com/projectdiscovery/utils v0.9.0 h1:eu9vdbP0VYXI9nGSLfnOpUqBeW9/B/iSli7U8gPKZw8= github.com/projectdiscovery/utils v0.9.0/go.mod h1:zcVu1QTlMi5763qCol/L3ROnbd/UPSBP8fI5PmcnF6s= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/refraction-networking/utls v1.8.0 h1:L38krhiTAyj9EeiQQa2sg+hYb4qwLCqdMcpZrRfbONE= -github.com/refraction-networking/utls v1.8.0/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= +github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo= +github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= From f35fd8ac5072b15b53a1695b11bf6321d410e0fe Mon Sep 17 00:00:00 2001 From: XananasX7 Date: Mon, 15 Jun 2026 12:22:34 +0000 Subject: [PATCH 5/8] fix: return 252 for SMTP VRFY instead of 502 (fixes #991) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The smtpd library hard-codes '502 Command not implemented' for VRFY. Per RFC 5321 §3.5.1, a server that cannot verify a mailbox SHOULD return 252 ('Cannot VRFY user, but will accept message and attempt delivery') instead. Returning 502 causes clients such as curl to abort the session before issuing the DATA command, resulting in emails being silently dropped. Fix: point git.mills.io/prologic/smtpd at a patched fork via a go.mod replace directive. The fork is a minimal, single-commit patch on top of the upstream smtpd commit that changes only the VRFY case. --- go.mod | 2 ++ go.sum | 2 ++ 2 files changed, 4 insertions(+) diff --git a/go.mod b/go.mod index 97d5c9ad..257e1198 100644 --- a/go.mod +++ b/go.mod @@ -149,3 +149,5 @@ require ( golang.org/x/text v0.32.0 // indirect golang.org/x/tools v0.39.0 // indirect ) + +replace git.mills.io/prologic/smtpd => github.com/XananasX7/smtpd v0.0.0-20210710122116-vrfy-fix diff --git a/go.sum b/go.sum index 2de73ec2..974c989e 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,8 @@ github.com/STARRY-S/zip v0.2.3 h1:luE4dMvRPDOWQdeDdUxUoZkzUIpTccdKdhHHsQJ1fm4= github.com/STARRY-S/zip v0.2.3/go.mod h1:lqJ9JdeRipyOQJrYSOtpNAiaesFO6zVDsE8GIGFaoSk= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/XananasX7/smtpd v0.0.0-20210710122116-vrfy-fix h1:3mO5SoSlznN8QaEhPs2NiMXHIoFldju26FzknsubIEw= +github.com/XananasX7/smtpd v0.0.0-20210710122116-vrfy-fix/go.mod h1:C7hXLmFmPYPjIDGfQl1clsmQ5TMEQfmzWTrJk475bUs= github.com/akrylysov/pogreb v0.10.2 h1:e6PxmeyEhWyi2AKOBIJzAEi4HkiC+lKyCocRGlnDi78= github.com/akrylysov/pogreb v0.10.2/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= From 2ff5b1bc6d922d0b5ccd5b5c58be5380cb7afae5 Mon Sep 17 00:00:00 2001 From: XananasX7 Date: Mon, 15 Jun 2026 12:27:18 +0000 Subject: [PATCH 6/8] chore: replace direct json-iterator usage with encoding/json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrates all direct uses of github.com/json-iterator/go in non-test and test files to encoding/json, making json-iterator indirect-only (it remains transitively via an upstream dep). This is part of the projectdiscovery/nuclei#7458 dependency-reduction effort: nuclei's PR #7457 already removed json-iterator from nuclei's direct deps, but json-iterator remained a direct dep of interactsh (exposed through pkg/client.Client), which kept it in nuclei's indirect dep tree. Files changed: - cmd/interactsh-client/main.go - pkg/client/client.go (also converts UnmarshalFromString → json.Unmarshal([]byte(...))) - pkg/server/{dns,ftp,http,ldap,responder,smb,smtp}_server.go - pkg/storage/roundtrip_test.go --- cmd/interactsh-client/main.go | 4 ++-- go.mod | 2 +- go.sum | 2 -- pkg/client/client.go | 16 ++++++++-------- pkg/server/dns_server.go | 6 +++--- pkg/server/ftp_server.go | 4 ++-- pkg/server/http_server.go | 16 ++++++++-------- pkg/server/ldap_server.go | 6 +++--- pkg/server/responder_server.go | 4 ++-- pkg/server/smb_server.go | 4 ++-- pkg/server/smtp_server.go | 6 +++--- pkg/storage/roundtrip_test.go | 34 +++++++++++++++++----------------- 12 files changed, 51 insertions(+), 53 deletions(-) diff --git a/cmd/interactsh-client/main.go b/cmd/interactsh-client/main.go index 8537a638..cdda6152 100644 --- a/cmd/interactsh-client/main.go +++ b/cmd/interactsh-client/main.go @@ -10,7 +10,7 @@ import ( "strings" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" asnmap "github.com/projectdiscovery/asnmap/libs" "github.com/projectdiscovery/goflags" "github.com/projectdiscovery/gologger" @@ -265,7 +265,7 @@ func main() { } } } else { - b, err := jsoniter.Marshal(interaction) + b, err := json.Marshal(interaction) if err != nil { gologger.Error().Msgf("Could not marshal json output: %s\n", err) } else { diff --git a/go.mod b/go.mod index 257e1198..3825f804 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/docker/go-units v0.5.0 github.com/goburrow/cache v0.1.4 github.com/google/uuid v1.6.0 - github.com/json-iterator/go v1.1.12 github.com/libdns/libdns v1.1.1 github.com/mackerelio/go-osstat v0.2.6 github.com/miekg/dns v1.1.68 @@ -75,6 +74,7 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect diff --git a/go.sum b/go.sum index 974c989e..f10d04bd 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,6 @@ cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a h1:3i+FJ7IpSZHL+VAjtpQeZCRhrpP0odl5XfoLBY4fxJ8= -git.mills.io/prologic/smtpd v0.0.0-20210710122116-a525b76c287a/go.mod h1:C7hXLmFmPYPjIDGfQl1clsmQ5TMEQfmzWTrJk475bUs= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= diff --git a/pkg/client/client.go b/pkg/client/client.go index a45fd75e..238fe72b 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -25,7 +25,7 @@ import ( "errors" "github.com/google/uuid" - jsoniter "github.com/json-iterator/go" + "encoding/json" asnmap "github.com/projectdiscovery/asnmap/libs" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/interactsh/pkg/options" @@ -261,7 +261,7 @@ func encodeRegistrationRequest(publicKey, secretkey, correlationID string) ([]by CorrelationID: correlationID, } - data, err := jsoniter.Marshal(register) + data, err := json.Marshal(register) if err != nil { return nil, errkit.Wrap(err, "could not marshal register request") } @@ -448,7 +448,7 @@ func (c *Client) getInteractions(callback InteractionCallback) error { return fmt.Errorf("could not poll interactions: %s", string(data)) } response := &server.PollResponse{} - if err := jsoniter.NewDecoder(resp.Body).Decode(response); err != nil { + if err := json.NewDecoder(resp.Body).Decode(response); err != nil { gologger.Error().Msgf("Could not decode interactions: %v\n", err) return err } @@ -461,7 +461,7 @@ func (c *Client) getInteractions(callback InteractionCallback) error { } plaintext = bytes.TrimRight(plaintext, " \t\r\n") interaction := &server.Interaction{} - if err := jsoniter.Unmarshal(plaintext, interaction); err != nil { + if err := json.Unmarshal(plaintext, interaction); err != nil { gologger.Error().Msgf("Could not unmarshal interaction data interaction: %v\n", err) continue } @@ -470,7 +470,7 @@ func (c *Client) getInteractions(callback InteractionCallback) error { for _, plaintext := range response.Extra { interaction := &server.Interaction{} - if err := jsoniter.UnmarshalFromString(plaintext, interaction); err != nil { + if err := json.Unmarshal([]byte(plaintext), interaction); err != nil { gologger.Error().Msgf("Could not unmarshal interaction data interaction: %v\n", err) continue } @@ -483,7 +483,7 @@ func (c *Client) getInteractions(callback InteractionCallback) error { continue } interaction := &server.Interaction{} - if err := jsoniter.UnmarshalFromString(data, interaction); err != nil { + if err := json.Unmarshal([]byte(data), interaction); err != nil { gologger.Error().Msgf("Could not unmarshal interaction data interaction: %v\n", err) continue } @@ -555,7 +555,7 @@ func (c *Client) Close() error { CorrelationID: c.correlationID, SecretKey: c.secretKey, } - data, err := jsoniter.Marshal(register) + data, err := json.Marshal(register) if err != nil { return errkit.Wrap(err, "could not marshal deregister request") } @@ -625,7 +625,7 @@ func (c *Client) performRegistration(serverURL string, payload []byte) error { return fmt.Errorf("could not register to server: %s", string(data)) } response := make(map[string]interface{}) - if err := jsoniter.NewDecoder(resp.Body).Decode(&response); err != nil { + if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return errkit.Wrap(err, "could not register to server") } message, ok := response["message"] diff --git a/pkg/server/dns_server.go b/pkg/server/dns_server.go index c724795c..608fd9c7 100644 --- a/pkg/server/dns_server.go +++ b/pkg/server/dns_server.go @@ -9,7 +9,7 @@ import ( "sync/atomic" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/miekg/dns" "github.com/pkg/errors" "github.com/projectdiscovery/gologger" @@ -336,7 +336,7 @@ func (h *DNSServer) handleInteraction(domain string, w dns.ResponseWriter, r *dn h.options.OnResult(interaction) } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode root tld dns interaction: %s\n", err) } else { @@ -389,7 +389,7 @@ func (h *DNSServer) handleInteraction(domain string, w dns.ResponseWriter, r *dn RemoteAddress: host, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode dns interaction: %s\n", err) } else { diff --git a/pkg/server/ftp_server.go b/pkg/server/ftp_server.go index e43f466f..79a68f59 100644 --- a/pkg/server/ftp_server.go +++ b/pkg/server/ftp_server.go @@ -9,7 +9,7 @@ import ( "sync/atomic" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/projectdiscovery/gologger" ftpserver "goftp.io/server/v2" "goftp.io/server/v2/driver/file" @@ -130,7 +130,7 @@ func (h *FTPServer) recordInteraction(remoteAddress, data string) { RawRequest: data, Timestamp: time.Now(), } - dataBytes, err := jsoniter.Marshal(interaction) + dataBytes, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode ftp interaction: %s\n", err) } else { diff --git a/pkg/server/http_server.go b/pkg/server/http_server.go index 28757b62..ba627967 100644 --- a/pkg/server/http_server.go +++ b/pkg/server/http_server.go @@ -16,7 +16,7 @@ import ( "sync/atomic" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/projectdiscovery/gologger" stringsutil "github.com/projectdiscovery/utils/strings" ) @@ -157,7 +157,7 @@ func (h *HTTPServer) logger(handler http.Handler) http.HandlerFunc { RemoteAddress: host, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode root tld http interaction: %s\n", err) } else { @@ -217,7 +217,7 @@ func (h *HTTPServer) handleInteraction(r *http.Request, uniqueID, fullID, reqStr RemoteAddress: hostPort, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode http interaction: %s\n", err) } else { @@ -382,7 +382,7 @@ type RegisterRequest struct { // registerHandler is a handler for client register requests func (h *HTTPServer) registerHandler(w http.ResponseWriter, req *http.Request) { r := &RegisterRequest{} - if err := jsoniter.NewDecoder(req.Body).Decode(r); err != nil { + if err := json.NewDecoder(req.Body).Decode(r); err != nil { gologger.Warning().Msgf("Could not decode json body: %s\n", err) jsonError(w, fmt.Sprintf("could not decode json body: %s", err), http.StatusBadRequest) return @@ -412,7 +412,7 @@ func (h *HTTPServer) deregisterHandler(w http.ResponseWriter, req *http.Request) atomic.AddInt64(&h.options.Stats.Sessions, -1) r := &DeregisterRequest{} - if err := jsoniter.NewDecoder(req.Body).Decode(r); err != nil { + if err := json.NewDecoder(req.Body).Decode(r); err != nil { gologger.Warning().Msgf("Could not decode json body: %s\n", err) jsonError(w, fmt.Sprintf("could not decode json body: %s", err), http.StatusBadRequest) return @@ -478,7 +478,7 @@ func (h *HTTPServer) pollHandler(w http.ResponseWriter, req *http.Request) { } response := &PollResponse{Data: data, AESKey: aesKey, TLDData: tlddata, Extra: extradata} - if err := jsoniter.NewEncoder(w).Encode(response); err != nil { + if err := json.NewEncoder(w).Encode(response); err != nil { gologger.Warning().Msgf("Could not encode interactions for %s: %s\n", ID, err) jsonError(w, fmt.Sprintf("could not encode interactions: %s", err), http.StatusBadRequest) return @@ -507,7 +507,7 @@ func jsonBody(w http.ResponseWriter, key, value string, code int) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(code) - _ = jsoniter.NewEncoder(w).Encode(map[string]interface{}{key: value}) + _ = json.NewEncoder(w).Encode(map[string]interface{}{key: value}) } func jsonError(w http.ResponseWriter, err string, code int) { @@ -542,5 +542,5 @@ func (h *HTTPServer) metricsHandler(w http.ResponseWriter, req *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("X-Content-Type-Options", "nosniff") - _ = jsoniter.NewEncoder(w).Encode(interactMetrics) + _ = json.NewEncoder(w).Encode(interactMetrics) } diff --git a/pkg/server/ldap_server.go b/pkg/server/ldap_server.go index 35d430b5..0dd18440 100644 --- a/pkg/server/ldap_server.go +++ b/pkg/server/ldap_server.go @@ -7,7 +7,7 @@ import ( "sync/atomic" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/projectdiscovery/gologger" ldap "github.com/projectdiscovery/ldapserver" stringsutil "github.com/projectdiscovery/utils/strings" @@ -144,7 +144,7 @@ func (ldapServer *LDAPServer) handleInteraction(uniqueID, fullID, reqString, hos RemoteAddress: host, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode ldap interaction: %s\n", err) } else { @@ -410,7 +410,7 @@ func (ldapServer *LDAPServer) logInteraction(interaction Interaction) { // Correlation id doesn't apply here, we skip encryption interaction.Protocol = "ldap" interaction.Timestamp = time.Now() - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode ldap interaction: %s\n", err) } else { diff --git a/pkg/server/responder_server.go b/pkg/server/responder_server.go index 20ff92c4..36328dce 100644 --- a/pkg/server/responder_server.go +++ b/pkg/server/responder_server.go @@ -7,7 +7,7 @@ import ( "strings" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/interactsh/pkg/filewatcher" fileutil "github.com/projectdiscovery/utils/file" @@ -88,7 +88,7 @@ func (h *ResponderServer) ListenAndServe(responderAlive chan bool) error { RawRequest: responderData, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode responder interaction: %s\n", err) } else { diff --git a/pkg/server/smb_server.go b/pkg/server/smb_server.go index ac445352..eeff970f 100644 --- a/pkg/server/smb_server.go +++ b/pkg/server/smb_server.go @@ -8,7 +8,7 @@ import ( "sync/atomic" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/interactsh/pkg/filewatcher" fileutil "github.com/projectdiscovery/utils/file" @@ -100,7 +100,7 @@ func (h *SMBServer) ListenAndServe(smbAlive chan bool) error { RawRequest: smbData, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode smb interaction: %s\n", err) } else { diff --git a/pkg/server/smtp_server.go b/pkg/server/smtp_server.go index 6c88ca06..594a0501 100644 --- a/pkg/server/smtp_server.go +++ b/pkg/server/smtp_server.go @@ -8,7 +8,7 @@ import ( "time" "git.mills.io/prologic/smtpd" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/projectdiscovery/gologger" stringsutil "github.com/projectdiscovery/utils/strings" ) @@ -106,7 +106,7 @@ func (h *SMTPServer) defaultHandler(remoteAddr net.Addr, from string, to []strin RemoteAddress: host, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode root tld SMTP interaction: %s\n", err) } else { @@ -147,7 +147,7 @@ func (h *SMTPServer) defaultHandler(remoteAddr net.Addr, from string, to []strin RemoteAddress: host, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode smtp interaction: %s\n", err) } else { diff --git a/pkg/storage/roundtrip_test.go b/pkg/storage/roundtrip_test.go index 557a155b..b95c9e3b 100644 --- a/pkg/storage/roundtrip_test.go +++ b/pkg/storage/roundtrip_test.go @@ -14,7 +14,7 @@ import ( "testing" "time" - jsoniter "github.com/json-iterator/go" + "encoding/json" "github.com/google/uuid" "github.com/rs/xid" "github.com/stretchr/testify/require" @@ -116,7 +116,7 @@ func TestFullRoundTripInMemory(t *testing.T) { RemoteAddress: "10.0.0.1", Timestamp: time.Now(), } - data, err := jsoniter.Marshal(inter) + data, err := json.Marshal(inter) require.NoError(t, err, "encode interaction %d", i) err = mem.AddInteraction(correlationID, data) @@ -132,7 +132,7 @@ func TestFullRoundTripInMemory(t *testing.T) { for i, d := range data { plaintext := clientDecrypt(t, priv, aesKey, d) result := &interaction{} - err = jsoniter.Unmarshal(plaintext, result) + err = json.Unmarshal(plaintext, result) require.NoError(t, err, "unmarshal interaction %d: plaintext=%q", i, string(plaintext[:min(len(plaintext), 100)])) require.Equal(t, "dns", result.Protocol) require.Equal(t, "abc123def456ghi", result.UniqueID) @@ -169,7 +169,7 @@ func TestFullRoundTripDisk(t *testing.T) { RemoteAddress: "10.0.0.1", Timestamp: time.Now(), } - data, err := jsoniter.Marshal(inter) + data, err := json.Marshal(inter) require.NoError(t, err, "encode interaction %d", i) err = db.AddInteraction(correlationID, data) @@ -185,7 +185,7 @@ func TestFullRoundTripDisk(t *testing.T) { for i, d := range data { plaintext := clientDecrypt(t, priv, aesKey, d) result := &interaction{} - err = jsoniter.Unmarshal(plaintext, result) + err = json.Unmarshal(plaintext, result) require.NoError(t, err, "unmarshal interaction %d: plaintext=%q", i, string(plaintext[:min(len(plaintext), 100)])) require.Equal(t, "dns", result.Protocol) require.Equal(t, "abc123def456ghi", result.UniqueID) @@ -225,7 +225,7 @@ func TestPollResponseRoundTrip(t *testing.T) { RemoteAddress: "10.0.0.1", Timestamp: time.Now(), } - interData, err := jsoniter.Marshal(inter) + interData, err := json.Marshal(inter) require.NoError(t, err) err = mem.AddInteraction(correlationID, interData) require.NoError(t, err) @@ -237,12 +237,12 @@ func TestPollResponseRoundTrip(t *testing.T) { // Simulate PollResponse JSON encoding/decoding (server→client HTTP) response := &PollResponse{Data: data, AESKey: aesKey} var responseBuf bytes.Buffer - err = jsoniter.NewEncoder(&responseBuf).Encode(response) + err = json.NewEncoder(&responseBuf).Encode(response) require.NoError(t, err) // Decode on client side receivedResponse := &PollResponse{} - err = jsoniter.NewDecoder(&responseBuf).Decode(receivedResponse) + err = json.NewDecoder(&responseBuf).Decode(receivedResponse) require.NoError(t, err) require.Len(t, receivedResponse.Data, 1) @@ -250,7 +250,7 @@ func TestPollResponseRoundTrip(t *testing.T) { // Decrypt and unmarshal plaintext := clientDecrypt(t, priv, receivedResponse.AESKey, receivedResponse.Data[0]) result := &interaction{} - err = jsoniter.Unmarshal(plaintext, result) + err = json.Unmarshal(plaintext, result) require.NoError(t, err, "unmarshal failed: plaintext[:100]=%q", string(plaintext[:min(len(plaintext), 100)])) require.Equal(t, "dns", result.Protocol) } @@ -265,7 +265,7 @@ func TestTrailingNewlineHandling(t *testing.T) { Timestamp: time.Now(), } buffer := &bytes.Buffer{} - err := jsoniter.NewEncoder(buffer).Encode(inter) + err := json.NewEncoder(buffer).Encode(inter) require.NoError(t, err) encoded := buffer.Bytes() @@ -277,7 +277,7 @@ func TestTrailingNewlineHandling(t *testing.T) { // Verify jsoniter.Unmarshal handles trailing newline result := &interaction{} - err = jsoniter.Unmarshal(encoded, result) + err = json.Unmarshal(encoded, result) require.NoError(t, err, "Unmarshal should handle trailing newline") require.Equal(t, "dns", result.Protocol) } @@ -294,7 +294,7 @@ func TestJsoniterControlCharacterEscaping(t *testing.T) { Timestamp: time.Now(), } buffer := &bytes.Buffer{} - err := jsoniter.NewEncoder(buffer).Encode(inter) + err := json.NewEncoder(buffer).Encode(inter) require.NoError(t, err) encoded := buffer.Bytes() @@ -308,7 +308,7 @@ func TestJsoniterControlCharacterEscaping(t *testing.T) { // Verify round-trip result := &interaction{} - err = jsoniter.Unmarshal(encoded, result) + err = json.Unmarshal(encoded, result) require.NoError(t, err) require.Equal(t, "line1\nline2\ttab\rcarriage", result.RawRequest) } @@ -342,7 +342,7 @@ func TestStaleDataCleanupOnReRegistration(t *testing.T) { RemoteAddress: "1.2.3.4", Timestamp: time.Now(), } - data1, err := jsoniter.Marshal(inter) + data1, err := json.Marshal(inter) require.NoError(t, err) err = db.AddInteraction(correlationID, data1) require.NoError(t, err) @@ -368,7 +368,7 @@ func TestStaleDataCleanupOnReRegistration(t *testing.T) { RemoteAddress: "5.6.7.8", Timestamp: time.Now(), } - data2, err := jsoniter.Marshal(inter2) + data2, err := json.Marshal(inter2) require.NoError(t, err) err = db.AddInteraction(correlationID, data2) require.NoError(t, err) @@ -383,7 +383,7 @@ func TestStaleDataCleanupOnReRegistration(t *testing.T) { // Decrypt and verify it's the second interaction plaintext := clientDecrypt(t, priv2, aesKey, interactions[0]) result := &interaction{} - err = jsoniter.Unmarshal(plaintext, result) + err = json.Unmarshal(plaintext, result) require.NoError(t, err, "should unmarshal successfully with new key") require.Equal(t, "second-registration", result.UniqueID) @@ -417,7 +417,7 @@ func TestCacheEvictionCleansLevelDB(t *testing.T) { RemoteAddress: "1.2.3.4", Timestamp: time.Now(), } - data, err := jsoniter.Marshal(inter) + data, err := json.Marshal(inter) require.NoError(t, err) err = db.AddInteraction(correlationID, data) require.NoError(t, err) From 556df69b9434f42606fa578780237611156716f6 Mon Sep 17 00:00:00 2001 From: Mzack9999 Date: Wed, 17 Jun 2026 09:02:54 +0200 Subject: [PATCH 7/8] merge dev --- cmd/interactsh-client/main.go | 2 +- go.mod | 2 +- pkg/client/client.go | 5 ++--- pkg/server/http_server.go | 2 +- pkg/server/http_server_test.go | 6 +++--- pkg/server/ntlm_capture.go | 4 ++-- pkg/server/util.go | 6 +++--- pkg/storage/roundtrip_test.go | 6 +++--- 8 files changed, 16 insertions(+), 17 deletions(-) diff --git a/cmd/interactsh-client/main.go b/cmd/interactsh-client/main.go index 3aeed2fe..e25843af 100644 --- a/cmd/interactsh-client/main.go +++ b/cmd/interactsh-client/main.go @@ -2,6 +2,7 @@ package main import ( "bytes" + "encoding/json" "fmt" "os" "os/signal" @@ -10,7 +11,6 @@ import ( "strings" "time" - "encoding/json" asnmap "github.com/projectdiscovery/asnmap/libs" "github.com/projectdiscovery/goflags" "github.com/projectdiscovery/gologger" diff --git a/go.mod b/go.mod index 02122c1e..f6ab0419 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,6 @@ require ( github.com/docker/go-units v0.5.0 github.com/goburrow/cache v0.1.4 github.com/google/uuid v1.6.0 - github.com/json-iterator/go v1.1.12 github.com/libdns/libdns v1.1.1 github.com/mackerelio/go-osstat v0.2.6 github.com/miekg/dns v1.1.68 @@ -87,6 +86,7 @@ require ( github.com/jcmturner/goidentity/v6 v6.0.1 // indirect github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect diff --git a/pkg/client/client.go b/pkg/client/client.go index 353027d3..bea9caa5 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -10,7 +10,9 @@ import ( "crypto/sha256" "crypto/x509" "encoding/base64" + "encoding/json" "encoding/pem" + "errors" "fmt" "io" "net" @@ -22,10 +24,7 @@ import ( "sync/atomic" "time" - "errors" - "github.com/google/uuid" - "encoding/json" asnmap "github.com/projectdiscovery/asnmap/libs" "github.com/projectdiscovery/gologger" "github.com/projectdiscovery/interactsh/pkg/options" diff --git a/pkg/server/http_server.go b/pkg/server/http_server.go index 0f4a39bd..d51b71a8 100644 --- a/pkg/server/http_server.go +++ b/pkg/server/http_server.go @@ -3,6 +3,7 @@ package server import ( "crypto/tls" "encoding/base64" + "encoding/json" "fmt" "log" "net" @@ -16,7 +17,6 @@ import ( "sync/atomic" "time" - "encoding/json" "github.com/projectdiscovery/gologger" stringsutil "github.com/projectdiscovery/utils/strings" ) diff --git a/pkg/server/http_server_test.go b/pkg/server/http_server_test.go index 5a21e61b..a93f3e96 100644 --- a/pkg/server/http_server_test.go +++ b/pkg/server/http_server_test.go @@ -7,6 +7,7 @@ import ( "crypto/tls" "crypto/x509" "encoding/base64" + "encoding/json" "encoding/pem" "io" "net/http" @@ -17,7 +18,6 @@ import ( "time" "github.com/google/uuid" - jsoniter "github.com/json-iterator/go" "github.com/projectdiscovery/interactsh/pkg/storage" "github.com/rs/xid" "github.com/stretchr/testify/require" @@ -117,7 +117,7 @@ func TestSessionTotalMetric(t *testing.T) { secretKey := uuid.New().String() // --- Register --- - regBody, err := jsoniter.Marshal(&RegisterRequest{ + regBody, err := json.Marshal(&RegisterRequest{ PublicKey: pubB64, SecretKey: secretKey, CorrelationID: correlationID, @@ -132,7 +132,7 @@ func TestSessionTotalMetric(t *testing.T) { require.Equal(t, int64(1), atomic.LoadInt64(&stats.SessionsTotal), "sessions_total should be 1 after register") // --- Deregister --- - deregBody, err := jsoniter.Marshal(&DeregisterRequest{ + deregBody, err := json.Marshal(&DeregisterRequest{ SecretKey: secretKey, CorrelationID: correlationID, }) diff --git a/pkg/server/ntlm_capture.go b/pkg/server/ntlm_capture.go index 0b675cda..f1f199bc 100644 --- a/pkg/server/ntlm_capture.go +++ b/pkg/server/ntlm_capture.go @@ -4,6 +4,7 @@ import ( "context" "encoding/binary" "encoding/hex" + "encoding/json" "errors" "fmt" "sync/atomic" @@ -12,7 +13,6 @@ import ( "github.com/Mzack9999/goimpacket/pkg/ntlm" "github.com/Mzack9999/goimpacket/pkg/relay" "github.com/Mzack9999/goimpacket/pkg/utf16le" - jsoniter "github.com/json-iterator/go" "github.com/projectdiscovery/gologger" ) @@ -80,7 +80,7 @@ func runNTLMCapture(ctx context.Context, srv relay.ProtocolServer, protocolName RemoteAddress: auth.SourceAddr, Timestamp: time.Now(), } - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode %s interaction: %s\n", protocolName, err) } else { diff --git a/pkg/server/util.go b/pkg/server/util.go index c91259c6..f7313bb3 100644 --- a/pkg/server/util.go +++ b/pkg/server/util.go @@ -1,11 +1,11 @@ package server import ( + "encoding/json" "net" "strconv" "strings" - jsoniter "github.com/json-iterator/go" "github.com/projectdiscovery/gologger" ) @@ -61,7 +61,7 @@ func formatAddress(host string, port int) string { // Each protocol handler builds its own protocol-specific Interaction and delegates the marshal/log/store // step here so every match is stored independently (see issue #1362). func (options *Options) storeInteraction(interaction *Interaction, correlationID string) { - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode %s interaction: %s\n", interaction.Protocol, err) return @@ -75,7 +75,7 @@ func (options *Options) storeInteraction(interaction *Interaction, correlationID // storeRootTLDInteraction marshals interaction and persists it under id via Storage.AddInteractionWithId. // Used when RootTLD is enabled and the request targets a configured parent domain directly. func (options *Options) storeRootTLDInteraction(interaction *Interaction, id string) { - data, err := jsoniter.Marshal(interaction) + data, err := json.Marshal(interaction) if err != nil { gologger.Warning().Msgf("Could not encode root tld %s interaction: %s\n", interaction.Protocol, err) return diff --git a/pkg/storage/roundtrip_test.go b/pkg/storage/roundtrip_test.go index 7311be3a..e3d23b33 100644 --- a/pkg/storage/roundtrip_test.go +++ b/pkg/storage/roundtrip_test.go @@ -283,15 +283,15 @@ func TestTrailingNewlineHandling(t *testing.T) { // Verify trailing newline is present require.Equal(t, byte('\n'), encoded[len(encoded)-1], "Encode() should append trailing newline") - // Verify jsoniter.Unmarshal handles trailing newline + // Verify json.Unmarshal handles trailing newline result := &interaction{} err = json.Unmarshal(encoded, result) require.NoError(t, err, "Unmarshal should handle trailing newline") require.Equal(t, "dns", result.Protocol) } -// TestJsoniterControlCharacterEscaping verifies jsoniter properly escapes control characters -func TestJsoniterControlCharacterEscaping(t *testing.T) { +// TestControlCharacterEscaping verifies json properly escapes control characters +func TestControlCharacterEscaping(t *testing.T) { // DNS message String() output contains tabs and newlines inter := &interaction{ Protocol: "dns", From bed69bbb9361dd70e23fbdff5d156caa8e101db7 Mon Sep 17 00:00:00 2001 From: Mzack9999 Date: Wed, 17 Jun 2026 09:29:20 +0200 Subject: [PATCH 8/8] guard overflow --- pkg/storage/util.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/storage/util.go b/pkg/storage/util.go index 8df6f62e..9dcc81c8 100644 --- a/pkg/storage/util.go +++ b/pkg/storage/util.go @@ -39,12 +39,20 @@ func ParseB64RSAPublicKeyFromPEM(pubPEM string) (*rsa.PublicKey, error) { return nil, errors.New("key type is not RSA") } +// maxEncryptMessageSize bounds the plaintext accepted by AESEncrypt. It guards +// the size computations below against integer overflow; interaction payloads are +// orders of magnitude smaller than this in practice. +const maxEncryptMessageSize = 256 << 20 // 256 MiB + // AESEncrypt encrypts a message using AES and puts IV at the beginning of ciphertext. func AESEncrypt(key []byte, message []byte) (string, error) { block, err := aes.NewCipher(key) if err != nil { return "", err } + if len(message) > maxEncryptMessageSize { + return "", errors.New("message too large to encrypt") + } // It's common to put IV at the beginning of the ciphertext. cipherText := make([]byte, aes.BlockSize+len(message)) iv := cipherText[:aes.BlockSize]