commit 01fb94e51100d041731a34ea87ea5cb03189066f
parent 521cd3d1f908c8beffa08ddece4679641493df1f
Author: MTRNord <mtrnord1@gmail.com>
Date: Tue, 30 Aug 2022 20:11:14 +0200
Run tests in CI and pass creds via env vars instead
Diffstat:
10 files changed, 383 insertions(+), 36 deletions(-)
diff --git a/.github/workflows/docker-build-publish-fuzz_login.yml b/.github/workflows/docker_fuzz_login.yml
diff --git a/.github/workflows/docker_synapse_test_env.yml b/.github/workflows/docker_synapse_test_env.yml
@@ -0,0 +1,83 @@
+name: Docker Synapse
+on:
+ push:
+ branches: ["main"]
+
+env:
+ # Use docker.io for Docker Hub if empty
+ REGISTRY: ghcr.io
+ # github.repository as <account>/<repo>
+ IMAGE_NAME: ${{ github.repository }}
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ # This is used to complete the identity challenge
+ # with sigstore/fulcio when running outside of PRs.
+ id-token: write
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Install the cosign tool except on PR
+ # https://github.com/sigstore/cosign-installer
+ - name: Install cosign
+ if: github.event_name != 'pull_request'
+ uses: sigstore/cosign-installer@7e0881f8fe90b25e305bbf0309761e9314607e25
+ with:
+ cosign-release: "v1.9.0"
+
+ # Workaround: https://github.com/docker/build-push-action/issues/461
+ - name: Setup Docker buildx
+ uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
+
+ # Login against a Docker registry except on PR
+ # https://github.com/docker/login-action
+ - name: Log into registry ${{ env.REGISTRY }}
+ if: github.event_name != 'pull_request'
+ uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ # Extract metadata (tags, labels) for Docker
+ # https://github.com/docker/metadata-action
+ - name: Extract Docker metadata
+ id: meta
+ uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
+ with:
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+ tags: type=raw,value=latest
+
+ # Build and push Docker image with Buildx (don't push on PR)
+ # https://github.com/docker/build-push-action
+ - name: Build and push Docker image
+ id: build-and-push
+ uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
+ with:
+ build-args: version=v1.66.0rc2
+ context: ./dockerfiles
+ push: ${{ github.event_name != 'pull_request' }}
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+ file: ./dockerfiles/synapse
+
+ # Sign the resulting Docker image digest except on PRs.
+ # This will only write to the public Rekor transparency log when the Docker
+ # repository is public to avoid leaking data. If you would like to publish
+ # transparency data even for private images, pass --force to cosign below.
+ # https://github.com/sigstore/cosign
+ - name: Sign the published Docker image
+ if: ${{ github.event_name != 'pull_request' }}
+ env:
+ COSIGN_EXPERIMENTAL: "true"
+ # This step uses the identity token to provision an ephemeral certificate
+ # against the sigstore community Fulcio instance.
+ run: echo "${{ steps.meta.outputs.tags }}" | xargs -I {} cosign sign {}@${{ steps.build-and-push.outputs.digest }}
diff --git a/.github/workflows/test_known.yml b/.github/workflows/test_known.yml
@@ -0,0 +1,65 @@
+name: Test known issues
+
+on:
+ workflow_run:
+ workflows: ["Docker Synapse"]
+ types:
+ - completed
+
+env:
+ CARGO_TERM_COLOR: always
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ container: rustlang/rust:nightly-slim
+
+ services:
+ postgres:
+ # Docker Hub image
+ image: postgres
+ # Provide the password for postgres
+ env:
+ POSTGRES_PASSWORD: postgres
+ # Set health checks to wait until postgres has started
+ options: >-
+ --health-cmd pg_isready
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+ redis:
+ image: redis
+ # Set health checks to wait until redis has started
+ options: >-
+ --health-cmd "redis-cli ping"
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+ synapse:
+ image: ghcr.io/MTRNord/synapse:latest
+ # Set health checks to wait until redis has started
+ options: >-
+ --health-interval 10s
+ --health-timeout 5s
+ --health-retries 5
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Login get_nonce
+ id: get_nonce
+ run: echo "::set-output nonce=$(curl http://localhost:8008/_synapse/admin/v1/register | jq -r .nonce)"
+ - name: Generate mac
+ id: generate_mac
+ run: python3 ./dockerfiles/synapse_generate_login.py
+ env:
+ NONCE: ${{ steps.get_nonce.outputs.nonce }}
+ - name: Login
+ run: 'curl -X POST http://localhost:8008/_synapse/admin/v1/login -d ''{"mac": "${MAC}", "nonce": "${NONCE}", "username": "fuzzer", "password": "Chu8chool0dooqueiwo0lohviegho6ieveuNg3Ohcio2aekaiw0ioF6waifo8eep"}'''
+ env:
+ MAC: ${{ steps.generate_mac.outputs.hmac }}
+ NONCE: ${{ steps.get_nonce.outputs.nonce }}
+ - name: Run tests
+ run: cargo test
+ env:
+ MATRIX_USERNAME: "fuzzer"
+ MATRIX_PASSWORD: "Chu8chool0dooqueiwo0lohviegho6ieveuNg3Ohcio2aekaiw0ioF6waifo8eep"
diff --git a/README.md b/README.md
@@ -13,41 +13,25 @@ Matrix fuzzing is a dumb fuzzer fuzzing a few matrix endpoints. It requires a HS
# Usage of fuzzcheck-rs
1. Create a HS
-1. Setup a user
-1. Add the secrets to src/secrets.rs.
-
- Example code:
-
- ```rust
- pub const USERNAME: &str = "@a:localhost";
- pub const PASSWORD: &str = "abc123";
- ```
-
-1. Install fuzzcheck -> https://github.com/loiclec/fuzzcheck-rs#setup
-1. Run `cargo fuzzcheck <target>`
-1. Wait until it crashes
-1. Verify the error by trying the output json yourself
-1. Please make sure to follow https://matrix.org/security-disclosure-policy/ for found errors instead of posting them in public unless you are 100% sure they are not a security issue. If you are in doubt prefer the security disclosure policy.
+2. Setup a user
+3. Set `MATRIX_USERNAME` and `MATRIX_PASSWORD` to the username and password of the user you want to fuzz as.
+4. Install fuzzcheck -> https://github.com/loiclec/fuzzcheck-rs#setup
+5. Run `cargo fuzzcheck <target>`
+6. Wait until it crashes
+7. Verify the error by trying the output json yourself
+8. Please make sure to follow https://matrix.org/security-disclosure-policy/ for found errors instead of posting them in public unless you are 100% sure they are not a security issue. If you are in doubt prefer the security disclosure policy.
# Usage of afl.rs
1. Create a HS
1. Setup a user
-1. Add the secrets to src/secrets.rs.
-
- Example code:
-
- ```rust
- pub const USERNAME: &str = "@a:localhost";
- pub const PASSWORD: &str = "abc123";
- ```
-
-1. Install afl.rs -> `cargo install afl`
-1. Run `cargo afl build`
-2. Run `cargo afl fuzz -i ./afl/<target>/in -o ./afl/<target>/out ./target/debug/<target>`
-3. Wait until it crashes
-4. Verification is a little harder. See https://github.com/rust-fuzz/afl.rs/issues/215 on how to reproduce things
-5. Please make sure to follow https://matrix.org/security-disclosure-policy/ for found errors instead of posting them in public unless you are 100% sure they are not a security issue. If you are in doubt prefer the security disclosure policy.
+2. Install afl.rs -> `cargo install afl`
+3. Run `cargo afl build`
+4. Set `MATRIX_USERNAME` and `MATRIX_PASSWORD` to the username and password of the user you want to fuzz as.
+5. Run `cargo afl fuzz -i ./afl/<target>/in -o ./afl/<target>/out ./target/debug/<target>`
+6. Wait until it crashes
+7. Verification is a little harder. See https://github.com/rust-fuzz/afl.rs/issues/215 on how to reproduce things
+8. Please make sure to follow https://matrix.org/security-disclosure-policy/ for found errors instead of posting them in public unless you are 100% sure they are not a security issue. If you are in doubt prefer the security disclosure policy.
# Hall of Explosions (Bugs found)
diff --git a/dockerfiles/synapse b/dockerfiles/synapse
@@ -0,0 +1,8 @@
+ARG version
+FROM matrix/synapse:${version}
+
+COPY ./synapse_config.yaml /synapse/config/homeserver.yaml
+COPY ./synapse_log.yaml /synapse/config/log.yaml
+COPY ./synapse_signing.key /synapse/keys/signing.key
+
+CMD "exec python -B -m synapse.app.homeserver -c /synapse/config/homeserver.yaml"
+\ No newline at end of file
diff --git a/dockerfiles/synapse_config.yaml b/dockerfiles/synapse_config.yaml
@@ -0,0 +1,143 @@
+## Server ##
+
+server_name: "localhost"
+public_baseurl: "http://localhost:8008"
+pid_file: /homeserver.pid
+web_client: False
+soft_file_limit: 0
+log_config: "/synapse/config/log.yaml"
+report_stats: false
+
+## Ports ##
+
+listeners:
+ - port: 8008
+ tls: false
+ bind_addresses: ["::"]
+ type: http
+ x_forwarded: true
+
+ resources:
+ - names: [client, federation]
+ compress: false
+
+ - port: 9090
+ tls: false
+ bind_addresses: ["::"]
+ type: http
+
+ resources:
+ - names: [metrics]
+ compress: false
+
+ - port: 9093
+ tls: false
+ bind_addresses: ["::"]
+ type: http
+
+ resources:
+ - names: [replication]
+ compress: false
+
+## Files ##
+
+media_store_path: "/synapse/data/media"
+uploads_path: "/synapse/data/uploads"
+
+## Registration ##
+registration_shared_secret: "sahZae3yahjaequ8boh2cae5uo5eiciede2hoa9eew8mai1oy4iiChietheequ9U"
+enable_registration: false
+
+## API Configuration ##
+
+## Database configuration ##
+database:
+ name: "psycopg2"
+ args:
+ user: "postgres"
+ password: "postgres"
+ sslmode: "prefer"
+ database: "synapse"
+ port: 5432
+ cp_min: 5
+ cp_max: 10
+ host: "postgres"
+
+## Redis configuration ##
+redis:
+ enabled: true
+ host: "redis"
+ port: 6379
+
+## Metrics ###
+
+enable_metrics: true
+
+## Signing Keys ##
+
+signing_key_path: "/synapse/keys/signing.key"
+
+# The trusted servers to download signing keys from.
+trusted_key_servers:
+ - server_name: matrix.org
+
+## Extra config ##
+
+enable_media_repo: false
+federation_domain_whitelist: []
+federation_rr_transactions_per_room_per_second: 1000000000000
+federation_verify_certificates: false
+rc_3pid_validation:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_admin_redaction:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_federation:
+ concurrent: 3
+ reject_limit: 1000000000000
+ sleep_delay: 500
+ sleep_limit: 10
+ window_size: 1000
+rc_invites:
+ per_issuer:
+ burst_count: 150000000000
+ per_second: 1000000000000
+ per_room:
+ burst_count: 150000000000
+ per_second: 1000000000000
+ per_user:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_joins:
+ local:
+ burst_count: 150000000000
+ per_second: 1000000000000
+ remote:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_joins_per_room:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_login:
+ account:
+ burst_count: 150000000000
+ per_second: 1000000000000
+ address:
+ burst_count: 150000000000
+ per_second: 1000000000000
+ failed_attempts:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_message:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_registration:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_registration_token_validity:
+ burst_count: 150000000000
+ per_second: 1000000000000
+rc_third_party_invite:
+ burst_count: 150000000000
+ per_second: 1000000000000
diff --git a/dockerfiles/synapse_generate_login.py b/dockerfiles/synapse_generate_login.py
@@ -0,0 +1,28 @@
+import hashlib
+import hmac
+import os
+
+
+def generate_mac(nonce, user, password, admin=False, user_type=None):
+ mac = hmac.new(
+ key=shared_secret,
+ digestmod=hashlib.sha1,
+ )
+
+ mac.update(nonce.encode('utf8'))
+ mac.update(b"\x00")
+ mac.update(user.encode('utf8'))
+ mac.update(b"\x00")
+ mac.update(password.encode('utf8'))
+ mac.update(b"\x00")
+ mac.update(b"admin" if admin else b"notadmin")
+ if user_type:
+ mac.update(b"\x00")
+ mac.update(user_type.encode('utf8'))
+
+ return mac.hexdigest()
+
+
+hmac = generate_mac(os.environ['NONCE'], "fuzzer",
+ "Chu8chool0dooqueiwo0lohviegho6ieveuNg3Ohcio2aekaiw0ioF6waifo8eep")
+print(f"::set-output hmac={hmac}")
diff --git a/dockerfiles/synapse_log.yaml b/dockerfiles/synapse_log.yaml
@@ -0,0 +1,20 @@
+version: 1
+formatters:
+ precise:
+ format: "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s- %(message)s"
+filters:
+ context:
+ (): synapse.util.logcontext.LoggingContextFilter
+ request: ""
+handlers:
+ console:
+ class: logging.StreamHandler
+ formatter: precise
+ filters: [context]
+ level: INFO
+loggers:
+ synapse:
+ level: INFO
+root:
+ level: INFO
+ handlers: [console]
diff --git a/dockerfiles/synapse_signing.key b/dockerfiles/synapse_signing.key
@@ -0,0 +1 @@
+ed25519 a_oLGZ qZ1gPAYosg/jvgVQN316wNjJzIiadkKJ4Wglek5VDIY
+\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
@@ -5,9 +5,8 @@
use crate::types::{Flow, LoginGet, LoginPost};
use once_cell::sync::OnceCell;
-use std::collections::HashMap;
+use std::{collections::HashMap, env};
-pub mod secrets;
pub mod types;
#[no_coverage]
@@ -31,6 +30,14 @@ pub fn client() -> &'static reqwest::blocking::Client {
#[no_coverage]
fn login() -> String {
+ let username = match env::var("MATRIX_USERNAME") {
+ Ok(v) => v,
+ Err(e) => panic!("$MATRIX_USERNAME is not set ({})", e),
+ };
+ let password = match env::var("MATRIX_PASSWORD") {
+ Ok(v) => v,
+ Err(e) => panic!("$MATRIX_PASSWORD is not set ({})", e),
+ };
let client = crate::client();
let res: LoginGet = client
.get("http://localhost:8008/_matrix/client/v3/login")
@@ -44,8 +51,8 @@ fn login() -> String {
let mut map = HashMap::new();
map.insert("type", "m.login.password");
- map.insert("user", secrets::USERNAME);
- map.insert("password", secrets::PASSWORD);
+ map.insert("user", &username);
+ map.insert("password", &password);
let res: LoginPost = client
.post("http://localhost:8008/_matrix/client/v3/login")
.json(&map)
@@ -228,11 +235,17 @@ mod tests {
json_data._type = "m.login.password".to_string();
}
}
+
+ let username = match env::var("MATRIX_USERNAME") {
+ Ok(v) => v,
+ Err(e) => panic!("$MATRIX_USERNAME is not set ({})", e),
+ };
+
if json_data.user.is_some() {
- json_data.user = Some(crate::secrets::USERNAME.to_string());
+ json_data.user = Some(username);
}
if let Some(identifier) = &mut json_data.identifier {
- identifier.user = crate::secrets::USERNAME.to_string();
+ identifier.user = username;
identifier._type = "m.id.user".to_string();
}