diff --git a/README.md b/README.md index 6151501f..1c2b252b 100644 --- a/README.md +++ b/README.md @@ -362,6 +362,7 @@ CONFIG: -dr, -dynamic-resp enable setting up arbitrary response data -cr, -custom-records string custom dns records YAML file for DNS server -hi, -http-index string custom index file for http server + -dhr, -default-http-response string file to serve for all http requests (takes priority over other options) -hd, -http-directory string directory with files to serve with http server -ds, -disk disk based storage -dsp, -disk-path string disk storage path diff --git a/cmd/interactsh-server/main.go b/cmd/interactsh-server/main.go index a02e365d..fe0fb166 100644 --- a/cmd/interactsh-server/main.go +++ b/cmd/interactsh-server/main.go @@ -67,6 +67,7 @@ func main() { flagSet.StringVarP(&cliOptions.CustomRecords, "custom-records", "cr", "", "custom dns records YAML file for DNS server"), flagSet.StringVarP(&cliOptions.HTTPIndex, "http-index", "hi", "", "custom index file for http server"), flagSet.StringVarP(&cliOptions.HTTPDirectory, "http-directory", "hd", "", "directory with files to serve with http server"), + flagSet.StringVarP(&cliOptions.DefaultHTTPResponseFile, "default-http-response", "dhr", "", "file to serve for all http requests (takes priority over other options)"), flagSet.BoolVarP(&cliOptions.DiskStorage, "disk", "ds", false, "disk based storage"), flagSet.StringVarP(&cliOptions.DiskStoragePath, "disk-path", "dsp", "", "disk storage path"), flagSet.StringVarP(&cliOptions.HeaderServer, "server-header", "csh", "", "custom value of Server header in response"), diff --git a/pkg/options/server_options.go b/pkg/options/server_options.go index 3001427e..f91c80b6 100644 --- a/pkg/options/server_options.go +++ b/pkg/options/server_options.go @@ -54,6 +54,7 @@ type CLIServerOptions struct { DisableUpdateCheck bool NoVersionHeader bool HeaderServer string + DefaultHTTPResponseFile string } func (cliServerOptions *CLIServerOptions) AsServerOptions() *server.Options { @@ -93,5 +94,6 @@ func (cliServerOptions *CLIServerOptions) AsServerOptions() *server.Options { EnableMetrics: cliServerOptions.EnableMetrics, NoVersionHeader: cliServerOptions.NoVersionHeader, HeaderServer: cliServerOptions.HeaderServer, + DefaultHTTPResponseFile: cliServerOptions.DefaultHTTPResponseFile, } } diff --git a/pkg/server/http_server.go b/pkg/server/http_server.go index 1b6d7a84..6066ebe9 100644 --- a/pkg/server/http_server.go +++ b/pkg/server/http_server.go @@ -25,11 +25,12 @@ import ( // HTTPServer is a http server instance that listens both // TLS and Non-TLS based servers. type HTTPServer struct { - options *Options - tlsserver http.Server - nontlsserver http.Server - customBanner string - staticHandler http.Handler + options *Options + tlsserver http.Server + nontlsserver http.Server + customBanner string + defaultResponse string + staticHandler http.Handler } type noopLogger struct { @@ -63,12 +64,22 @@ func NewHTTPServer(options *Options) (*HTTPServer, error) { // If custom index, read the custom index file and serve it. // Supports {DOMAIN} placeholders. if options.HTTPIndex != "" { - abs, _ := filepath.Abs(options.HTTPDirectory) + abs, _ := filepath.Abs(options.HTTPIndex) gologger.Info().Msgf("Using custom server index: %s", abs) if data, err := os.ReadFile(options.HTTPIndex); err == nil { server.customBanner = string(data) } } + // If default response file is specified, read it and serve for all requests. + // This takes priority over all other response options. + // Supports {DOMAIN} placeholders. + if options.DefaultHTTPResponseFile != "" { + abs, _ := filepath.Abs(options.DefaultHTTPResponseFile) + gologger.Info().Msgf("Using default HTTP response file for all requests: %s", abs) + if data, err := os.ReadFile(options.DefaultHTTPResponseFile); err == nil { + server.defaultResponse = string(data) + } + } router := &http.ServeMux{} router.Handle("/", server.logger(server.corsMiddleware(http.HandlerFunc(server.defaultHandler)))) router.Handle("/register", server.corsMiddleware(server.authMiddleware(http.HandlerFunc(server.registerHandler)))) @@ -255,6 +266,13 @@ func (h *HTTPServer) defaultHandler(w http.ResponseWriter, req *http.Request) { } reflection := h.options.URLReflection(req.Host) + + // If default response is set, serve it for all requests (highest priority) + if h.defaultResponse != "" { + _, _ = fmt.Fprint(w, strings.ReplaceAll(h.defaultResponse, "{DOMAIN}", domain)) + return + } + if stringsutil.HasPrefixI(req.URL.Path, "/s/") && h.staticHandler != nil { if h.options.DynamicResp && len(req.URL.Query()) > 0 { values := req.URL.Query() diff --git a/pkg/server/server.go b/pkg/server/server.go index b067ec26..cb96be74 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -107,6 +107,8 @@ type Options struct { NoVersionHeader bool // HeaderServer use custom string in HTTP response Server header instead of domain HeaderServer string + // DefaultHTTPResponseFile is a file to serve for all HTTP requests (takes priority over other options) + DefaultHTTPResponseFile string ACMEStore *acme.Provider Stats *Metrics