Skip to content

Commit

Permalink
doc: add cli guide on validating slowloris (#10)
Browse files Browse the repository at this point in the history
* chore: rename proof to turtle-proof

* doc: guide on using the cli
  • Loading branch information
bcho committed Sep 4, 2023
1 parent 41acc4e commit a51a623
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 6 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ $ turtle -h
$ turtle slowloris -h
```

To learn more, please checkout one of the following guides:

- [Is my server Slowloris-proofed?](/docs/usage/cli-slowloris.md)

### Turtle Golang Library

For the Golang library, documentation can be found on [GoDoc][godoc].
Expand Down
41 changes: 35 additions & 6 deletions cmd/proof/main.go → cmd/turtle-proof/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package main
import (
"context"
"errors"
"fmt"
"io"
"log/slog"
"net"
"net/http"
"os"
Expand All @@ -14,6 +14,8 @@ import (
"github.com/alecthomas/kong"
)

var logger = slog.Default().WithGroup("turtle-proof")

type CLI struct {
ServerAddr string `cmd:"server-addr" help:"the address to listen on" default:"127.0.0.1:8889"`
Scenario string `cmd:"scenario" enum:"none,proof" help:"the scenario to run" default:"none"`
Expand Down Expand Up @@ -58,16 +60,20 @@ func (c *CLI) CreateServer() *http.Server {
WriteTimeout: c.ServerWriteTimeout,

ConnState: func(conn net.Conn, state http.ConnState) {
fmt.Println("ConnState", conn.RemoteAddr(), state)
logger.Info(
"ConnState",
slog.String("remote_addr", conn.RemoteAddr().String()),
slog.String("state", state.String()),
)
},

Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("here")
logger.Info("handling request")

if r.Body != nil {
fmt.Println("read body")
logger.Info("reading body")
if _, err := io.ReadAll(r.Body); err != nil {
fmt.Println("read error", err)
logger.Error("read error", slog.String("error", err.Error()))
w.WriteHeader(http.StatusInternalServerError)
}
}
Expand All @@ -78,9 +84,29 @@ func (c *CLI) CreateServer() *http.Server {
}
}

const description = `
Proof HTTP server for turtle test.
## Start with default settings
turtle-proof
## Start with proofed settings
turtle-proof --scenario proof
## Using custom settings
turtle-proof --server-addr="127.0.0.1:8888" --server-read-header-timeout 3s --server-read-timeout 60s --server-write-timeout 60s
`

func main() {
cli := &CLI{}
cliCtx := kong.Parse(cli)
cliCtx := kong.Parse(
cli,
kong.Name("turtle-proof"),
kong.Description(description),
)

if err := cli.defaults(); err != nil {
cliCtx.FatalIfErrorf(err)
Expand All @@ -97,6 +123,9 @@ func main() {
}
}()

time.Sleep(300 * time.Millisecond) // wait for server start
logger.Info("server started", slog.String("addr", server.Addr))

<-ctx.Done()

shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
Expand Down
12 changes: 12 additions & 0 deletions docs/demo/slowloris-invulnerable.cast
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Set Shell zsh
Set FontSize 11
Escape
Type "[200~turtle slowloris http://localhost:8889 --http-send-gibberish"
Escape
Type "[201~"
Enter
Sleep 10s
Type "q"
Sleep 1s
Ctrl+D
Output slowloris-invulnerable.gif
Binary file added docs/demo/slowloris-invulnerable.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions docs/demo/slowloris-vulnerable.cast
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Set Shell zsh
Set FontSize 11
Escape
Type "[200~turtle slowloris http://localhost:8889 --http-send-gibberish"
Escape
Type "[201~"
Enter
Sleep 10s
Type "q"
Sleep 1s
Ctrl+D
Output slowloris-vulnerable.gif
Binary file added docs/demo/slowloris-vulnerable.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions docs/usage/cli-slowloris.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Is my server Slowloris-proofed?

[Slowloris attack][cf_slowloris] attempts to break an HTTP server by sending partial HTTP request,
which contains never finish HTTP header lines:

```
GET / HTTP 1.1 # this is the only line required to start an HTTP request
HOST example.com
User-Agent my-user-agent
Header-Name Header-Value
# ... keep sending gibberish header name & value lines
```

Since the HTTP request is never ended, vulnerable server keeps the connection open. As a result, server side resources like memory, file descriptor will be consumed.

Invulnerable server should close the connection after a specified time if the request is unable to read completely.

We can use turtle to validate if an HTTP endpoint is Slowloris-proofed:

- if the server is immune to the attack, we should see closed events, and the total number of requests should be more than the test connections;
- if the server is vulnerable to the attack, the connections will be kept opened until test finished.

## Validating via CLI

> **NOTE** We can start a test server with `turtle-proof`. For setup guide, please see [turtle proof server][turtle-proof-server].
1. Start a vulnerable server:

```
$ turtle-proof
2023/09/04 11:33:04 INFO server started turtle-proof.addr=127.0.0.1:8889
```

2. Launch the test with the `slowloris` sub-command:

```
$ turtle slowloris http://127.0.0.1:8889 --http-send-gibberish
```

We should see output similar to below, where the number of connections stays at 100 without closing.

![](/docs/demo/slowloris-vulnerable.gif)

3. Start a invulnerable server:

```
$ turtle-proof --scenario=proof
2023/09/04 11:36:49 INFO server started turtle-proof.addr=127.0.0.1:8889
```

4. Launch the test again

```
$ turtle slowloris http://127.0.0.1:8889 --http-send-gibberish
```

Now, we should see many closing / reopening events like this:

![](/docs/demo/slowloris-invulnerable.gif)

[cf_slowloris]: https://www.cloudflare.com/learning/ddos/ddos-attack-tools/slowloris/
[turtle-proof-server]: ./turtle-proof-server.md

0 comments on commit a51a623

Please sign in to comment.