feat: starting the TCP client proof of concept
This commit is contained in:
parent
0ef459bcfe
commit
25948a17f4
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -1296,10 +1296,12 @@ dependencies = [
|
||||
name = "tcp-test"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"nl-sys",
|
||||
"pcap-sys",
|
||||
"rand 0.8.5",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1412,6 +1414,20 @@ dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -34,6 +34,13 @@ script = [
|
||||
"docker-compose run --entrypoint=setcap build cap_net_raw=eip /workspaces/sparse/target/debug/tcp-test"
|
||||
]
|
||||
|
||||
[tasks.run-tcp-test]
|
||||
workspace = false
|
||||
dependencies = ["tcp-test"]
|
||||
script = [
|
||||
"docker-compose run tcptest_client /workspaces/sparse/target/debug/tcp-test $(/sbin/ip a show docker0 | awk -F'[ \t/]*' '/inet / { print $3 }')"
|
||||
]
|
||||
|
||||
[tasks.fmt]
|
||||
command = "cargo"
|
||||
args = ["fmt"]
|
||||
|
||||
@ -44,3 +44,9 @@ services:
|
||||
expose:
|
||||
- "54248/udp"
|
||||
command: /workspaces/sparse/target/debug/ex-revshell-server
|
||||
|
||||
tcptest_client:
|
||||
image: alpine
|
||||
volumes:
|
||||
- ./target:/workspaces/sparse/target
|
||||
command: /workspaces/sparse/target/debug/tcp-target
|
||||
|
||||
@ -146,7 +146,13 @@ impl<'a> IPv4Pkt<'a> {
|
||||
|
||||
pub fn get_layer4_packet(&self) -> error::Result<Layer4Pkt<'a>> {
|
||||
match self.protocol() {
|
||||
17 => Ok(Layer4Pkt::UDP(UDPPkt {
|
||||
// ICMP
|
||||
0x1 => Err(error::Error::UnknownPacketType(0x1)),
|
||||
// TCP
|
||||
0x6 => Ok(Layer4Pkt::TCP(TCPPkt {
|
||||
data: &self.data[(self.header_len() as usize)..],
|
||||
})),
|
||||
0x11 => Ok(Layer4Pkt::UDP(UDPPkt {
|
||||
data: &self.data[(self.header_len() as usize)..],
|
||||
})),
|
||||
p => Err(error::Error::UnknownPacketType(p.into())),
|
||||
@ -156,12 +162,14 @@ impl<'a> IPv4Pkt<'a> {
|
||||
|
||||
pub enum Layer4Pkt<'a> {
|
||||
UDP(UDPPkt<'a>),
|
||||
TCP(TCPPkt<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Layer4Pkt<'a> {
|
||||
pub fn len(&self) -> u16 {
|
||||
match self {
|
||||
Layer4Pkt::UDP(pkt) => pkt.len(),
|
||||
Layer4Pkt::TCP(_) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,6 +210,88 @@ impl<'a> UDPPkt<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TCPPkt<'a> {
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> TCPPkt<'a> {
|
||||
pub fn len(&self) -> u8 {
|
||||
(self.data[12] >> 4) * 4
|
||||
}
|
||||
|
||||
pub fn srcport(&self) -> u16 {
|
||||
u16::from_be_bytes(self.data[0..2].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn dstport(&self) -> u16 {
|
||||
u16::from_be_bytes(self.data[2..4].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn seqnumber(&self) -> u32 {
|
||||
u32::from_be_bytes(self.data[4..8].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn acknumber(&self) -> u32 {
|
||||
u32::from_be_bytes(self.data[8..12].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> u8 {
|
||||
self.data[13]
|
||||
}
|
||||
|
||||
pub fn cwr(&self) -> bool {
|
||||
self.flags() & 0x80 != 0
|
||||
}
|
||||
|
||||
pub fn ece(&self) -> bool {
|
||||
self.flags() & 0x40 != 0
|
||||
}
|
||||
|
||||
pub fn urg(&self) -> bool {
|
||||
self.flags() & 0x20 != 0
|
||||
}
|
||||
|
||||
pub fn ack(&self) -> bool {
|
||||
self.flags() & 0x10 != 0
|
||||
}
|
||||
|
||||
pub fn psh(&self) -> bool {
|
||||
self.flags() & 0x08 != 0
|
||||
}
|
||||
|
||||
pub fn rst(&self) -> bool {
|
||||
self.flags() & 0x04 != 0
|
||||
}
|
||||
|
||||
pub fn syn(&self) -> bool {
|
||||
self.flags() & 0x02 != 0
|
||||
}
|
||||
|
||||
pub fn fin(&self) -> bool {
|
||||
self.flags() & 0x01 != 0
|
||||
}
|
||||
|
||||
pub fn window(&self) -> u16 {
|
||||
u16::from_be_bytes(self.data[14..16].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn checksum(&self) -> u16 {
|
||||
u16::from_be_bytes(self.data[16..18].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn urgent_ptr(&self) -> u16 {
|
||||
u16::from_be_bytes(self.data[18..20].try_into().unwrap())
|
||||
}
|
||||
|
||||
pub fn options(&self) -> &[u8] {
|
||||
&self.data[20..(self.len() as usize)]
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data[(self.len() as usize)..]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EthernetPacket {
|
||||
data: Vec<u8>,
|
||||
@ -252,7 +342,8 @@ impl IPv4Packet {
|
||||
|
||||
let ttl: u8 = 64;
|
||||
let protocol: u8 = match packet {
|
||||
Layer4Packet::UDP(_) => 17,
|
||||
Layer4Packet::UDP(_) => 0x11,
|
||||
Layer4Packet::TCP(_) => 0x6,
|
||||
};
|
||||
|
||||
let source_upper = u16::from_be_bytes(source.octets()[0..2].try_into().unwrap());
|
||||
@ -290,6 +381,7 @@ impl IPv4Packet {
|
||||
&dest.octets(),
|
||||
match packet {
|
||||
Layer4Packet::UDP(pkt) => &*pkt.data,
|
||||
Layer4Packet::TCP(pkt) => &*pkt.data,
|
||||
},
|
||||
]
|
||||
.concat();
|
||||
@ -306,12 +398,14 @@ impl IPv4Packet {
|
||||
#[derive(Clone)]
|
||||
pub enum Layer4Packet {
|
||||
UDP(UDPPacket),
|
||||
TCP(TCPPacket),
|
||||
}
|
||||
|
||||
impl Layer4Packet {
|
||||
pub fn pkt(&'_ self) -> Layer4Pkt<'_> {
|
||||
match self {
|
||||
Layer4Packet::UDP(pkt) => Layer4Pkt::UDP(pkt.pkt()),
|
||||
Layer4Packet::TCP(pkt) => Layer4Pkt::TCP(pkt.pkt()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -345,3 +439,98 @@ impl UDPPacket {
|
||||
UDPPkt { data: &self.data }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TCPPacket {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl TCPPacket {
|
||||
#[inline]
|
||||
pub fn pkt(&'_ self) -> TCPPkt<'_> {
|
||||
TCPPkt { data: &self.data }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TCPPacketBuilder {
|
||||
srcport: u16,
|
||||
dstport: u16,
|
||||
seqnumber: u32,
|
||||
acknumber: u32,
|
||||
flags: u8,
|
||||
window: u16,
|
||||
urgent_ptr: u16,
|
||||
options: Vec<u8>,
|
||||
}
|
||||
|
||||
macro_rules! declare_flag {
|
||||
($name:ident, $offset:expr) => {
|
||||
pub fn $name(mut self, enable: bool) -> Self {
|
||||
if enable {
|
||||
self.flags |= $offset
|
||||
} else {
|
||||
self.flags &= (0xFF ^ $offset)
|
||||
}
|
||||
self
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl TCPPacketBuilder {
|
||||
pub fn srcport(mut self, port: u16) -> Self {
|
||||
self.srcport = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn dstport(mut self, port: u16) -> Self {
|
||||
self.dstport = port;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn seqnumber(mut self, num: u32) -> Self {
|
||||
self.seqnumber = num;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn acknumber(mut self, num: u32) -> Self {
|
||||
self.acknumber = num;
|
||||
self
|
||||
}
|
||||
|
||||
declare_flag!(cwr, 0x80);
|
||||
declare_flag!(ece, 0x40);
|
||||
declare_flag!(urg, 0x20);
|
||||
declare_flag!(ack, 0x10);
|
||||
declare_flag!(psh, 0x08);
|
||||
declare_flag!(rst, 0x04);
|
||||
declare_flag!(syn, 0x02);
|
||||
declare_flag!(fin, 0x01);
|
||||
|
||||
pub fn window(mut self, window: u16) -> Self {
|
||||
self.window = window;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn urgent_ptr(mut self, ptr: u16) -> Self {
|
||||
self.urgent_ptr = ptr;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn options(mut self, opts: Vec<u8>) -> Self {
|
||||
self.options = opts;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build<I1, I2>(self, srcip: I1, dstip: I2, data: Vec<u8>) -> TCPPacket
|
||||
where
|
||||
I1: Into<Ipv4Addr>,
|
||||
I2: Into<Ipv4Addr>,
|
||||
{
|
||||
let source = srcip.into();
|
||||
let dest = dstip.into();
|
||||
|
||||
let protocol = &[0x00u8, 0x06u8];
|
||||
|
||||
let tcp_length = data.len() + self.options.len() + 32;
|
||||
}
|
||||
}
|
||||
|
||||
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
@ -0,0 +1 @@
|
||||
edition = "2021"
|
||||
@ -10,3 +10,5 @@ pcap-sys = { path = "../../pcap-sys" }
|
||||
nl-sys = { path = "../../nl-sys" }
|
||||
rand = "0.8.5"
|
||||
tokio = { version = "1.32.0", features = ["full"] }
|
||||
anyhow = "1.0.75"
|
||||
tokio-stream = { version = "0.1.14", features = ["full"] }
|
||||
|
||||
@ -1,4 +1,44 @@
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use anyhow::anyhow;
|
||||
|
||||
use nl_sys::{netlink, route};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("Hello, world!");
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let ip = std::env::args()
|
||||
.skip(1)
|
||||
.next()
|
||||
.ok_or(anyhow!("could not get target IP"))?
|
||||
.parse::<Ipv4Addr>()?;
|
||||
|
||||
let (ifname, src_mac, dst_mac, srcip) = {
|
||||
let socket = netlink::Socket::new()?;
|
||||
|
||||
let routes = socket.get_routes()?;
|
||||
let neighs = socket.get_neigh()?;
|
||||
let links = socket.get_links()?;
|
||||
let addrs = socket.get_addrs()?;
|
||||
|
||||
let (ifname, srcip, srcmac, dstmac) =
|
||||
route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, ip)
|
||||
.ok_or(anyhow!("unable to find a route to the IP"))?;
|
||||
|
||||
(ifname, srcip, srcmac, dstmac)
|
||||
};
|
||||
|
||||
let mut interface = pcap_sys::new_aggregate_interface(false)?;
|
||||
|
||||
interface.set_buffer_size(8192)?;
|
||||
interface.set_non_blocking(true)?;
|
||||
interface.set_promisc(false)?;
|
||||
interface.set_timeout(10)?;
|
||||
|
||||
let mut interface = interface.activate()?;
|
||||
|
||||
interface.set_filter("inbound and tcp port 54249", true, None)?;
|
||||
|
||||
interface.prune(|_, interface| interface.datalink() != pcap_sys::consts::DLT_EN10MB);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -7,7 +7,9 @@ server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.bind(("0.0.0.0", 54248))
|
||||
server.listen(32)
|
||||
|
||||
client, addr = server.accept()
|
||||
with client:
|
||||
while True:
|
||||
client, addr = server.accept()
|
||||
print('Got connection')
|
||||
with client:
|
||||
print(client.recv(24))
|
||||
client.sendall(b"pong")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user