-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmonkey.go
116 lines (93 loc) · 3.17 KB
/
monkey.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
package main
import (
"fmt"
"math/rand"
"time"
"os"
)
// MaxTimeBetweenAttacks is max time in seconds between two attacks when running in the background.
var MaxTimeBetweenAttacks = 60
// AttacksStrategy is a map of attack names to attacks for use as a strategy pattern.
var AttacksStrategy = map[string](func(endpointConfig EndpointConfig, attackConfig AttackConfig, responseChannel chan Response) error){"HTTP_SPAM": RunHTTPSpam,"CORRUPT_HTTP": RunCorruptHTTP,"URL_QUERY_SPAM": RunURLQuery}
func main() {
config := GetConfigFromCli()
if IsCIMode() {
fmt.Println("🔨 CI Mode detected. Each attack configuration will be ran in sequence for all endpoints.")
PerformSequentialAttack(config)
} else {
wakeTheMonkey(config)
}
}
// PerformSequentialAttack runs through each attack in config and run them in sequence.
func PerformSequentialAttack(config *Config) {
isFailure := false;
for _,endpoint := range config.Endpoints {
for _,attack := range endpoint.Attacks {
response := executeAttackSync(endpoint, attack)
isFailure = isFailure && response.Passed
logResponse(response)
}
}
if isFailure {
os.Exit(1)
}
os.Exit(0)
}
func wakeTheMonkey(config *Config) {
fmt.Println("🐒 Waking the Monkey")
responseChannel := make(chan Response)
SetupTargets(config, responseChannel)
listenForResponses(responseChannel)
}
func listenForResponses(responseChannel chan Response) {
for {
response := <- responseChannel
logResponse(response)
}
}
func logResponse(response Response) {
if response.Passed {
fmt.Printf("✅ Attack %s Passed\n", response.AttackConfig.Type)
} else {
fmt.Printf("❌ Attack %s Failed: %s\n", response.AttackConfig.Type, response.Report)
}
}
// SetupTargets initialises the threads for each of the attacks.
func SetupTargets(config *Config, responseChannel chan Response) {
for _,endpoint := range config.Endpoints {
fmt.Printf("🎯 Setting up %s\n", endpoint.Name)
setupAttackThreads(endpoint, responseChannel)
}
}
func setupAttackThreads(endpoint EndpointConfig, responseChannel chan Response) {
for _,attack := range endpoint.Attacks {
go beginHarassment(endpoint, attack, responseChannel)
}
}
func beginHarassment(endpoint EndpointConfig, attack AttackConfig, responseChannel chan Response) {
for {
executeAttack(endpoint, attack, responseChannel)
pauseForRandomDuration()
}
}
func executeAttack(endpoint EndpointConfig, attack AttackConfig, responseChannel chan Response) {
attackFunc := getAttackFunction(attack)
go attackFunc(endpoint, attack, responseChannel)
}
func executeAttackSync(endpoint EndpointConfig, attack AttackConfig) Response {
attackFunc := getAttackFunction(attack)
responseChannel := make(chan Response)
go attackFunc(endpoint, attack, responseChannel)
response := <- responseChannel
return response
}
func getAttackFunction(attack AttackConfig) (func(endpointConfig EndpointConfig, attackConfig AttackConfig, responseChannel chan Response) error) {
attackFunc, present := AttacksStrategy[attack.Type]
if !present {
panic(fmt.Errorf("Unknown attack type %s", attack.Type))
}
return attackFunc
}
func pauseForRandomDuration() {
time.Sleep(time.Duration(rand.Intn(MaxTimeBetweenAttacks)) * time.Second)
}