From 174e6b2bbdd299b478ae00875d265c06459c5ad0 Mon Sep 17 00:00:00 2001 From: Marin Ivanov Date: Fri, 26 Apr 2019 10:41:44 +0300 Subject: Add HTTP protocol tarpit --- README.md | 9 +++++---- handle.go | 8 +++++--- http.go | 39 +++++++++++++++++++++++++++++++++++++++ main.go | 14 +++++++++----- 4 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 http.go diff --git a/README.md b/README.md index 4cdc323..41576ed 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ Tarpit command application that may slow down malicious attempts to scan a syste Supported Protocols: - SSH +- HTTP # Building and Running @@ -13,11 +14,11 @@ GOOS=linux GOARCH=amd64 go build -o "build/tarpit-linux-amd64" This command will build the application in `build/tarpit-linux-amd64`. We can then run the tarpit on an unprivileged port (e.g. 2222). -`$ ./build/tarpit-linux-amd64 -p 2222` +`$ ./build/tarpit-linux-amd64 -P ssh -p 2222` Or you can run it on a privileged port with `sudo`. -`$ sudo ./build/tarpit-linux-amd64 -p 22` +`$ sudo ./build/tarpit-linux-amd64 -P ssh -p 22` ## Options @@ -26,7 +27,7 @@ Usage of ./tarpit: -b, --bind-address string address to bind the socket to -d, --delay string delay between the tarpit keep-alive data packets (default "10s") -g, --gid uint16 setgid, after creating a listening socket - -p, --port uint16 TCP port (default 22) + -p, --port uint16 TCP port, leave it 0 for service default -P, --proto string protocol to tarpit (default "ssh") -u, --uid uint16 setuid, after creating a listening socket -v, --version show current version @@ -36,7 +37,7 @@ Usage of ./tarpit: The ports `< 1024` require superuser privileges. The command allows to drop superuser privileges (using setuid/setgid), right after it acquires a listening socket. Thus, allowing to bind to a privileged port and start serving as a regular unprivileged user. This is done by running the command as a superuser (e.g. with `sudo`) and setting the `-u/--uid ` and `-g/--gid ` command line flags. -`$ sudo ./build/tarpit-linux-amd64 -p 22 -u "$(id -u)" -g "$(id -g)"` +`$ sudo ./build/tarpit-linux-amd64 -P ssh -p 22 -u "$(id -u)" -g "$(id -g)"` # Acknowledgements diff --git a/handle.go b/handle.go index 918f3a8..c153b7d 100644 --- a/handle.go +++ b/handle.go @@ -9,12 +9,14 @@ import ( type empty struct{} type protoHandler func(net.Conn, time.Duration) -func protocolHandler(proto string) (protoHandler, error) { +func protocolHandler(proto string) (protoHandler, uint16, error) { switch proto { case "ssh": - return sshHandler, nil + return sshHandler, 22, nil + case "http": + return httpHandler, 80, nil default: - return nil, fmt.Errorf("unknown protocol '%s'", proto) + return nil, 0, fmt.Errorf("unknown protocol '%s'", proto) } } diff --git a/http.go b/http.go new file mode 100644 index 0000000..c8199a3 --- /dev/null +++ b/http.go @@ -0,0 +1,39 @@ +package main + +import ( + "bufio" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net" + "time" +) + +func httpHandler(conn net.Conn, delay time.Duration) { + rd := bufio.NewReader(conn) + rd.ReadLine() + _, err := fmt.Fprintf(conn, "HTTP/1.1 200 OK\r\n") + if err != nil { + return + } + + eof := make(chan empty) + go func() { + io.Copy(ioutil.Discard, conn) + eof <- empty{} + }() + + tick := time.Tick(delay) + for { + select { + case <-eof: + return + case <-tick: + _, err := fmt.Fprintf(conn, "X-%x: %x\r\n", rand.Uint32(), rand.Uint32()) + if err != nil { + return + } + } + } +} diff --git a/main.go b/main.go index d83f018..4033688 100644 --- a/main.go +++ b/main.go @@ -29,7 +29,7 @@ func main() { flag.StringVarP(&protocol, "proto", "P", "ssh", "protocol to tarpit") flag.StringVarP(&delayParam, "delay", "d", "10s", "delay between the tarpit keep-alive data packets") flag.StringVarP(&bindAddr, "bind-address", "b", "", "address to bind the socket to") - flag.Uint16VarP(&port, "port", "p", 22, "TCP port") + flag.Uint16VarP(&port, "port", "p", 0, "TCP port, leave it 0 for service default") flag.Uint16VarP(&uid, "uid", "u", 0, "setuid, after creating a listening socket") flag.Uint16VarP(&gid, "gid", "g", 0, "setgid, after creating a listening socket") flag.BoolVarP(&versionFlag, "version", "v", false, "show current version") @@ -40,8 +40,11 @@ func main() { return } - handler, err := protocolHandler(protocol) + handler, defaultPort, err := protocolHandler(protocol) assert(err, "protocol handler", configErrorCode) + if port == 0 { + port = defaultPort + } delay, err := time.ParseDuration(delayParam) assert(err, "parse delay", configErrorCode) @@ -69,8 +72,9 @@ func main() { } func assert(err error, msg string, code int) { - if err != nil { - fmt.Fprintf(os.Stderr, "ERR: %s; %s \n", msg, err.Error()) - os.Exit(code) + if err == nil { + return } + fmt.Fprintf(os.Stderr, "ERR: %s; %s \n", msg, err.Error()) + os.Exit(code) } -- cgit v1.2.3