Курс — Хакинг на Rust. #19 Инструменты хакера на Rust. Сетевые атаки. Работа с сокетами: TCP/UDP, raw sockets
Здравствуйте, дорогие друзья.
Сокеты — основа сетевого взаимодействия. В Rust они реализуются через стандартную библиотеку (std::net
) и низкоуровневые крейты (socket2
, pnet
).
Преимущества Rust:
- Безопасность: Нет утечек памяти даже при работе с сырыми сокетами.
- Скорость: Нулевые накладные расходы для высоконагруженных задач.
- Контроль: Возможность манипуляции пакетами на уровне байтов.
TCP-сокеты: Надёжное соединение
TCP гарантирует доставку данных и порядок пакетов. Используется для HTTP, SSH, передачи файлов.
Пример TCP-сервера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
use std::net::{TcpListener, TcpStream}; use std::io::{Read, Write}; fn handle_client(mut stream: TcpStream) { let mut buffer = [0; 512]; stream.read(&mut buffer).unwrap(); stream.write(b"HTTP/1.1 200 OK\r\n\r\nHello from Rust!").unwrap(); } fn main() { let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); for stream in listener.incoming() { handle_client(stream.unwrap()); } } |
Пример TCP-клиента
1 2 3 4 5 6 7 8 9 10 |
use std::net::TcpStream; use std::io::{Read, Write}; fn main() { let mut stream = TcpStream::connect("127.0.0.1:7878").unwrap(); stream.write(b"GET / HTTP/1.1\r\n\r\n").unwrap(); let mut buffer = [0; 512]; stream.read(&mut buffer).unwrap(); println!("Ответ: {}", String::from_utf8_lossy(&buffer)); } |
UDP-сокеты: Быстрая доставка без гарантий
UDP используется для потокового видео, DNS, игр.
UDP-сервер
1 2 3 4 5 6 7 8 9 10 11 |
use std::net::{UdpSocket, SocketAddr}; fn main() { let socket = UdpSocket::bind("0.0.0.0:8080").unwrap(); let mut buffer = [0; 1024]; loop { let (size, addr) = socket.recv_from(&mut buffer).unwrap(); println!("Получено {} байт от {}", size, addr); socket.send_to(&buffer[..size], addr).unwrap(); } } |
UDP-клиент
1 2 3 4 5 6 7 8 9 |
use std::net::UdpSocket; fn main() { let socket = UdpSocket::bind("0.0.0.0:0").unwrap(); socket.send_to(b"Hello UDP", "127.0.0.1:8080").unwrap(); let mut buffer = [0; 1024]; let (size, _) = socket.recv_from(&mut buffer).unwrap(); println!("Ответ: {:?}", &buffer[..size]); } |
Raw Sockets: Низкоуровневая магия
Raw sockets позволяют отправлять и принимать сырые пакеты (IP, ICMP, TCP). Требуют прав суперпользователя.
Создание raw сокета
Для работы с сырыми сокетами используйте крейт socket2
:
1 2 |
[dependencies] socket2 = "0.4" |
Пример ICMP-пинга:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
use socket2::{Socket, Domain, Type, Protocol}; use std::net::{Ipv4Addr, SocketAddrV4}; fn main() { let socket = Socket::new( Domain::IPV4, Type::RAW, Some(Protocol::ICMPV4), ).unwrap(); socket.bind(&SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0).into()).unwrap(); // Создание ICMP-пакета (Echo Request) let icmp_packet = [ 0x08, 0x00, 0x7d, 0x4b, // Тип, код, checksum 0x00, 0x00, 0x00, 0x00, // Идентификатор, номер последовательности ]; socket.send_to( &icmp_packet, &SocketAddrV4::new(Ipv4Addr::new(8, 8, 8, 8), 0).into() ).unwrap(); } |
Генерация TCP SYN-пакетов (SYN-сканирование)
SYN-сканирование позволяет обнаружить открытые порты без установки полного соединения.
Пример с pnet
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
use pnet::packet::{ip::IpNextHeaderProtocols, tcp::TcpFlags}; use pnet::packet::ipv4::MutableIpv4Packet; use pnet::packet::tcp::MutableTcpPacket; use pnet::transport::{TransportChannelType, transport_channel}; use std::net::Ipv4Addr; fn send_syn(target: Ipv4Addr, port: u16) { let (mut sender, _) = transport_channel( 4096, TransportChannelType::Layer4( pnet::transport::TransportProtocol::Ipv4(IpNextHeaderProtocols::Tcp) ) ).unwrap(); let mut tcp_buffer = [0u8; 20]; let mut tcp_packet = MutableTcpPacket::new(&mut tcp_buffer).unwrap(); tcp_packet.set_source(44444); tcp_packet.set_destination(port); tcp_packet.set_flags(TcpFlags::SYN); tcp_packet.set_window(65535); let mut ip_buffer = [0u8; 20 + tcp_packet.packet().len()]; let mut ip_packet = MutableIpv4Packet::new(&mut ip_buffer).unwrap(); ip_packet.set_next_level_protocol(IpNextHeaderProtocols::Tcp); ip_packet.set_source(Ipv4Addr::new(192, 168, 1, 100)); ip_packet.set_destination(target); ip_packet.set_payload(tcp_packet.packet()); sender.send_to(ip_packet, target.into()).unwrap(); } |
Обработка ошибок и безопасность
- Проверка прав: Raw sockets требуют
sudo
или CAP_NET_RAW. - Обработка ошибок: Используйте
?
для пропагации ошибок
1 |
let socket = Socket::new(...).map_err(|e| format!("Ошибка: {}", e))?; |
- Безопасное использование
unsafe
: Инкапсулируйте опасные операции.
Инструменты и библиотеки
socket2
: Гибкая настройка сокетов (таймауты, буферы).pnet
: Работа с низкоуровневыми протоколами.tokio/net
: Асинхронные сокеты для высоконагруженных приложений.
Этические аспекты
- Только в рамках закона: Raw sockets могут использоваться для DDoS-атак (например, SYN-flood).
- Защита: Анализируйте свой трафик снифферами для обнаружения аномалий.
Задание для самостоятельной работы:
- Реализуйте UDP-флудер с ограничением скорости.
- Модифицируйте пример SYN-сканера для обработки ответов (SYN-ACK).
- Напишите сниффер ICMP-пакетов с использованием
pnet
.
Итог:
Rust сочетает контроль над сетевым стеком с безопасностью, что делает его идеальным выбором для создания инструментов сетевого взаимодействия. Понимание сокетов — основа для MITM-атак, фаззинга и анализа уязвимостей.

На этом все. Всем хорошего дня!