forked from tsenart/vegeta
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enables automated fuzzing on continuous fuzzing platform Fuzzit. Fuzz regression tests run every build and PR. Full length fuzzing runs every push to master. Targets everything that does some parsing. Defined fuzzing targets are: * AttackerHTTP - Delivers fuzz as an HTTP response. Uses socket file. * AttackerTCP - Delivers fuzz as a TCP byte stream. Uses socket file. * HTTPTargeter - Fuzz decoding of a target list in HTTP format. * JSONTargeter - Fuzz decoding of a target list in JSON format. * ResultsFormatDetection - Fuzz result list format detection. * GobDecoder - Fuzz decoder of a result list in gob format. * CSVDecoder - Fuzz decoding of a result list in CSV format. * JSONDecoder - Fuzz decoding a result list in JSON format.
- Loading branch information
Showing
7 changed files
with
464 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,26 @@ | ||
language: go | ||
services: | ||
- docker | ||
sudo: false | ||
go: | ||
- tip | ||
install: | ||
- go get -v golang.org/x/lint/golint | ||
- go get -d -t -v ./... | ||
- go build -v ./... | ||
script: | ||
- go vet ./... | ||
- $HOME/gopath/bin/golint -set_exit_status $(go list ./... | grep -v /vendor/) | ||
- go test -v ./... | ||
jobs: | ||
include: | ||
- stage: Test | ||
script: | ||
- go vet ./... | ||
- $HOME/gopath/bin/golint -set_exit_status $(go list ./... | grep -v /vendor/) | ||
- go test -v ./... | ||
- stage: Fuzz regression | ||
go: 1.12.x | ||
dist: bionic | ||
script: ./fuzzit.sh local-regression | ||
- stage: Fuzz | ||
if: branch = master AND type IN (push) | ||
go: 1.12.x | ||
dist: bionic | ||
script: ./fuzzit.sh fuzzing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#!/bin/bash | ||
set -xe | ||
|
||
# Validate arguments | ||
if [ "$#" -ne 1 ]; then | ||
echo "Usage: $0 <fuzz-type>" | ||
exit 1 | ||
fi | ||
|
||
# Configure | ||
NAME=vegeta | ||
ROOT=./lib | ||
TYPE=$1 | ||
|
||
# Setup | ||
export GO111MODULE="off" | ||
go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build | ||
go get -d -v -u ./... | ||
if [ ! -f fuzzit ]; then | ||
wget -q -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v2.4.29/fuzzit_Linux_x86_64 | ||
chmod a+x fuzzit | ||
fi | ||
|
||
# Fuzz | ||
function fuzz { | ||
FUNC=Fuzz$1 | ||
TARGET=$2 | ||
DIR=${3:-$ROOT} | ||
go-fuzz-build -libfuzzer -func $FUNC -o fuzzer.a $DIR | ||
clang -fsanitize=fuzzer fuzzer.a -o fuzzer | ||
./fuzzit create job --type $TYPE $NAME/$TARGET fuzzer | ||
} | ||
fuzz HTTPTargeter http-targeter | ||
fuzz JSONTargeter json-targeter | ||
fuzz ResultsFormatDetection results-format-detection | ||
fuzz GobDecoder gob-decoder | ||
fuzz CSVDecoder csv-decoder | ||
fuzz JSONDecoder json-decoder | ||
fuzz AttackerTCP attacker-tcp | ||
fuzz AttackerHTTP attacker-http |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// +build gofuzz | ||
|
||
package vegeta | ||
|
||
import ( | ||
"encoding/binary" | ||
"fmt" | ||
"io/ioutil" | ||
"net" | ||
"net/http" | ||
"os" | ||
"time" | ||
) | ||
|
||
// FuzzAttackerTCP fuzzes binary responses to attacker. | ||
func FuzzAttackerTCP(fuzz []byte) int { | ||
// Ignore empty fuzz | ||
if len(fuzz) == 0 { | ||
return -1 | ||
} | ||
|
||
// Start server | ||
directory, err := ioutil.TempDir("/tmp", "fuzz") | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
socket := fmt.Sprintf("%s/attacker.sock", directory) | ||
listener, err := net.Listen("unix", socket) | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
go func() { | ||
connection, err := listener.Accept() | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
_, err = connection.Write(fuzz) | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
err = connection.Close() | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
}() | ||
defer listener.Close() | ||
defer os.RemoveAll(directory) | ||
|
||
// Setup targeter | ||
targeter := Targeter(func(target *Target) error { | ||
target.Method = "GET" | ||
target.URL = "http://vegeta.test" | ||
return nil | ||
}) | ||
|
||
// Deliver a single hit | ||
attacker := NewAttacker( | ||
UnixSocket(socket), | ||
Workers(1), | ||
MaxWorkers(1), | ||
Timeout(time.Second), | ||
KeepAlive(false), | ||
) | ||
result := attacker.hit(targeter, "fuzz") | ||
if result.Error != "" { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
// FuzzAttackerHTTP fuzzes valid HTTP responses to attacker. | ||
func FuzzAttackerHTTP(fuzz []byte) int { | ||
// Decode response | ||
code, headers, body, ok := decodeFuzzResponse(fuzz) | ||
if !ok { | ||
return -1 | ||
} | ||
|
||
// Start server | ||
directory, err := ioutil.TempDir("/tmp", "fuzz") | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
socket := fmt.Sprintf("%s/attacker.sock", directory) | ||
listener, err := net.Listen("unix", socket) | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
handler := func(response http.ResponseWriter, request *http.Request) { | ||
for name, values := range headers { | ||
for _, value := range values { | ||
response.Header().Add(name, value) | ||
} | ||
} | ||
response.WriteHeader(int(code)) | ||
_, err := response.Write(body) | ||
if err != nil { | ||
panic(err.Error()) | ||
} | ||
} | ||
server := http.Server{ | ||
Handler: http.HandlerFunc(handler), | ||
} | ||
defer server.Close() | ||
defer listener.Close() | ||
defer os.RemoveAll(directory) | ||
go server.Serve(listener) | ||
|
||
// Setup targeter | ||
targeter := Targeter(func(target *Target) error { | ||
target.Method = "GET" | ||
target.URL = "http://vegeta.test" | ||
return nil | ||
}) | ||
|
||
// Deliver a single hit | ||
attacker := NewAttacker( | ||
UnixSocket(socket), | ||
Workers(1), | ||
MaxWorkers(1), | ||
Timeout(time.Second), | ||
KeepAlive(false), | ||
) | ||
result := attacker.hit(targeter, "fuzz") | ||
if result.Error != "" { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
func decodeFuzzResponse(fuzz []byte) ( | ||
code int, | ||
headers map[string][]string, | ||
body []byte, | ||
ok bool, | ||
) { | ||
if len(fuzz) < 2 { | ||
return | ||
} | ||
headers = make(map[string][]string) | ||
body = []byte{} | ||
code = int(binary.LittleEndian.Uint16(fuzz[0:2])) | ||
if len(fuzz) == 2 { | ||
ok = true | ||
return | ||
} | ||
fuzz, ok = decodeFuzzHeaders(fuzz[2:], headers) | ||
if !ok { | ||
return | ||
} | ||
body = fuzz | ||
ok = true | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// +build gofuzz | ||
|
||
package vegeta | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
) | ||
|
||
// FuzzResultsFormatDetection tests result list format detection. | ||
func FuzzResultsFormatDetection(fuzz []byte) int { | ||
decoder := DecoderFor(bytes.NewReader(fuzz)) | ||
if decoder == nil { | ||
return 0 | ||
} | ||
ok := readAllResults(decoder) | ||
if !ok { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
// FuzzGobDecoder tests decoding a gob format result list. | ||
func FuzzGobDecoder(fuzz []byte) int { | ||
decoder := NewDecoder(bytes.NewReader(fuzz)) | ||
ok := readAllResults(decoder) | ||
if !ok { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
// FuzzCSVDecoder tests decoding a CSV format result list. | ||
func FuzzCSVDecoder(fuzz []byte) int { | ||
decoder := NewCSVDecoder(bytes.NewReader(fuzz)) | ||
ok := readAllResults(decoder) | ||
if !ok { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
// FuzzJSONDecoder tests decoding a JSON format result list. | ||
func FuzzJSONDecoder(fuzz []byte) int { | ||
decoder := NewJSONDecoder(bytes.NewReader(fuzz)) | ||
ok := readAllResults(decoder) | ||
if !ok { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
func readAllResults(decoder Decoder) (ok bool) { | ||
for { | ||
result := &Result{} | ||
err := decoder.Decode(result) | ||
if err == io.EOF { | ||
return true | ||
} else if err != nil { | ||
return false | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// +build gofuzz | ||
|
||
package vegeta | ||
|
||
import ( | ||
"bytes" | ||
"net/http" | ||
) | ||
|
||
// FuzzHTTPTargeter tests decoding an HTTP encoded target list. | ||
func FuzzHTTPTargeter(fuzz []byte) int { | ||
headers, body, fuzz, ok := decodeFuzzTargetDefaults(fuzz) | ||
if !ok { | ||
return -1 | ||
} | ||
targeter := NewHTTPTargeter( | ||
bytes.NewReader(fuzz), | ||
body, | ||
headers, | ||
) | ||
_, err := ReadAllTargets(targeter) | ||
if err != nil { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
// FuzzJSONTargeter tests decoding a JSON encoded target list. | ||
func FuzzJSONTargeter(fuzz []byte) int { | ||
headers, body, fuzz, ok := decodeFuzzTargetDefaults(fuzz) | ||
if !ok { | ||
return -1 | ||
} | ||
targeter := NewJSONTargeter( | ||
bytes.NewReader(fuzz), | ||
body, | ||
headers, | ||
) | ||
_, err := ReadAllTargets(targeter) | ||
if err != nil { | ||
return 0 | ||
} | ||
return 1 | ||
} | ||
|
||
func decodeFuzzTargetDefaults(fuzz []byte) ( | ||
headers http.Header, | ||
body []byte, | ||
rest []byte, | ||
ok bool, | ||
) { | ||
if len(fuzz) < 2 { | ||
return | ||
} | ||
headers = make(map[string][]string) | ||
body = []byte{} | ||
rest = []byte{} | ||
rest, ok = decodeFuzzHeaders(fuzz, headers) | ||
if !ok { | ||
return | ||
} | ||
if len(rest) == 0 { | ||
ok = true | ||
return | ||
} | ||
body, rest, ok = extractFuzzByteString(rest) | ||
return | ||
} |
Oops, something went wrong.