Skip to content

Commit 86b1448

Browse files
committed
Attempt to rune bruteforce test
1 parent 68aa997 commit 86b1448

File tree

3 files changed

+177
-27
lines changed

3 files changed

+177
-27
lines changed

.github/workflows/cflite.yml

+26-15
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,29 @@ jobs:
1313
matrix:
1414
sanitizer: [address]
1515
steps:
16-
- name: Build Fuzzers (${{ matrix.sanitizer }})
17-
id: build
18-
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
19-
with:
20-
sanitizer: ${{ matrix.sanitizer }}
21-
language: c
22-
bad-build-check: false
23-
- name: Run Fuzzers (${{ matrix.sanitizer }})
24-
id: run
25-
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
26-
with:
27-
fuzz-seconds: 100
28-
mode: 'code-change'
29-
report-unreproducible-crashes: false
30-
sanitizer: ${{ matrix.sanitizer }}
16+
- name: Check out repository code
17+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
18+
with:
19+
fetch-depth: 1
20+
21+
- name: Run app
22+
run: |
23+
cd $GITHUB_WORKSPACE
24+
./.github/workflows/scripts/run_app.sh
25+
26+
- name: Build Fuzzers (${{ matrix.sanitizer }})
27+
id: build
28+
uses: google/clusterfuzzlite/actions/build_fuzzers@v1
29+
with:
30+
sanitizer: ${{ matrix.sanitizer }}
31+
language: c
32+
bad-build-check: false
33+
34+
- name: Run Fuzzers (${{ matrix.sanitizer }})
35+
id: run
36+
uses: google/clusterfuzzlite/actions/run_fuzzers@v1
37+
with:
38+
fuzz-seconds: 100
39+
mode: 'code-change'
40+
report-unreproducible-crashes: false
41+
sanitizer: ${{ matrix.sanitizer }}

.github/workflows/scripts/run_app.sh

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/bin/bash
2+
set -e
3+
4+
echo "Running setup"
5+
sudo apt-get update
6+
sudo apt-get install -y tor
7+
8+
cd $GITHUB_WORKSPACE/backend # to install backend dependencies
9+
python3 -mvenv env
10+
source env/bin/activate
11+
pip3 install coverage
12+
pip3 install -r requirements/requirements-$(lsb_release -cs).txt
13+
14+
cd $GITHUB_WORKSPACE/client # to install frontend dependencies
15+
npm install -d
16+
./node_modules/grunt/bin/grunt build_for_testing
17+
18+
./bin/globaleaks -z
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,145 @@
11
import atheris
2+
import random
3+
import string
24
import sys
3-
from globaleaks.rest import api
5+
from twisted.internet import protocol, ssl, reactor
6+
from twisted.protocols import basic
47

5-
def fuzz_test_resolve_handler(fuzz_input: str):
6-
# Call the resolve_handler method with the fuzzed input
7-
match, handler = api.APIResourceWrapper().resolve_handler(fuzz_input)
88

9-
def fuzz_target(input_data: bytes):
10-
# Convert the fuzzed byte input to a string
9+
class HTTPSClientProtocol(basic.Int32StringReceiver):
10+
"""
11+
Custom Protocol to handle sending HTTP requests over TLS.
12+
"""
13+
14+
def connectionMade(self):
15+
"""
16+
This is called when the connection is established.
17+
Continuously send random requests.
18+
"""
19+
self.send_random_request()
20+
21+
def dataReceived(self, data):
22+
"""
23+
This is called when we receive a response from the server.
24+
Print out the response and send a new request.
25+
"""
26+
print(f"Received response: {data[:100]}...") # Print first 100 chars of the response
27+
self.send_random_request()
28+
29+
def send_random_request(self):
30+
"""Generate and send a random HTTP request."""
31+
random_http_request = self.generate_random_http_request()
32+
print(f"Sending request: {random_http_request[:50]}...") # Print first 50 chars of request
33+
self.sendString(random_http_request.encode('utf-8'))
34+
35+
def generate_random_string(self, length: int) -> str:
36+
"""Generate a random string of given length."""
37+
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
38+
39+
def generate_random_http_request(self) -> str:
40+
"""Generate a random HTTP request (GET, POST, etc.) with random headers and path."""
41+
methods = ["GET", "POST", "PUT", "DELETE", "PATCH"]
42+
method = random.choice(methods)
43+
44+
path = '/' + self.generate_random_string(random.randint(5, 20))
45+
http_version = "HTTP/1.1"
46+
47+
headers = {
48+
"Host": "localhost:8443",
49+
"User-Agent": "FuzzingBot/1.0",
50+
"Content-Type": random.choice(["text/plain", "application/json", "text/html"]),
51+
}
52+
53+
headers_str = "\r\n".join([f"{key}: {value}" for key, value in headers.items()])
54+
55+
body = ""
56+
if method in ["POST", "PUT"]:
57+
body = f"\r\n\r\n{self.generate_random_string(50)}"
58+
59+
request = f"{method} {path} {http_version}\r\n{headers_str}{body}\r\n\r\n"
60+
return request
61+
62+
63+
class HTTPSClientFactory(protocol.ClientFactory):
64+
"""Factory for creating a new HTTPSClientProtocol instance."""
65+
66+
def buildProtocol(self, addr):
67+
return HTTPSClientProtocol()
68+
69+
def clientConnectionFailed(self, connector, reason):
70+
"""This is called when a connection attempt fails."""
71+
print(f"Connection failed: {reason}")
72+
# Retry the connection after a delay
73+
connector.connect()
74+
75+
def clientConnectionLost(self, connector, reason):
76+
"""This is called when a connection is lost."""
77+
print(f"Connection lost: {reason}")
78+
# Retry the connection after a delay
79+
connector.connect()
80+
81+
82+
def fuzz_test_request(input_data: bytes):
83+
"""
84+
Fuzzing function for Atheris. The input data is used to generate random HTTP requests.
85+
"""
86+
87+
# Convert the fuzzed byte input into a string
1188
fuzz_input = input_data.decode(errors="ignore")
1289

13-
# Call the fuzz test handler function with the decoded string
14-
fuzz_test_resolve_handler(fuzz_input)
90+
# Generate a random HTTP request using fuzzed data
91+
random_http_request = generate_random_http_request_with_fuzzed_input(fuzz_input)
1592

16-
def main():
17-
# Set up Atheris and pass the fuzz target function
18-
atheris.Setup(sys.argv, fuzz_target)
93+
print(f"Sending fuzzed request: {random_http_request[:50]}...") # Print first 50 chars
1994

20-
# Start fuzzing
95+
# Initiate a real connection to the server
96+
context_factory = ssl.ClientContextFactory()
97+
factory = HTTPSClientFactory()
98+
99+
reactor.connectSSL('127.0.0.1', 8443, factory, context_factory) # Connect to the server
100+
101+
# Send the fuzzed HTTP request over TLS
102+
factory.buildProtocol(None).sendString(random_http_request.encode('utf-8'))
103+
104+
105+
def generate_random_string(length: int) -> str:
106+
"""Generate a random string of given length."""
107+
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
108+
109+
110+
def generate_random_http_request_with_fuzzed_input(fuzz_input: str) -> str:
111+
"""
112+
Generate an HTTP request with the fuzzed input, potentially modifying the request.
113+
"""
114+
methods = ["GET", "POST", "PUT", "DELETE", "PATCH"]
115+
method = random.choice(methods)
116+
117+
path = '/' + generate_random_string(random.randint(5, 20))
118+
http_version = "HTTP/1.1"
119+
120+
headers = {
121+
"Host": "localhost:8443",
122+
"User-Agent": "FuzzingBot/1.0",
123+
"Content-Type": "text/plain",
124+
}
125+
126+
headers_str = "\r\n".join([f"{key}: {value}" for key, value in headers.items()])
127+
128+
# Using fuzz input in the body or headers
129+
body = f"\r\n\r\n{fuzz_input}"
130+
131+
request = f"{method} {path} {http_version}\r\n{headers_str}{body}\r\n\r\n"
132+
return request
133+
134+
135+
def main():
136+
"""
137+
Set up Atheris for fuzzing, while making use of the `fuzz_test_request` function.
138+
"""
139+
atheris.Setup(sys.argv, fuzz_test_request)
21140
atheris.Fuzz()
22141

142+
23143
if __name__ == "__main__":
24144
main()
145+

0 commit comments

Comments
 (0)