commit 6de2661b4c739c27ce2089931f38d415a0cfa58f
parent 80139672bea0b9548ac7dfdee54315f4fa6214ff
Author: MTRNord <mtrnord1@gmail.com>
Date: Sat, 13 Aug 2022 12:36:11 +0200
Add basic login fuzzing
Diffstat:
9 files changed, 164 insertions(+), 27 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -19,3 +19,7 @@ once_cell = "1.13.0"
reqwest = {version = "0.11.11", features = ["blocking", "json", "gzip"]}
serde = {version = "1.0", features = ["derive"]}
serde_json = "1.0.83"
+
+[features]
+default = ["fuzzing"]
+fuzzing = []
diff --git a/afl/createRoom/in/10 b/afl/createRoom/in/10
@@ -0,0 +1 @@
+z"room_version":"","topic":"��"}
+\ No newline at end of file
diff --git a/afl/createRoom/in/14 b/afl/createRoom/in/14
@@ -0,0 +1 @@
+{"ronm_version":"","topic":"��"}
+\ No newline at end of file
diff --git a/afl/createRoom/in/15 b/afl/createRoom/in/15
@@ -0,0 +1 @@
+{"rooí_version":"","topic":"��"}
+\ No newline at end of file
diff --git a/afl/createRoom/in/8 b/afl/createRoom/in/8
@@ -0,0 +1 @@
+{"rnom_version":"","topic":"��"}
+\ No newline at end of file
diff --git a/afl/createRoom/in/9 b/afl/createRoom/in/9
@@ -0,0 +1 @@
+û"room_version":"","topic":"��"}
+\ No newline at end of file
diff --git a/src/fuzzTargets/createRoom.rs b/src/fuzzTargets/createRoom.rs
@@ -3,24 +3,28 @@ use matrix_fuzz::{client, secrets::ACCESS_TOKEN, types::create_room::CreateRoomM
fn main() {
afl::fuzz_nohook!(|data: CreateRoomMagicJSON| {
- // FIXME: We probably should set it to null and not do a false positive
+ let mut data = data;
// HACK due to https://github.com/matrix-org/synapse/issues/13510
if let Some(room_alias_name) = &data.room_alias_name {
if room_alias_name.contains('\0') {
- return;
+ data.room_alias_name = None;
}
}
+
// HACK due to NUL in type or state_key
- if let Some(initial_state) = &data.initial_state {
- for state in initial_state {
- if state._type.contains('\0') {
- return;
- }
- if state.state_key.contains('\0') {
- return;
- }
- }
+ if let Some(initial_state) = &mut data.initial_state {
+ initial_state
+ .retain(|state| !(state._type.contains('\0') || state.state_key.contains('\0')));
+ // for state in initial_state {
+ // if state._type.contains('\0') {
+ // return;
+ // }
+ // if state.state_key.contains('\0') {
+ // return;
+ // }
+ // }
}
+
/*// HACK due to https://github.com/matrix-org/synapse/issues/13511
if let Some(pids) = &data.invite_3pid {
for pid in pids {
diff --git a/src/lib.rs b/src/lib.rs
@@ -128,27 +128,105 @@ mod tests {
#[cfg(all(fuzzing, test))]
mod tests {
- use crate::types::create_room::{CreateRoomMagic, CreateRoomMagicJSON};
+ use crate::types::{
+ create_room::{CreateRoomMagic, CreateRoomMagicJSON},
+ LoginPostReq,
+ };
+
+ fn login(data: &LoginPostReq) -> bool {
+ let mut data = data.clone();
+ // We hardcode the type for better fuzzing
+ data._type = "m.login.password".to_string();
+
+ if let Some(user) = &data.user {
+ if user.contains("\0") {
+ data.user = None;
+ }
+ }
+ if let Some(medium) = &data.medium {
+ if medium.contains("\0") {
+ data.medium = None;
+ }
+ }
+ if let Some(address) = &data.address {
+ if address.contains("\0") {
+ data.address = None;
+ }
+ }
+ if let Some(user) = &data.user {
+ if user.contains("\0") {
+ data.user = None;
+ }
+ }
+
+ let client = crate::client();
+ let resp = client
+ .post("http://localhost:8008/_matrix/client/v3/login")
+ .json(&data)
+ .send();
+ if let Ok(resp) = resp {
+ let status = resp.status();
+ if !status.is_success() {
+ if status == 400 {
+ return true;
+ }
+ let content = resp.text();
+ if let Ok(ref content) = content {
+ if content.contains("Unknown login type")
+ || content.contains("Invalid login submission")
+ || content.contains("Invalid username or password")
+ {
+ return true;
+ }
+ }
+ println!("Status: {:?}", status);
+ println!("Content: {:?}", content);
+ }
+ }
+ false
+ }
+
+ #[test]
+ fn fuzz_login() {
+ let client = crate::client();
+ let resp = client
+ .get("http://localhost:8008/_matrix/key/v2/server")
+ .send()
+ .unwrap();
+ if !resp.status().is_success() {
+ panic!("Failed to connect");
+ }
+
+ let result = fuzzcheck::fuzz_test(login)
+ .default_options()
+ .stop_after_first_test_failure(true)
+ .launch();
+ assert!(!result.found_test_failure);
+ }
fn create_room(data: &CreateRoomMagic) -> bool {
+ let mut json_data: CreateRoomMagicJSON = data.into();
// FIXME: We probably should set it to null and not do a false positive
// HACK due to https://github.com/matrix-org/synapse/issues/13510
- if let Some(room_alias_name) = &data.room_alias_name {
+ if let Some(room_alias_name) = &json_data.room_alias_name {
if room_alias_name.contains('\0') {
- return true;
+ json_data.room_alias_name = None;
}
}
// HACK due to NUL in type or state_key
- if let Some(initial_state) = &data.initial_state {
- for state in initial_state {
- if state._type.contains('\0') {
- return true;
- }
- if state.state_key.contains('\0') {
- return true;
- }
- }
+ if let Some(initial_state) = &mut json_data.initial_state {
+ initial_state
+ .retain(|state| !(state._type.contains('\0') || state.state_key.contains('\0')));
+ // for state in initial_state {
+ // if state._type.contains('\0') {
+ // return;
+ // }
+ // if state.state_key.contains('\0') {
+ // return;
+ // }
+ // }
}
+
/*// HACK due to https://github.com/matrix-org/synapse/issues/13511
if let Some(pids) = &data.invite_3pid {
for pid in pids {
@@ -161,7 +239,6 @@ mod tests {
// TODO: Login once and reuse the access token
let access_token = crate::access_token();
let client = crate::client();
- let json_data: CreateRoomMagicJSON = data.into();
let resp = client
.post("http://localhost:8008/_matrix/client/v3/createRoom")
.header("Authorization", format!("Bearer {}", access_token))
@@ -180,9 +257,9 @@ mod tests {
|| content.contains("Invalid user_id")
|| content.contains("is not a valid preset")
|| content.contains("You are not allowed to set others state")
- {
- return true;
- }
+ {
+ return true;
+ }
}
println!("Content: {:?}", content);
diff --git a/src/types.rs b/src/types.rs
@@ -1,5 +1,7 @@
pub mod create_room;
+use arbitrary::Arbitrary;
+use fuzzcheck::DefaultMutator;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
@@ -19,3 +21,43 @@ pub struct LoginPost {
pub access_token: String,
pub home_server: String,
}
+
+#[derive(Debug, Clone, Serialize, Deserialize, DefaultMutator, Arbitrary)]
+pub struct LoginPostReq {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub address: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub device_id: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub identifier: Option<Identifier>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub initial_device_display_name: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub medium: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub password: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub refresh_token: Option<bool>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub token: Option<String>,
+ #[serde(rename = "type")]
+ pub _type: String,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub user: Option<String>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, DefaultMutator, Arbitrary)]
+pub struct Identifier {
+ #[serde(rename = "type")]
+ pub _type: String,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub user: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub medium: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub address: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub country: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub phone: Option<String>,
+}