From 0bb287156848fe37d74109a8e8e853885bd18fe9 Mon Sep 17 00:00:00 2001 From: Andrew Rioux Date: Tue, 26 Sep 2023 01:57:10 -0400 Subject: [PATCH] feat: added the ability to respond to ARP requests --- examples/bind-shell/client/src/main.rs | 43 +++++--- examples/reverse-shell/server/src/main.rs | 8 +- packets/src/lib.rs | 125 +++++++++++++++++++++- tcp-test/client/src/main.rs | 88 ++++++++++----- 4 files changed, 219 insertions(+), 45 deletions(-) diff --git a/examples/bind-shell/client/src/main.rs b/examples/bind-shell/client/src/main.rs index ca52c98..ee85c13 100644 --- a/examples/bind-shell/client/src/main.rs +++ b/examples/bind-shell/client/src/main.rs @@ -1,4 +1,9 @@ -use std::{io::prelude::*, net::UdpSocket, thread, sync::{Arc, Mutex, Condvar}}; +use std::{ + io::prelude::*, + net::UdpSocket, + sync::{Arc, Condvar, Mutex}, + thread, +}; use anyhow::{anyhow, Context}; use ed25519_dalek::{Keypair, Signer}; @@ -17,7 +22,7 @@ impl Msg<'_> { 0 => Some(Msg::Ready(bytes[1])), 1 => Some(Msg::Stdout(&bytes[1..])), 2 => Some(Msg::Stderr(&bytes[1..])), - _ => None + _ => None, } } } @@ -47,8 +52,12 @@ fn main() -> anyhow::Result<()> { let mut buffer = [0u8; 1536]; loop { - let Ok(amount) = remote_listen.recv(&mut buffer[..]) else { continue; }; - let Some(msg) = Msg::parse(&buffer[..amount]) else { continue; }; + let Ok(amount) = remote_listen.recv(&mut buffer[..]) else { + continue; + }; + let Some(msg) = Msg::parse(&buffer[..amount]) else { + continue; + }; match msg { Msg::Ready(_) => { @@ -59,12 +68,14 @@ fn main() -> anyhow::Result<()> { }; *inuse = false; cvar.notify_one(); - }, + } Msg::Stderr(err) => { let _ = stderr.write(err); - }, + } Msg::Stdout(out) => { - let Ok(mut stdout) = stdout_arc.lock() else { continue; }; + let Ok(mut stdout) = stdout_arc.lock() else { + continue; + }; let _ = stdout.write(out); } } @@ -92,13 +103,19 @@ fn main() -> anyhow::Result<()> { } { - let Ok(mut stdout) = stdout_arc.lock() else { continue; }; - let Ok(_) = write!(&*stdout, "root@{}:{} # ", &target, &cwd) else { continue; }; + let Ok(mut stdout) = stdout_arc.lock() else { + continue; + }; + let Ok(_) = write!(&*stdout, "root@{}:{} # ", &target, &cwd) else { + continue; + }; let _ = stdout.flush(); } let mut cmd = String::new(); - let Ok(amount) = stdin.read_line(&mut cmd) else { continue; }; + let Ok(amount) = stdin.read_line(&mut cmd) else { + continue; + }; let mut cmd = cmd.trim(); if amount == 0 { @@ -113,8 +130,10 @@ fn main() -> anyhow::Result<()> { }; match cmd.split(" ").collect::>()[..] { - ["exit"] => { break }, - ["cd", dir] => { cwd = dir.to_owned(); }, + ["exit"] => break, + ["cd", dir] => { + cwd = dir.to_owned(); + } _ => { let (lock, _) = &*stdout_inuse; let Ok(mut inuse) = lock.lock() else { diff --git a/examples/reverse-shell/server/src/main.rs b/examples/reverse-shell/server/src/main.rs index 3fbd3de..86a2933 100644 --- a/examples/reverse-shell/server/src/main.rs +++ b/examples/reverse-shell/server/src/main.rs @@ -6,7 +6,9 @@ fn main() -> anyhow::Result<()> { loop { let mut buf = [0u8; 4]; - let Ok((amount, src)) = input.recv_from(&mut buf[..]) else { continue; }; + let Ok((amount, src)) = input.recv_from(&mut buf[..]) else { + continue; + }; if amount != 4 { continue; @@ -14,6 +16,8 @@ fn main() -> anyhow::Result<()> { println!("Received packet: {}", i32::from_be_bytes(buf)); - let Ok(_) = input.send_to(&buf, src) else { continue; }; + let Ok(_) = input.send_to(&buf, src) else { + continue; + }; } } diff --git a/packets/src/lib.rs b/packets/src/lib.rs index dac53ba..c6ba82a 100644 --- a/packets/src/lib.rs +++ b/packets/src/lib.rs @@ -58,6 +58,17 @@ impl<'a> EthernetPkt<'a> { Ok(Layer3Pkt::IPv4Pkt(pkt)) } + 0x0806 => { + if self.data.len() < 42 { + return Err(error::Error::PacketLengthInvalid); + } + + let pkt = ARPPkt { + data: &self.data[14..], + }; + + Ok(Layer3Pkt::ARP(pkt)) + } p => Err(error::Error::UnknownPacketType(p)), } } @@ -71,6 +82,7 @@ impl<'a> EthernetPkt<'a> { pub enum Layer3Pkt<'a> { IPv4Pkt(IPv4Pkt<'a>), + ARP(ARPPkt<'a>), } pub struct IPv4Pkt<'a> { @@ -160,6 +172,51 @@ impl<'a> IPv4Pkt<'a> { } } +pub struct ARPPkt<'a> { + data: &'a [u8], +} + +impl<'a> ARPPkt<'a> { + pub fn htype(&self) -> u16 { + u16::from_be_bytes(self.data[0..2].try_into().unwrap()) + } + + pub fn ptype(&self) -> u16 { + u16::from_be_bytes(self.data[2..4].try_into().unwrap()) + } + + pub fn hwlen(&self) -> u8 { + self.data[4] + } + + pub fn plen(&self) -> u8 { + self.data[5] + } + + pub fn opcode(&self) -> u16 { + u16::from_be_bytes(self.data[6..8].try_into().unwrap()) + } + + pub fn srchwaddr(&self) -> &[u8] { + &self.data[8usize..8usize + self.hwlen() as usize] + } + + pub fn srcprotoaddr(&self) -> &[u8] { + let start = self.hwlen() as usize + 8; + &self.data[start..start + self.plen() as usize] + } + + pub fn targethwaddr(&self) -> &[u8] { + let start = self.hwlen() as usize + self.plen() as usize + 8; + &self.data[start..start + self.hwlen() as usize] + } + + pub fn targetprotoaddr(&self) -> &[u8] { + let start = self.hwlen() as usize + self.plen() as usize + self.hwlen() as usize + 8; + &self.data[start..start + self.plen() as usize] + } +} + pub enum Layer4Pkt<'a> { UDP(UDPPkt<'a>), TCP(TCPPkt<'a>), @@ -169,7 +226,7 @@ impl<'a> Layer4Pkt<'a> { pub fn len(&self) -> u16 { match self { Layer4Pkt::UDP(pkt) => pkt.len(), - Layer4Pkt::TCP(_) => 0, + Layer4Pkt::TCP(pkt) => pkt.data.len() as u16, } } @@ -358,6 +415,9 @@ impl EthernetPacket { Layer3Packet::IPv4(pkt) => EthernetPacket { data: [&dst[..], &src[..], &[0x08_u8, 0x00_u8][..], &*pkt.data].concat(), }, + Layer3Packet::ARP(pkt) => EthernetPacket { + data: [&dst[..], &src[..], &[0x08_u8, 0x06_u8][..], &*pkt.data].concat(), + }, } } @@ -370,13 +430,74 @@ impl EthernetPacket { #[derive(Clone)] pub enum Layer3Packet { IPv4(IPv4Packet), + ARP(ARPPacket), +} + +#[derive(Clone)] +pub struct ARPPacket { + data: Vec, +} + +pub enum ARPMode { + Request, + Reply, +} + +impl ARPMode { + fn opcode(&self) -> u16 { + match self { + Self::Request => 1, + Self::Reply => 2, + } + } +} + +pub enum ARPProto { + IPv4, +} + +impl ARPProto { + fn opcode(&self) -> u16 { + match self { + Self::IPv4 => 0x0800, + } + } +} + +impl ARPPacket { + pub fn construct( + op: ARPMode, + proto: ARPProto, + srchwaddr: &[u8], + targethwaddr: &[u8], + srcprotoaddr: &[u8], + targetprotoaddr: &[u8], + ) -> ARPPacket { + assert!(srchwaddr.len() == targethwaddr.len()); + assert!(srcprotoaddr.len() == targetprotoaddr.len()); + + let data = [ + &0x0001u16.to_be_bytes()[..], + &proto.opcode().to_be_bytes()[..], + &[srchwaddr.len() as u8], + &[srcprotoaddr.len() as u8], + &op.opcode().to_be_bytes(), + srchwaddr, + srcprotoaddr, + targethwaddr, + targetprotoaddr, + ] + .concat(); + + ARPPacket { data } + } } static IPV4_ID: AtomicU16 = AtomicU16::new(0xabcd); #[derive(Clone)] pub struct IPv4Packet { - data: Vec, + pub data: Vec, } impl IPv4Packet { diff --git a/tcp-test/client/src/main.rs b/tcp-test/client/src/main.rs index 627fe03..bbb8c1a 100644 --- a/tcp-test/client/src/main.rs +++ b/tcp-test/client/src/main.rs @@ -10,8 +10,8 @@ use log::{debug, error, info, trace}; use nl_sys::{netlink, route}; use packets::{ - self, EthernetPacket, IPv4Packet, IPv4Pkt, Layer3Packet, Layer3Pkt, Layer4Packet, Layer4Pkt, - TCPPacket, TCPPacketBuilder, TCPPkt, + self, ARPMode, ARPPacket, ARPProto, EthernetPacket, IPv4Packet, IPv4Pkt, Layer3Packet, + Layer3Pkt, Layer4Packet, Layer4Pkt, TCPPacket, TCPPacketBuilder, TCPPkt, }; use pcap_sys; use tokio::{sync::mpsc, task}; @@ -71,7 +71,7 @@ impl TcpOptions { } } -fn socket_accepts_packet(socket: &TcpSocket, ip: IPv4Pkt<'_>, tcp: TCPPkt<'_>) -> bool { +fn socket_accepts_packet(socket: &TcpSocket, ip: &IPv4Pkt<'_>, tcp: &TCPPkt<'_>) -> bool { if let Some(peer) = &socket.peer_info { peer.local_addr == ip.dest_ip() && peer.remote_addr == ip.source_ip() @@ -110,7 +110,7 @@ fn connect( .syn(true) .window(64240) .seqnumber(socket.local_seq_no) - .options([TcpOptions::MaxSegmentSize(64240).get_bytes()].concat()) + //.options([TcpOptions::MaxSegmentSize(64240).get_bytes()].concat()) .build(local_addr, remote_addr, vec![], None); (local_port, packet) @@ -127,8 +127,11 @@ fn process_packet( Ok((None, None)) } -fn send_data(socket: &mut TcpSocket, data: Vec) -> anyhow::Result<(TCPPacketBuilder, Vec)> { - Ok(todo!()) +fn send_data( + socket: &mut TcpSocket, + data: Vec, +) -> anyhow::Result)>> { + Ok(None) } struct TcpSocketHandle { @@ -167,7 +170,7 @@ async fn main() -> anyhow::Result<()> { .ok_or(anyhow!("could not get target IP"))? .parse::()?; - let (routes, (ifname, ifindex, srcip, src_mac, dst_mac, src_snmask)) = { + let (ifname, _, srcip, src_mac, dst_mac, _) = { let socket = netlink::Socket::new()?; let routes = socket.get_routes()?; @@ -175,16 +178,21 @@ async fn main() -> anyhow::Result<()> { let links = socket.get_links()?; let addrs = socket.get_addrs()?; - let res = route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, ip) - .ok_or(anyhow!("unable to find a route to the IP"))?; - - (routes, res) + route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, ip) + .ok_or(anyhow!("unable to find a route to the IP"))? }; let mut socket = TcpSocket::default(); let mut interface = pcap_sys::Interface::::new(&ifname)?; + let srcip: u32 = srcip.into(); + let srcip = srcip + 10; + let srcip: Ipv4Addr = srcip.into(); + dbg!(srcip, src_mac, dst_mac); + + let dst_mac = [0x00, 0x16, 0x3e, 0xde, 0xa9, 0x93]; + interface.set_buffer_size(8192)?; interface.set_non_blocking(true)?; interface.set_promisc(false)?; @@ -194,18 +202,14 @@ async fn main() -> anyhow::Result<()> { macro_rules! format_packet { ($tcp_packet:expr) => {{ - let layer3pkt = Layer3Packet::IPv4(IPv4Packet::construct( - srcip, - ip, - &Layer4Packet::TCP($tcp_packet), - )); - EthernetPacket::construct(src_mac, dst_mac, &layer3pkt) + let ippkt = IPv4Packet::construct(srcip, ip, &Layer4Packet::TCP($tcp_packet)); + EthernetPacket::construct(src_mac, dst_mac, &Layer3Packet::IPv4(ippkt)) }}; } let (port, packet) = connect(&mut socket, ip, 54248, srcip); - interface.set_filter(&format!("inbound and tcp port {port}"), true, None)?; + interface.set_filter(&format!("arp or (inbound and tcp port {port})"), true, None)?; if interface.datalink() != pcap_sys::consts::DLT_EN10MB { bail!("interface does not support ethernet"); @@ -226,23 +230,50 @@ async fn main() -> anyhow::Result<()> { task::spawn(async move { use_socket(socket_handle) }); loop { - let Some((builder, data)) = tokio::select! { + let Some(packet) = tokio::select! { Some(Ok(bytes)) = packets.next() => { let pkt = bytes.pkt(); - let Ok(Layer3Pkt::IPv4Pkt(ip_pkt)) = pkt.get_layer3_pkt() else { continue; }; - let Ok(Layer4Pkt::TCP(tcp_pkt)) = ip_pkt.get_layer4_packet() else { continue; }; - let Ok((to_send, received)) = process_packet(&mut socket, tcp_pkt) else { continue; }; + match pkt.get_layer3_pkt() { + Ok(Layer3Pkt::IPv4Pkt(ip_pkt)) => { + let Ok(Layer4Pkt::TCP(tcp_pkt)) = ip_pkt.get_layer4_packet() else { continue; }; - if let Some(received) = received { - _ = receive_packet.send(received).await; + if !socket_accepts_packet(&socket, &ip_pkt, &tcp_pkt) { + continue; + } + + let Ok((to_send, received)) = process_packet(&mut socket, tcp_pkt) else { continue; }; + + if let Some(received) = received { + _ = receive_packet.send(received).await; + } + + to_send.map(|(b, d)| format_packet!(b.build(srcip, ip, d, None))) + }, + Ok(Layer3Pkt::ARP(arp)) => { + if arp.opcode() != 1 || arp.plen() != 4 || arp.hwlen() != 6 { + continue; + } + + let senderip: [u8; 4] = arp.srcprotoaddr().try_into().unwrap(); + let sendermac: &[u8] = arp.srchwaddr(); + let queryip: [u8; 4] = arp.targetprotoaddr().try_into().unwrap(); + let queryip: Ipv4Addr = queryip.into(); + + if queryip != srcip { + continue; + } + + let response = ARPPacket::construct(ARPMode::Reply, ARPProto::IPv4, &src_mac, &sendermac, &queryip.octets(), &senderip); + + Some(EthernetPacket::construct(src_mac, sendermac.try_into().unwrap(), &Layer3Packet::ARP(response))) + }, + _ => continue } - - to_send }, Some(to_send) = send_packet.recv() => { match send_data(&mut socket, to_send) { - Ok(v) => Some(v), + Ok(v) => v.map(|(b, d)| format_packet!(b.build(srcip, ip, d, None))), Err(_) => continue } }, @@ -251,7 +282,6 @@ async fn main() -> anyhow::Result<()> { continue; }; - let packet = builder.build(srcip, ip, data, None); - _ = packets.sendpacket(format_packet!(packet).pkt()); + _ = packets.sendpacket(packet.pkt()); } }