feat: added modified TCP packet parser
checksum generation code is different, to allow for some sneaky tricks with regards to identifying the sparse session but binding to the same port multiple times
This commit is contained in:
parent
25948a17f4
commit
e5f6c2aa7e
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1298,6 +1298,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"nl-sys",
|
"nl-sys",
|
||||||
|
"packets",
|
||||||
"pcap-sys",
|
"pcap-sys",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
|||||||
@ -22,4 +22,4 @@ cc = "1.0"
|
|||||||
[features]
|
[features]
|
||||||
docker-breakout = []
|
docker-breakout = []
|
||||||
no-exit = []
|
no-exit = []
|
||||||
setuid = ["libc"]
|
setuid = ["libc"]
|
||||||
|
|||||||
@ -139,7 +139,9 @@ async fn handle_command(
|
|||||||
use pcap_sys::packets::*;
|
use pcap_sys::packets::*;
|
||||||
let eth_pkt = eth.pkt();
|
let eth_pkt = eth.pkt();
|
||||||
let Layer3Pkt::IPv4Pkt(ip_pkt) = eth_pkt.get_layer3_pkt()?;
|
let Layer3Pkt::IPv4Pkt(ip_pkt) = eth_pkt.get_layer3_pkt()?;
|
||||||
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
|
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()? else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
|
||||||
let source_port = udp_pkt.srcport();
|
let source_port = udp_pkt.srcport();
|
||||||
|
|
||||||
|
|||||||
@ -452,13 +452,14 @@ impl TCPPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct TCPPacketBuilder {
|
pub struct TCPPacketBuilder {
|
||||||
srcport: u16,
|
srcport: Option<u16>,
|
||||||
dstport: u16,
|
dstport: Option<u16>,
|
||||||
seqnumber: u32,
|
seqnumber: Option<u32>,
|
||||||
acknumber: u32,
|
acknumber: u32,
|
||||||
flags: u8,
|
flags: u8,
|
||||||
window: u16,
|
window: Option<u16>,
|
||||||
urgent_ptr: u16,
|
urgent_ptr: u16,
|
||||||
options: Vec<u8>,
|
options: Vec<u8>,
|
||||||
}
|
}
|
||||||
@ -478,17 +479,17 @@ macro_rules! declare_flag {
|
|||||||
|
|
||||||
impl TCPPacketBuilder {
|
impl TCPPacketBuilder {
|
||||||
pub fn srcport(mut self, port: u16) -> Self {
|
pub fn srcport(mut self, port: u16) -> Self {
|
||||||
self.srcport = port;
|
self.srcport = Some(port);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dstport(mut self, port: u16) -> Self {
|
pub fn dstport(mut self, port: u16) -> Self {
|
||||||
self.dstport = port;
|
self.dstport = Some(port);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seqnumber(mut self, num: u32) -> Self {
|
pub fn seqnumber(mut self, num: u32) -> Self {
|
||||||
self.seqnumber = num;
|
self.seqnumber = Some(num);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +508,7 @@ impl TCPPacketBuilder {
|
|||||||
declare_flag!(fin, 0x01);
|
declare_flag!(fin, 0x01);
|
||||||
|
|
||||||
pub fn window(mut self, window: u16) -> Self {
|
pub fn window(mut self, window: u16) -> Self {
|
||||||
self.window = window;
|
self.window = Some(window);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,6 +532,93 @@ impl TCPPacketBuilder {
|
|||||||
|
|
||||||
let protocol = &[0x00u8, 0x06u8];
|
let protocol = &[0x00u8, 0x06u8];
|
||||||
|
|
||||||
let tcp_length = data.len() + self.options.len() + 32;
|
let tcp_length = (data.len() + self.options.len() + 20) as u16;
|
||||||
|
|
||||||
|
let srcport = self.srcport.unwrap();
|
||||||
|
let dstport = self.dstport.unwrap();
|
||||||
|
let seqnumber = self.seqnumber.unwrap();
|
||||||
|
let window = self.window.unwrap();
|
||||||
|
|
||||||
|
let len: u8 = (self.options.len() / 4 + 5).try_into().unwrap();
|
||||||
|
let len = len << 4;
|
||||||
|
|
||||||
|
let mut bytes = [
|
||||||
|
&source.octets()[..],
|
||||||
|
&dest.octets(),
|
||||||
|
protocol,
|
||||||
|
&tcp_length.to_be_bytes(),
|
||||||
|
&srcport.to_be_bytes()[..],
|
||||||
|
&dstport.to_be_bytes(),
|
||||||
|
&seqnumber.to_be_bytes(),
|
||||||
|
&self.acknumber.to_be_bytes(),
|
||||||
|
&[len],
|
||||||
|
&[self.flags],
|
||||||
|
&window.to_be_bytes(),
|
||||||
|
&[0, 0],
|
||||||
|
&self.urgent_ptr.to_be_bytes(),
|
||||||
|
&self.options,
|
||||||
|
&data,
|
||||||
|
]
|
||||||
|
.concat();
|
||||||
|
|
||||||
|
let checksum = bytes
|
||||||
|
.chunks(2)
|
||||||
|
.map(|pair| {
|
||||||
|
if pair.len() == 1 {
|
||||||
|
(pair[0] as u32) << 8
|
||||||
|
} else {
|
||||||
|
(pair[0] as u32) << 8 | (pair[1] as u32)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fold(0u32, |acc, e| acc + e)
|
||||||
|
+ 30;
|
||||||
|
// + 30 to intentionally deviate from
|
||||||
|
// the RFC, to make it so that I can identify the packets as sparse
|
||||||
|
// packets
|
||||||
|
|
||||||
|
let checksum = (checksum >> 16) + (checksum & 0xffff);
|
||||||
|
let checksum = ((checksum >> 16) as u16) + (checksum as u16);
|
||||||
|
let checksum = dbg!(!checksum).to_be_bytes();
|
||||||
|
|
||||||
|
//bytes[16] = checksum[0];
|
||||||
|
//bytes[17] = checksum[1];
|
||||||
|
bytes[28] = checksum[0];
|
||||||
|
bytes[29] = checksum[1];
|
||||||
|
|
||||||
|
TCPPacket {
|
||||||
|
data: bytes[12..].to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tcp_checksum() {
|
||||||
|
let srcip = Ipv4Addr::new(127, 0, 0, 1);
|
||||||
|
let dstip = srcip.clone();
|
||||||
|
|
||||||
|
let packet = super::TCPPacketBuilder::default()
|
||||||
|
.srcport(36916)
|
||||||
|
.dstport(54248)
|
||||||
|
.seqnumber(0xFD65_CA26)
|
||||||
|
.syn(true)
|
||||||
|
.window(65495)
|
||||||
|
.options(vec![
|
||||||
|
0x02, 0x04, 0xff, 0xd7, 0x04, 0x02, 0x08, 0x0a, 0xce, 0x4e, 0xad, 0x04, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x01, 0x03, 0x03, 0x07,
|
||||||
|
])
|
||||||
|
.build(srcip, dstip, vec![]);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
&packet.data,
|
||||||
|
&vec![
|
||||||
|
0x90, 0x34, 0xd3, 0xe8, 0xfd, 0x65, 0xca, 0x26, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
|
||||||
|
0xff, 0xd7, 0xfe, 0x30, 0x00, 0x00, 0x02, 0x04, 0xff, 0xd7, 0x04, 0x02, 0x08, 0x0a,
|
||||||
|
0xce, 0x4e, 0xad, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,7 +105,9 @@ pub fn spawn_connection_handler(
|
|||||||
let packet = connection_packet.pkt();
|
let packet = connection_packet.pkt();
|
||||||
|
|
||||||
let Layer3Pkt::IPv4Pkt(ip_pkt) = packet.get_layer3_pkt()?;
|
let Layer3Pkt::IPv4Pkt(ip_pkt) = packet.get_layer3_pkt()?;
|
||||||
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
|
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()? else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
|
||||||
let data = udp_pkt.get_data();
|
let data = udp_pkt.get_data();
|
||||||
|
|
||||||
@ -198,7 +200,9 @@ fn authenticate<F: Fn()>(
|
|||||||
use packets::*;
|
use packets::*;
|
||||||
let p = p.pkt();
|
let p = p.pkt();
|
||||||
let Layer3Pkt::IPv4Pkt(ip_pkt) = p.get_layer3_pkt()?;
|
let Layer3Pkt::IPv4Pkt(ip_pkt) = p.get_layer3_pkt()?;
|
||||||
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
|
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()? else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
|
||||||
let Ok(data) = conninfo.try_decrypt_and_verify(udp_pkt.get_data()) else {
|
let Ok(data) = conninfo.try_decrypt_and_verify(udp_pkt.get_data()) else {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
@ -246,7 +250,9 @@ where
|
|||||||
let pkt = msg.pkt();
|
let pkt = msg.pkt();
|
||||||
|
|
||||||
let Layer3Pkt::IPv4Pkt(ip_pkt) = pkt.get_layer3_pkt()?;
|
let Layer3Pkt::IPv4Pkt(ip_pkt) = pkt.get_layer3_pkt()?;
|
||||||
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
|
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()? else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
|
||||||
if ip_pkt.source_ip() != conninfo.srcip || udp_pkt.srcport() != conninfo.srcport {
|
if ip_pkt.source_ip() != conninfo.srcip || udp_pkt.srcport() != conninfo.srcport {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@ -111,7 +111,9 @@ impl InterfaceSender {
|
|||||||
Self::Udp(interf) => {
|
Self::Udp(interf) => {
|
||||||
use packets::*;
|
use packets::*;
|
||||||
let Layer3Pkt::IPv4Pkt(ip_pkt) = packet.get_layer3_pkt()?;
|
let Layer3Pkt::IPv4Pkt(ip_pkt) = packet.get_layer3_pkt()?;
|
||||||
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
|
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()? else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
|
||||||
let addr = SocketAddrV4::new(ip_pkt.dest_ip(), udp_pkt.dstport());
|
let addr = SocketAddrV4::new(ip_pkt.dest_ip(), udp_pkt.dstport());
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,9 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let (kill_connection, kill_connection_recv) = channel::<(Ipv4Addr, u16)>();
|
let (kill_connection, kill_connection_recv) = channel::<(Ipv4Addr, u16)>();
|
||||||
|
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
let Ok(packet) = recv_eth_packet.recv() else { continue };
|
let Ok(packet) = recv_eth_packet.recv() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
if let Err(_) = interface_sender.sendpacket(packet.pkt()) {}
|
if let Err(_) = interface_sender.sendpacket(packet.pkt()) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -57,7 +59,9 @@ fn main() -> anyhow::Result<()> {
|
|||||||
s.spawn({
|
s.spawn({
|
||||||
let connections = &connections;
|
let connections = &connections;
|
||||||
move || loop {
|
move || loop {
|
||||||
let Ok(connection) = kill_connection_recv.recv() else { continue };
|
let Ok(connection) = kill_connection_recv.recv() else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
if let Ok(mut e) = connections.lock() {
|
if let Ok(mut e) = connections.lock() {
|
||||||
e.remove(&connection);
|
e.remove(&connection);
|
||||||
}
|
}
|
||||||
@ -71,7 +75,9 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let pkt = pkt.pkt();
|
let pkt = pkt.pkt();
|
||||||
|
|
||||||
let Layer3Pkt::IPv4Pkt(ip_pkt) = pkt.get_layer3_pkt()?;
|
let Layer3Pkt::IPv4Pkt(ip_pkt) = pkt.get_layer3_pkt()?;
|
||||||
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()?;
|
let Layer4Pkt::UDP(udp_pkt) = ip_pkt.get_layer4_packet()? else {
|
||||||
|
todo!()
|
||||||
|
};
|
||||||
|
|
||||||
let connection_handle = &(ip_pkt.dest_ip(), udp_pkt.srcport());
|
let connection_handle = &(ip_pkt.dest_ip(), udp_pkt.srcport());
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pcap-sys = { path = "../../pcap-sys" }
|
pcap-sys = { path = "../../pcap-sys" }
|
||||||
|
packets = { path = "../../packets" }
|
||||||
nl-sys = { path = "../../nl-sys" }
|
nl-sys = { path = "../../nl-sys" }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
tokio = { version = "1.32.0", features = ["full"] }
|
tokio = { version = "1.32.0", features = ["full"] }
|
||||||
|
|||||||
@ -3,6 +3,11 @@ use std::net::Ipv4Addr;
|
|||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
|
|
||||||
use nl_sys::{netlink, route};
|
use nl_sys::{netlink, route};
|
||||||
|
use packets::EthernetPacket;
|
||||||
|
|
||||||
|
struct TcpConnection {
|
||||||
|
packets_to_ack: Vec<EthernetPacket>,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
@ -27,7 +32,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
(ifname, srcip, srcmac, dstmac)
|
(ifname, srcip, srcmac, dstmac)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut interface = pcap_sys::new_aggregate_interface(false)?;
|
let mut interface = pcap_sys::Interface::<pcap_sys::DevDisabled>::new(&ifname)?;
|
||||||
|
|
||||||
interface.set_buffer_size(8192)?;
|
interface.set_buffer_size(8192)?;
|
||||||
interface.set_non_blocking(true)?;
|
interface.set_non_blocking(true)?;
|
||||||
@ -36,9 +41,14 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let mut interface = interface.activate()?;
|
let mut interface = interface.activate()?;
|
||||||
|
|
||||||
interface.set_filter("inbound and tcp port 54249", true, None)?;
|
let port: u16 = loop {
|
||||||
|
let port = rand::random();
|
||||||
|
if port > 30_000 {
|
||||||
|
break port;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
interface.prune(|_, interface| interface.datalink() != pcap_sys::consts::DLT_EN10MB);
|
interface.set_filter(&format!("inbound and tcp port {}", port), true, None)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user