Statically generated payloads (#643)

* update the master branch to use nmap-payloads file

* code generation

* statically generate payloads, workingish

* actually puts the map in memory at compile time

* I am not sure this needs to be in the repo since its built on compilation

* actually ignores

* converting this in networking class counts as paying attention to the lecture right?

* see if if works on windows

* see

* I think i fixed CI

* fixes clippy

* ugh

* formats the gen code automagically

* UDP Service Probing

* UDP Service Probing

* Better comments

* fixes clippy

* fixes cargo fmt
This commit is contained in:
BrendanGlancy authored and GitHub committed 2024-09-13 17:49:30 +01:00
1 parent a6f04c5c4a
commit 45fa80acd4
11 files changed
+3771 -297

No files matched your search

+1 -1
View File
@@ -69,7 +69,7 @@ jobs:
run: |
git config --global pack.windowMemory "100m"
git config --global pack.packSizeLimit "100m"
git config --global pack.threads "1"
git config --global pack.threads "1"
git config --global pack.deltaCacheSize "512m"
- name: Install dependencies
+1 -1
View File
@@ -121,4 +121,4 @@ fabric.properties
.idea
.idea*
settings.json
settings.json
Generated
+1
View File
@@ -1443,6 +1443,7 @@ dependencies = [
"hickory-resolver",
"itertools",
"log",
"once_cell",
"parameterized",
"rand",
"rlimit",
+1
View File
@@ -39,6 +39,7 @@ hickory-resolver = { version = "0.24.0", features = ["dns-over-rustls"] }
anyhow = "1.0.40"
subprocess = "0.2.6"
text_placeholder = { version = "0.5", features = ["struct_context"] }
once_cell = "1.19.0"
[dev-dependencies]
parameterized = "2.0.0"
+234
View File
@@ -0,0 +1,234 @@
use std::collections::BTreeMap;
use std::fs::{self, File};
use std::env;
use std::io::{BufReader, Read};
use std::path::PathBuf;
use std::process::Command;
// Reads in a file with payloads based on port
pub fn main() {
let mut file_path = env::current_dir().expect("cant find curr dir");
file_path.push("./nmap-payloads");
let mut data = String::new();
let file = File::open(&file_path).expect("File not found.");
let mut file_buf = BufReader::new(file);
file_buf
.read_to_string(&mut data)
.expect("unable to read file");
let mut fp_map: BTreeMap<i32, String> = BTreeMap::new();
let mut count = 0;
let mut capturing = false;
let mut curr = String::new();
for line in data.trim().split('\n') {
if line.contains('#') || line.is_empty() {
continue;
}
if line.starts_with("udp") {
if !curr.is_empty() {
fp_map.insert(count, curr);
curr = String::new();
}
capturing = true;
count += 1;
}
if capturing {
if !curr.is_empty() {
curr.push(' ');
}
curr.push_str(line);
}
}
let pb_linenr = ports_v(&fp_map);
let payb_linenr = payloads_v(&fp_map);
let map = port_payload_map(pb_linenr, payb_linenr);
generate_code(map);
}
/// Generates a file called Generated.rs and calls cargo fmt from the command line
///
/// # Arguments
///
/// * `port_payload_map` - A BTreeMap mapping port numbers to payload data
fn generate_code(port_payload_map: BTreeMap<Vec<u16>, Vec<u8>>) {
let dest_path = PathBuf::from("src/generated.rs");
let mut generated_code = String::new();
generated_code.push_str("use std::collections::BTreeMap;\n");
generated_code.push_str("use once_cell::sync::Lazy;\n\n");
generated_code.push_str("fn generated_data() -> BTreeMap<Vec<u16>, Vec<u8>> {\n");
generated_code.push_str(" let mut map = BTreeMap::new();\n");
for (ports, payloads) in port_payload_map {
generated_code.push_str(" map.insert(vec![");
generated_code.push_str(
&ports
.iter()
.map(|&p| p.to_string())
.collect::<Vec<_>>()
.join(","),
);
generated_code.push_str("], vec![");
generated_code.push_str(
&payloads
.iter()
.map(|&p| p.to_string())
.collect::<Vec<_>>()
.join(","),
);
generated_code.push_str("]);\n");
}
generated_code.push_str(" map\n");
generated_code.push_str("}\n\n");
generated_code.push_str(
"static PARSED_DATA: Lazy<BTreeMap<Vec<u16>, Vec<u8>>> = Lazy::new(generated_data);\n",
);
generated_code.push_str("pub fn get_parsed_data() -> &'static BTreeMap<Vec<u16>, Vec<u8>> {\n");
generated_code.push_str(" &PARSED_DATA\n");
generated_code.push_str("}\n");
fs::write(dest_path, generated_code).unwrap();
// format the generated code
Command::new("cargo")
.arg("fmt")
.arg("--all")
.output()
.expect("Failed to execute cargo fmt");
}
/// Creates a BTreeMap of line numbers mapped to a Vec<u16> of ports
///
/// # Arguments
///
/// * `fp_map` - A BTreeMap containing the parsed file data
///
/// # Returns
///
/// A BTreeMap where keys are line numbers and values are vectors of ports
fn ports_v(fp_map: &BTreeMap<i32, String>) -> BTreeMap<i32, Vec<u16>> {
let mut pb_linenr: BTreeMap<i32, Vec<u16>> = BTreeMap::new();
let mut port_list: Vec<u16> = Vec::new();
for (&line_nr, ports) in fp_map {
if ports.contains("udp ") {
let remain = &ports[4..];
let mut start = remain.split(' ');
let ports = start.next().unwrap();
let port_segments: Vec<&str> = ports.split(',').collect();
for segment in port_segments {
if segment.contains('-') {
let range: Vec<&str> = segment.trim().split('-').collect();
let start = range[0].parse::<u16>().unwrap();
let end = range[1].parse::<u16>().unwrap();
for port in start..end {
port_list.push(port);
}
} else if !segment.is_empty() {
match segment.parse::<u16>() {
Ok(port) => port_list.push(port),
Err(_) => println!("Error parsing port: {}", segment),
}
}
}
}
pb_linenr.insert(line_nr, port_list.clone());
port_list.clear();
}
pb_linenr
}
/// Parses out the Payloads into a BTreeMap of line numbers mapped to vectors of payload bytes
///
/// # Arguments
///
/// * `fp_map` - A BTreeMap containing the parsed file data
///
/// # Returns
///
/// A BTreeMap where keys are line numbers and values are vectors of payload bytes
fn payloads_v(fp_map: &BTreeMap<i32, String>) -> BTreeMap<i32, Vec<u8>> {
let mut payb_linenr: BTreeMap<i32, Vec<u8>> = BTreeMap::new();
for (&line_nr, data) in fp_map {
if data.contains('\"') {
let start = data.find('\"').expect("payload opening \" not found");
let payloads = &data[start + 1..];
payb_linenr.insert(line_nr, parser(payloads.trim()));
}
}
payb_linenr
}
/// Converts a hexadecimal string to a Vec<u8>
///
/// # Arguments
///
/// * `payload` - A string slice containing the hexadecimal payload
///
/// # Returns
///
/// A vector of bytes representing the decoded payload
fn parser(payload: &str) -> Vec<u8> {
let payload = payload.trim_matches('"');
let mut tmp_str = String::new();
let mut bytes: Vec<u8> = Vec::new();
for (idx, char) in payload.chars().enumerate() {
if char == '\\' && payload.chars().nth(idx + 1) == Some('x') {
continue;
} else if char.is_ascii_digit() {
tmp_str.push(char);
if tmp_str.len() == 2 {
bytes.push(u8::from_str_radix(&tmp_str, 16).unwrap());
tmp_str.clear();
}
}
}
bytes
}
/// Combines the ports BTreeMap and the Payloads BTreeMap
///
/// # Arguments
///
/// * `pb_linenr` - A BTreeMap mapping line numbers to vectors of ports
/// * `payb_linenr` - A BTreeMap mapping line numbers to vectors of payload bytes
///
/// # Returns
///
/// A BTreeMap mapping vectors of ports to vectors of payload bytes
fn port_payload_map(
pb_linenr: BTreeMap<i32, Vec<u16>>,
payb_linenr: BTreeMap<i32, Vec<u8>>,
) -> BTreeMap<Vec<u16>, Vec<u8>> {
let mut ppm_fin: BTreeMap<Vec<u16>, Vec<u8>> = BTreeMap::new();
for (port_linenr, ports) in pb_linenr {
for (pay_linenr, payloads) in &payb_linenr {
if pay_linenr == &port_linenr {
ppm_fin.insert(ports.to_vec(), payloads.to_vec());
}
}
}
ppm_fin
}
+500
View File
@@ -0,0 +1,500 @@
# Nmap nmap payload database -*- mode: fundamental; -*-
# $Id$
#
# These payloads are sent with every host discovery or port scan probe
# by default. This database should only include payloads that are
# unlikely to crash services, trip IDS alerts, or change state on the
# server. The idea behind these is to evoke a response using a payload.
# Some of them are taken from nmap-service-probes.
#
# This collection of data is (C) 1996-2022 by Nmap Software LLC. It
# is distributed under the Nmap Public Source license as provided in
# the LICENSE file of the source distribution or at
# https://nmap.org/npsl/. Note that this free license does not allow
# incorporation of Nmap or its data files within proprietary
# software. We sell a separate Nmap OEM for that as described
# (including pricing) at https://nmap.org/npsl/.
#
# Each entry begins with a protocol (only "udp" is supported) followed
# by a comma-separated list of ports, followed by one or more quoted
# strings containing the payload. These elements may be broken across
# several lines. For future expansion, additional keywords may follow
# the payload data. Any data following one of these keywords must be on
# the same line as the keyword so that unknown keywords can be ignored
# by the parser. Currently this file contains some entries with the
# "source" keyword to specify a desired source port, but it is not
# honored by Nmap.
#
# Multiple payloads may be defined for a single protocol and port, in
# which case they will be all be sent concurrently. There is a limit
# of 255 payloads per port.
#
# Lines longer than 1024 characters will be ignored.
#
# Example:
# udp 1234 "payloaddatapayloaddata"
# "payloaddatapayloaddata"
# source 5678
# GenericLines. Use for the echo service.
udp 7 "\x0D\x0A\x0D\x0A"
# DNSStatusRequest
# Sent for TFTP (69) as well due to its ability to provoke an error response
udp 53,69,5353,26198 "\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# DNS VER
udp 53,5353,26198
"\x77\x77\x01\x00\x00"
"\x01\x00\x00\x00\x00\x00\x00\x07version\x04bind\x00\x00\x10\x00\x03"
# DHCP INFORM
udp 67
"\x01\x01\x06\x00"
"\x01\x23\x45\x67\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x35\xd4\xd8\x51\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x63\x82\x53\x63\x35\x01"
"\x08\xff"
# TFTP GET
udp 69 "\x00\x01r7tftp.txt\x00octet\x00"
# QUIC packet with unsupported version Q999
# Also found on 443, but need to check whether DTLS or QUIC is more prevalent
udp 80 "\r12345678Q999\x00"
# RPCCheck
udp 111
"\x72\xFE\x1D\x13\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x86\xA0"
"\x00\x01\x97\x7C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00"
# ONCRPC CALL
udp 111,2049,4045,32768-65535
"\x3e\xec\xe3\xca\x00\x00\x00\x00\x00\x00\x00\x02\x00"
"\xbc\x61\x4e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# NTPRequest
udp 123
"\xE3\x00\x04\xFA\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\xC5\x4F\x23\x4B\x71\xB1\x52\xF3"
# NTP REQ
udp 123
"\xd9\x00\x0a\xfa\x00\x00\x00"
"\x00\x00\x01\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6"
"\xf1\x5e\xdb\x78\x00\x00\x00"
# DCERPC CALL
udp 135,1025-1199
"\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00"
"\x00\x00\x01\x00\x00\x00\xb8\x10\xb8\x10\x00\x00\x00\x00\x01\x00\x00"
"\x00\x00\x00\x01\x00\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x23\x45\x67"
"\x89\xab\xcd\xef\xe7\x03\x00\x00\xfe\xdc\xba\x98\x76\x54\x32\x10\x01"
"\x23\x45\x67\x89\xab\xcd\xef\xe7\x03\x00\x00"
# NBTStat
udp 137
"\x80\xF0\x00\x10\x00\x01\x00\x00\x00\x00\x00\x00"
"\x20CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x21\x00\x01"
# CIFS NS NAME QUERY UC
udp 137
"\x01\x91\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"
"\x20CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x21\x00\x01"
# CIFS NS NAME QUERY BC
udp 137
"\x01\x91\x00\x10\x00\x01\x00\x00\x00\x00\x00\x00"
"\x20CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x00\x00\x21\x00\x01"
# SNMPv3GetRequest
udp 161,260,3401
"\x30\x3A\x02\x01\x03\x30\x0F\x02\x02\x4A\x69\x02\x03\x00\xFF\xE3"
"\x04\x01\x04\x02\x01\x03\x04\x10\x30\x0E\x04\x00\x02\x01\x00\x02"
"\x01\x00\x04\x00\x04\x00\x04\x00\x30\x12\x04\x00\x04\x00\xA0\x0C"
"\x02\x02\x37\xF0\x02\x01\x00\x02\x01\x00\x30\x00"
# SNMP PUBLIC WALK
udp 161,260,3401
"\x30\x1f\x02\x01\x00\x04\x06public\xa1\x12\x02\x01\x00\x02"
"\x01\x00\x02\x01\x00\x30\x07\x30\x05\x06\x01\x00\x05\x00"
# Sqlping - disabled because it trips a Snort rule with SID 2049
# ("MS-SQL ping attempt").
# udp 1434 "\x02"
# xdmcp - X Display Manager Control Protocol. Version 1, packet type
# Query (2), no authorization names. We expect a Willing or Unwilling
# packet in reply.
# http://cgit.freedesktop.org/xorg/doc/xorg-docs/plain/hardcopy/XDMCP/xdmcp.PS.gz
udp 177 "\x00\x01\x00\x02\x00\x01\x00"
# Connectionless LDAP - used by Microsoft Active Directory
udp 389
"\x30\x84\x00\x00\x00\x2d\x02\x01\x07\x63\x84\x00\x00\x00\x24\x04\x00"
"\x0a\x01\x00\x0a\x01\x00\x02\x01\x00\x02\x01\x64\x01\x01\x00\x87\x0b"
"objectClass0\x84\x00\x00\x00\x00"
# svrloc
udp 427
"\x02\x01\x00\x006 \x00\x00\x00\x00\x00\x01\x00\x02en\x00\x00\x00\x15"
"service:service-agent\x00\x07default\x00\x00\x00\x00"
# DTLS
udp 443,853,3391,4433,4740,5349,5684,5868,6514,6636,8232,10161,10162,12346,12446,12546,12646,12746,12846,12946,13046
# DTLS 1.0, length 52
"\x16\xfe\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x36"
# ClientHello, length 40, sequence 0, offset 0
"\x01\x00\x00\x2a\x00\x00\x00\x00\x00\x00\x00\x2a"
# DTLS 1.2
"\xfe\xfd"
# Random
"\x00\x00\x00\x00\x7c\x77\x40\x1e\x8a\xc8\x22\xa0\xa0\x18\xff\x93"
"\x08\xca\xac\x0a\x64\x2f\xc9\x22\x64\xbc\x08\xa8\x16\x89\x19\x3f"
# Session id length 0, cookie length 0
"\x00\x00"
# Cipher suites, mandatory TLS_RSA_WITH_AES_128_CBC_SHA
"\x00\x02\x00\x2f"
# Compressors (NULL)
"\x01\x00"
# Internet Key Exchange version 1, phase 1 Main Mode. We offer every
# combination of (DES, 3DES) and (MD5, SHA) in the hope that one of them will
# be acceptable. Because we use a fixed cookie, we set the association lifetime
# to 1 second to reduce the chance that repeated probes will look like
# retransmissions (and therefore not get a response). This payload comes from
# ike-scan --lifetime 1 --cookie 0011223344556677 --trans=5,2,1,2 --trans=5,1,1,2 --trans=1,2,1,2 --trans=1,1,1,2
# We expect another phase 1 message in response. This payload works better with
# a source port of 500 or a randomized initiator cookie.
udp 500
# Initiator cookie 0x0011223344556677, responder cookie 0x0000000000000000.
"\x00\x11\x22\x33\x44\x55\x66\x77\x00\x00\x00\x00\x00\x00\x00\x00"
# Version 1, Main Mode, flags 0x00, message ID 0x00000000, length 192.
"\x01\x10\x02\x00\x00\x00\x00\x00\x00\x00\x00\xC0"
# Security Association payload, length 164, IPSEC, IDENTITY.
"\x00\x00\x00\xA4\x00\x00\x00\x01\x00\x00\x00\x01"
# Proposal 1, length 152, ISAKMP, 4 transforms.
"\x00\x00\x00\x98\x01\x01\x00\x04"
# Transform 1, 3DES-CBC, SHA, PSK, group 2.
"\x03\x00\x00\x24\x01\x01\x00\x00\x80\x01\x00\x05\x80\x02\x00\x02"
"\x80\x03\x00\x01\x80\x04\x00\x02"
"\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01"
# Transform 2, 3DES-CBC, MD5, PSK, group 2.
"\x03\x00\x00\x24\x02\x01\x00\x00\x80\x01\x00\x05\x80\x02\x00\x01"
"\x80\x03\x00\x01\x80\x04\x00\x02"
"\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01"
# Transform 3, DES-CBC, SHA, PSK, group 2.
"\x03\x00\x00\x24\x03\x01\x00\x00\x80\x01\x00\x01\x80\x02\x00\x02"
"\x80\x03\x00\x01\x80\x04\x00\x02"
"\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01"
# Transform 4, DES-CBC, MD5, PSK, group 2.
"\x00\x00\x00\x24\x04\x01\x00\x00\x80\x01\x00\x01\x80\x02\x00\x01"
"\x80\x03\x00\x01\x80\x04\x00\x02"
"\x80\x0B\x00\x01\x00\x0C\x00\x04\x00\x00\x00\x01"
# IPSEC START
udp 500,4500
"\x31\x27\xfc"
"\xb0\x38\x10\x9e\x89\x00\x00\x00\x00\x00\x00\x00\x00\x01\x10\x02\x00"
"\x00\x00\x00\x00\x00\x00\x00\xcc\x0d\x00\x00\x5c\x00\x00\x00\x01\x00"
"\x00\x00\x01\x00\x00\x00\x50\x01\x01\x00\x02\x03\x00\x00\x24\x01\x01"
"\x00\x00\x80\x01\x00\x05\x80\x02\x00\x02\x80\x04\x00\x02\x80\x03\x00"
"\x03\x80\x0b\x00\x01\x00\x0c\x00\x04\x00\x00\x0e\x10\x00\x00\x00\x24"
"\x02\x01\x00\x00\x80\x01\x00\x05\x80\x02\x00\x01\x80\x04\x00\x02\x80"
"\x03\x00\x03\x80\x0b\x00\x01\x00\x0c\x00\x04\x00\x00\x0e\x10\x0d\x00"
"\x00\x18\x1e\x2b\x51\x69\x05\x99\x1c\x7d\x7c\x96\xfc\xbf\xb5\x87\xe4"
"\x61\x00\x00\x00\x04\x0d\x00\x00\x14\x40\x48\xb7\xd5\x6e\xbc\xe8\x85"
"\x25\xe7\xde\x7f\x00\xd6\xc2\xd3\x0d\x00\x00\x14\x90\xcb\x80\x91\x3e"
"\xbb\x69\x6e\x08\x63\x81\xb5\xec\x42\x7b\x1f\x00\x00\x00\x14\x26\x24"
"\x4d\x38\xed\xdb\x61\xb3\x17\x2a\x36\xe3\xd0\xcf\xb8\x19"
# Routing Information Protocol version 1. Special-case request for the entire
# routing table (address family 0, address 0.0.0.0, metric 16). RFC 1058,
# section 3.4.1.
udp 520
"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x10"
# RMCP ASF ping
udp 623
"\x06\x00\xff\x06" # RMCP version 6, sequence 0xff, normal RMCP class ASF
"\x00\x00\x11\xbe" # IAN ASF code 4542
"\x80\x00\x00\x00" # payload-less ASF presence ping
# IPMI
# RMCP Get Channel Auth Capabilities
udp 623
"\x06\x00\xff\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x20\x18"
"\xc8\x81\x00\x38\x8e\x04\xb5"
# serialnumberd. This service runs on Mac OS X Server. This probe
# requests the serial number of another server. In response we expect a
# packet starting with "SNRESPS:", followed by some data whose purpose
# is not known.
udp 626 "SNQUERY: 127.0.0.1:AAAAAA:xsvr"
# OpenVPN P_CONTROL_HARD_RESET_CLIENT_V2
# Byte 0; 0x38 opcode
# Byte 1-8: Session ID, random
# Byte 9: Message packet-id array length (0)
# Byte 10-13: Message packet-id (0)
udp 1194 "8d\xc1x\x01\xb8\x9b\xcb\x8f\0\0\0\0\0"
# OpenVPN when in PKI mode and without the "HMAC Firewall" setting enabled
# (tls-auth) should respond to the following probe, which is
# 0x38<8 random bytes><4 null bytes>
udp 1194
"\x38\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x00"
# Citrix MetaFrame application browser service
# Original idea from http://sh0dan.org/oldfiles/hackingcitrix.html
# Payload contents copied from Wireshark capture of Citrix Program
# Neighborhood client application. The application uses this payload to
# locate Citrix servers on the local network. Response to this probe is
# a 48 byte UDP payload as shown here:
#
# 0000 30 00 02 31 02 fd a8 e3 02 00 06 44 c0 a8 80 55
# 0010 00 00 00 00 00 00 00 00 00 00 00 00 02 00 06 44
# 0020 c0 a8 80 56 00 00 00 00 00 00 00 00 00 00 00 00
#
# The first 12 bytes appear to be the same in all responses.
#
# Bytes 0x00 appears to be a packet length field
# Bytes 0x0C - 0x0F are the IP address of the server
# Bytes 0x10 - 0x13 may vary, 0x14 - 0x1F do not appear to
# Bytes 0x20 - 0x23 are the IP address of the primary system in a server farm
# configuration
# Bytes 0x24 - 0x27 can vary, 0x28 - 0x2F do not appear to
udp 1604
"\x1e\x00\x01\x30\x02\xfd\xa8\xe3\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# RADIUS Access-Request. This is a degenerate packet with no username or
# password; we expect an Access-Reject in response. The Identifier and Request
# Authenticator are both 0. It was generated by running
# echo 'User-Password = ""' | radclient <ip> auth ""
# and then manually stripping out the password.
#
# Section 2 of the RFC says "A request from a client for which the
# RADIUS server does not have a shared secret MUST be silently
# discarded." So this payload only works when the server is configured
# (or misconfigured) to know the scanning machine as a client.
#
# RFC 2865: "The early deployment of RADIUS was done using UDP port
# number 1645, which conflicts with the "datametrics" service. The
# officially assigned port number for RADIUS is 1812.
udp 1645,1812
"\x01\x00\x00\x14"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# L2TP ICRQ
udp 1701
"\xc8\x02"
"\x00\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00"
"\x01\x80\x08\x00\x00\x00\x02\x01\x00\x80\x0e\x00\x00\x00\x07"
"nxp-scan\x80\x0a\x00\x00\x00\x03\x00\x00\x00\x03\x80"
"\x08\x00\x00\x00\x09\x00\x00"
# UPNP MSEARCH
udp 1900
"M-SEARCH * HTTP/1.1\r\nHost: 239.255.255.250:1900\r\n"
"Man: \"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n"
# NFS version 2, RFC 1831. XID 0x00000000, program 100003 (NFS), procedure
# NFSPROC_NULL (does nothing, see section 2.2.1), null authentication (see
# section 9.1).
udp 2049
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01\x86\xA3"
"\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00"
# GPRS Tunneling Protocol (GTP)
udp 2123,2152
# GTPv1, protocol 1
"\x32"
# EchoRequest
"\x01"
# message length
"\x00\x04"
# Tunnel endpoint identifier
"\x00\x00\x42\x00"
# sequence number
"\x13\x37"
# N-PDU number
"\x00"
# next extension header type
"\x00"
# GPRS Tunneling Protocol (GTP) "prime" v2
# This same packet can be used for GTP v2 on ports 2123 and 2152 if you change
# the first byte from \x4e to \x40
udp 3386
# GTP'v2
"\x4e"
# EchoRequest
"\x01"
# message length
"\x00\x04"
# sequence number
"\xde\xfe\xc8\x00"
# Freelancer game server status query
# http://sourceforge.net/projects/gameq/
# (relevant files: games.ini, packets.ini, freelancer.php)
udp 2302 "\x00\x02\xf1\x26\x01\x26\xf0\x90\xa6\xf0\x26\x57\x4e\xac\xa0\xec\xf8\x68\xe4\x8d\x21"
# Apple Remote Desktop (ARD)
udp 3283 "\0\x14\0\x01\x03"
# STUN Binding request, see RFC 5389 Section 6
# message type = 0x001, Binding (see Section 18.1)
# message length = 0
# magic cookie = 0x2112a442
# transaction ID = "\x00"*12
udp 3478 "\x00\x01\x00\x00\x21\x12\xa4\x42\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# Sun Service Tag Discovery protocol (stdiscover)
# http://arc.opensolaris.org/caselog/PSARC/2006/638/stdiscover_protocolv2.pdf
# Would work better with a varying cookie; the second and later sends of this
# probe will be interpreted as resends by the server and will be ignored.
udp 6481 "[PROBE] 0000"
# NAT-PMP external IP address request. See section 3.2 of
# http://files.dns-sd.org/draft-cheshire-nat-pmp.txt.
udp 5351 "\x00\x00"
# DNS Service Discovery (DNS-SD) service query, as used in Zeroconf.
# Transaction ID 0x0000, flags 0x0000, 1 question: PTR query for
# _services._dns-sd._udp.local. If the remote host supports DNS-SD it will send
# back a list of all its services. This is the same as a packet capture of
# dns-sd -B _services._dns-sd._udp .
# See section 9 of
# http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt.
# This first probe is a QU probe, meaning a unicast response is desired
udp 5353
"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"
"\x09_services\x07_dns-sd\x04_udp\x05local\x00\x00\x0C\x80\x01"
# This second probe is a QM probe, meaning a unicast response is desired
udp 5353
"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"
"\x09_services\x07_dns-sd\x04_udp\x05local\x00\x00\x0C\x00\x01"
# PCANY STATUS
udp 5632 "ST"
# CoAP GET .well-known/core
udp 5683 "@\x01\x01\xce\xbb.well-known\x04core"
# UT2K PING
udp 7777 "None\x00"
# Ubiquiti Discovery Service - v1
udp 10001 "\x01\x00\x00\x00"
# Amanda backup service noop request. I think that this does nothing on the
# server but only asks it to send back its feature list. In reply we expect an
# ACK or (more likely) an ERROR. I couldn't find good online documentation of
# the Amanda network protocol. There is parsing code in the Amanda source at
# common-src/security-util.c. This is based on a packet capture of
# amcheck <config> <host>
udp 10080
"Amanda 2.6 REQ HANDLE 000-00000000 SEQ 0\n"
"SERVICE noop\n"
# VxWorks Wind River Debugger
udp 17185
# Random XID
"\x00\x00\x00\x00"
# RPC version 2 procedure call
"\x00\x00\x00\x00\x00\x00\x00\x02"
# WDB version 1
"\x55\x55\x55\x55\x00\x00\x00\x01"
# WDB_TARGET_PING
"\x00\x00\x00\x00"
# RPC Auth NULL
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# Checksum
"\xff\xff\x55\x13"
# WDB wrapper (length and sequence number)
"\x00\x00\x00\x30\x00\x00\x00\x01"
# Empty data?
"\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00"
# VXWORKS DEBUG (alternative?)
udp 17185
"\x72\x37\x72\x37\x00\x00\x00"
"\x00\x00\x00\x00\x02\x55\x55\x55\x55\x00\x00\x00\x01\x00\x00\x00\x01"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff"
"\xff\x55\x10\x00\x00\x00\x3c\x00\x00\x00\x03\x00\x00\x00\x02\x00\x00"
"\x00\x00\x00\x00\x00\x00"
# Quake 2 and Quake 3 game servers (and servers of derived games like Nexuiz).
# Gets game information from the server (see probe responses in
# nmap-service-probes). These services typically run on a base port or a
# few numbers higher.
# Quake 2. Typical ports: 27910-27914.
udp 27910-27914 "\xff\xff\xff\xffstatus"
# Quake 3. Typical ports:
# 26000-26004: Nexuiz
# 27960-27964: Various games
# 30720-30724: Tremulous
# 44400: Warsow
udp 26000-26004,27960-27964,30720-30724,44400 "\xff\xff\xff\xffgetstatus"
# Murmur 1.2.X (Mumble server)
# UDP ping. "abcdefgh" is an identifier. See
# http://mumble.sourceforge.net/Protocol.
udp 64738 "\x00\x00\x00\x00abcdefgh"
# Ventrilo 2.1.2+
# UDP general status request (encrypted).
# See http://aluigi.altervista.org/papers.htm#ventrilo
udp 3784
"\x01\xe7\xe5\x75\x31\xa3\x17\x0b\x21\xcf\xbf\x2b\x99\x4e\xdd\x19\xac\xde\x08\x5f\x8b\x24\x0a\x11\x19\xb6\x73\x6f\xad\x28\x13\xd2\x0a\xb9\x12\x75"
# Kademlia (kad) as used by various P2P applications. Send a Kademlia ping
# 4665, 4666, 4672, 6429: eDonkey/eMule and variants
udp 4665,4666,4672,6429 "\xE4\x60"
# TeamSpeak 2
# UDP login request
# See http://wiki.wireshark.org/TeamSpeak2
udp 8767
"\xf4\xbe\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x002x\xba\x85\tTeamSpeak\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\nWindows XP\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00 \x00<\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08nickname\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# TS3INIT1
udp 9987
"TS3INIT1\x00\x65\x00\x00\x88\x0a\x39\x7b\x0f\x00\x5b\x55\x72\xef\xdc\x78\x32\x6b\x00\x00\x00\x00\x00\x00\x00\x00"
# TeamSpeak 3
# UDP login request (encrypted)
# http://seclists.org/nmap-dev/2013/q3/72
udp 9987
"\x05\xca\x7f\x16\x9c\x11\xf9\x89\x00\x00\x00\x00\x02\x9d\x74\x8b\x45\xaa\x7b\xef\xb9\x9e\xfe\xad\x08\x19\xba\xcf\x41\xe0\x16\xa2\x32\x6c\xf3\xcf\xf4\x8e\x3c\x44\x83\xc8\x8d\x51\x45\x6f\x90\x95\x23\x3e\x00\x97\x2b\x1c\x71\xb2\x4e\xc0\x61\xf1\xd7\x6f\xc5\x7e\xf6\x48\x52\xbf\x82\x6a\xa2\x3b\x65\xaa\x18\x7a\x17\x38\xc3\x81\x27\xc3\x47\xfc\xa7\x35\xba\xfc\x0f\x9d\x9d\x72\x24\x9d\xfc\x02\x17\x6d\x6b\xb1\x2d\x72\xc6\xe3\x17\x1c\x95\xd9\x69\x99\x57\xce\xdd\xdf\x05\xdc\x03\x94\x56\x04\x3a\x14\xe5\xad\x9a\x2b\x14\x30\x3a\x23\xa3\x25\xad\xe8\xe6\x39\x8a\x85\x2a\xc6\xdf\xe5\x5d\x2d\xa0\x2f\x5d\x9c\xd7\x2b\x24\xfb\xb0\x9c\xc2\xba\x89\xb4\x1b\x17\xa2\xb6"
# Memcached
# version request (shorter response than stats)
# https://github.com/memcached/memcached/blob/master/doc/protocol.txt
udp 11211
"\0\x01\0\0\0\x01\0\0version\r\n"
# Steam, typically using a port in 27015-27030. Send a "Source Engine query"
udp 27015-27030
"\xff\xff\xff\xffTSource Engine Query\x00"
# TRIN00 UNIX PING
udp 27444 "png l44adsl"
# BO PING
udp 31337
"\xce\x63\xd1\xd2\x16\xe7\x13\xcf\x38"
"\xa5\xa5\x86\xb2\x75\x4b\x99\xaa\x32\x58"
# TRIN00 WIN PING
udp 34555 "png []..Ks"
# Beckhoff ADS discovery request
# https://github.com/ONE75/adsclient/blob/master/src/AdsClient.Finder/DeviceFinder.cs#L49-L64
udp 48899
"\x03\x66\x14\x71\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x10\x27\x00\x00\x00\x00"
+2996
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -271,6 +271,7 @@ pub struct Config {
#[cfg(not(tarpaulin_include))]
#[allow(clippy::doc_link_with_quotes)]
#[allow(clippy::manual_unwrap_or_default)]
impl Config {
/// Reads the configuration file with TOML format and parses it into a
/// Config struct.
+1 -1
View File
@@ -55,4 +55,4 @@ pub mod scripts;
pub mod address;
pub mod udp_packets;
pub mod generated;
+35 -15
View File
@@ -1,6 +1,6 @@
//! Core functionality for actual scanning behaviour.
use crate::generated::get_parsed_data;
use crate::port_strategy::PortStrategy;
use crate::udp_packets::udp_payload::cust_payload;
use log::debug;
mod socket_iterator;
@@ -11,6 +11,7 @@ use async_std::prelude::*;
use async_std::{io, net::UdpSocket};
use colored::Colorize;
use futures::stream::FuturesUnordered;
use std::collections::BTreeMap;
use std::{
collections::HashSet,
net::{IpAddr, Shutdown, SocketAddr},
@@ -84,10 +85,11 @@ impl Scanner {
let mut open_sockets: Vec<SocketAddr> = Vec::new();
let mut ftrs = FuturesUnordered::new();
let mut errors: HashSet<String> = HashSet::new();
let udp_map = get_parsed_data();
for _ in 0..self.batch_size {
if let Some(socket) = socket_iterator.next() {
ftrs.push(self.scan_socket(socket));
ftrs.push(self.scan_socket(socket, udp_map.clone()));
} else {
break;
}
@@ -101,7 +103,7 @@ impl Scanner {
while let Some(result) = ftrs.next().await {
if let Some(socket) = socket_iterator.next() {
ftrs.push(self.scan_socket(socket));
ftrs.push(self.scan_socket(socket, udp_map.clone()));
}
match result {
@@ -133,19 +135,13 @@ impl Scanner {
/// ```
///
/// Note: `self` must contain `self.ip`.
async fn scan_socket(&self, socket: SocketAddr) -> io::Result<SocketAddr> {
async fn scan_socket(
&self,
socket: SocketAddr,
udp_map: BTreeMap<Vec<u16>, Vec<u8>>,
) -> io::Result<SocketAddr> {
if self.udp {
let payload = cust_payload(socket.port());
let tries = self.tries.get();
for _ in 1..=tries {
match self.udp_scan(socket, &payload, self.timeout).await {
Ok(true) => return Ok(socket),
Ok(false) => continue,
Err(e) => return Err(e),
}
}
return Ok(socket);
return self.scan_udp_socket(socket, udp_map).await;
}
let tries = self.tries.get();
@@ -180,6 +176,30 @@ impl Scanner {
unreachable!();
}
async fn scan_udp_socket(
&self,
socket: SocketAddr,
udp_map: BTreeMap<Vec<u16>, Vec<u8>>,
) -> io::Result<SocketAddr> {
let mut payload: Vec<u8> = Vec::new();
for (key, value) in udp_map {
if key.contains(&socket.port()) {
payload = value;
}
}
let tries = self.tries.get();
for _ in 1..=tries {
match self.udp_scan(socket, &payload, self.timeout).await {
Ok(true) => return Ok(socket),
Ok(false) => continue,
Err(e) => return Err(e),
}
}
Ok(socket)
}
/// Performs the connection to the socket with timeout
/// # Example
///
-279
View File
@@ -1,279 +0,0 @@
pub mod udp_payload {
// const MAX_PAYLOAD_IPV4: usize = 65507; // 65,535 - 20 (IP header) - 8 (UDP header)
// const MAX_PAYLOAD_IPV6: usize = 65527; // 65,535 - 40 (IPv6 header) - 8 (UDP header)
/// From [RFC 768](https://www.rfc-editor.org/rfc/rfc768.txt)
/// We send blank UDP packets, unless the port is determined to be special.
///
/// ```text
/// HEADER Handled by the OS
/// 0 1 2 3
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Source Port | Destination Port |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Length | Checksum |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// We append the data, based on the port the the header
/// DATA
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// | Data (based on port) |
/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/// ```
///
/// # Fields
///
/// - **Source Port**: The source port number.
/// - **Destination Port**: The destination port number.
/// - **Length**: The length of the UDP header and data.
/// - **Checksum**: The checksum for error-checking.
/// - **Data**: The payload data, which can vary based on the port.
#[allow(clippy::match_single_binding)]
pub fn cust_payload(dst_prt: u16) -> Vec<u8> {
match dst_prt {
// 53 => craft_dns_query_packet(),
// 67 => craft_dhcpc_packet(),
// 123 => craft_ntp_packet(),
// 161 => craft_snmp_packet(),
_ => vec![],
}
}
pub fn craft_snmptrap_packet() -> Vec<u16> {
let version = vec![0x30, 0x82]; // SNMP version
let community_string = vec![0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63]; // Community string "public"
let pdu_type = vec![0xa4, 0x82]; // PDU type for SNMP Trap
let enterprise_oid = vec![0x06, 0x09, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00]; // Enterprise OID
// Combine the components into a single SNMP Trap packet
[version, community_string, pdu_type, enterprise_oid].concat()
}
/// From [RFC 1592](https://www.rfc-editor.org/rfc/rfc1592.txt)
/// Crafts an SNMP packet based on the structure from RFC 1592.
///
/// RFC 1592 defines the structure of an SNMP packet as follows
/// - **ASN.1 header**: 0x30
/// - **PDU length**: 37 + length of community name
/// - **SNMP version**: 0x02 0x01 0x00 (integer, length=1, value=0)
/// - **Community name**: A string of varying length
/// - **SNMP GET request**: 0xa0 0x1c (request type=0xa0, length=0x1c)
/// - **SNMP request ID**: 0x02 0x01 0x01 (integer, length=1, ID=1)
/// - **SNMP error status**: 0x02 0x01 0x00 (integer, length=1, error=0)
/// - **SNMP index**: 0x02 0x01 0x00 (integer, length=1, index=0)
/// - **VarBind list**: 0x30 0x11 (length=0x11)
/// - **VarBind**: 0x30 0x0f (length=0x0f)
/// - **Object ID**: 0x06 0x0b (length=0x0b)
/// - **Object instance**: 1.3.6.1.4.1.2.2.1.1.1.0
/// - **Null value**: 0x05 0x00 (length=0)
///
/// The PDU length formula:
/// ```text
/// PDU_length = length of version field and string tag (4 bytes)
/// + length of community length field (1 byte)
/// + length of community name (depends...)
/// + length of SNMP GET request (32 bytes)
/// ```
///
/// # Returns
///
/// A `Vec<u8>` representing the crafted SNMP packet.
pub fn craft_snmp_packet() -> Vec<u8> {
// TODO all versions of snmp
let v1 = vec![0x30, 0x29, 0x02, 0x01, 0x00];
let community_string = vec![0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63];
let pdu_type = vec![0xa0, 0x1c];
let request_id = vec![0x02, 0x04, 0x7a, 0x69, 0x67, 0x71];
let error_status = vec![0x02, 0x01, 0x00];
let error_index = vec![0x02, 0x01, 0x00];
let variable_bindings = vec![
0x30, 0x0e, 0x30, 0x0c, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00,
0x05, 0x00,
];
let _basic_snmp = [
0x30, 0x26, 0x02, 0x01, 0x01, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0xa0,
0x19, 0x02, 0x04, 0x71, 0x64, 0xfe, 0xf1, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x30,
0x0b, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x05, 0x00,
];
[
v1,
community_string,
pdu_type,
request_id,
error_status,
error_index,
variable_bindings,
]
.concat()
}
/// Constructs a DHCP packet based on the RFC 1541 Dynamic Host Configuration Protocol specification.
///
///
/// # Returns
///
/// A `Vec<u8>` representing the DHCP packet.
///
/// This function crafts a DHCP Discover packet with the following fields:
/// - **op**: BOOTREQUEST (1)
/// - **htype**: Ethernet (1)
/// - **hlen**: 6
/// - **hops**: 0
/// - **xid**: Random transaction ID
/// - **secs**: 0
/// - **flags**: 0x8000 (Broadcast)
/// - **ciaddr**: 0.0.0.0
/// - **yiaddr**: 0.0.0.0
/// - **siaddr**: 0.0.0.0
/// - **giaddr**: 0.0.0.0
/// - **chaddr**: 00:00:00:00:00:00 (Client MAC address)
/// - **sname**: Not given
/// - **file**: Not given
/// - **options**: DHCP options
pub fn craft_dhcpc_packet() -> Vec<u8> {
let mut packet = Vec::with_capacity(240);
// BOOTP message type: Boot Request (1)
packet.push(0x01);
// Hardware type: Ethernet (10Mb) (1)
packet.push(0x01);
// Hardware address length: 6
packet.push(0x06);
// Hops: 0
packet.push(0x00);
// Transaction ID: random (0x3903F326)
packet.extend(&[0x39, 0x03, 0xF3, 0x26]);
// Seconds elapsed: 0
packet.extend(&[0x00, 0x00]);
// Bootp flags: 0x8000 (Broadcast) (0x8000)
packet.extend(&[0x80, 0x00]);
// Client IP address: 0.0.0.0
packet.extend(&[0x00, 0x00, 0x00, 0x00]);
// Your (client) IP address: 0.0.0.0
packet.extend(&[0x00, 0x00, 0x00, 0x00]);
// Next server IP address: 0.0.0.0
packet.extend(&[0x00, 0x00, 0x00, 0x00]);
// Relay agent IP address: 0.0.0.0
packet.extend(&[0x00, 0x00, 0x00, 0x00]);
// Client MAC address: 00:00:00:00:00:00
packet.extend(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
// Client hardware address padding: 00000000000000000000
packet.extend(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
// Server host name not given
packet.extend(&[0x00; 64]);
// Boot file name not given
packet.extend(&[0x00; 128]);
// Magic cookie: DHCP
packet.extend(&[0x63, 0x82, 0x53, 0x63]);
// DHCP Message Type: DHCP Discover (1)
packet.extend(&[0x35, 0x01, 0x01]);
// DHCP Option: Parameter Request List
packet.extend(&[0x37, 0x04, 0x01, 0x03, 0x06, 0x2a]);
// End Option
packet.push(0xff);
packet
}
/// Constructs a DNS query packet.
///
/// The structure of the DNS packet is as follows:
///
/// ```text
/// +---------------------+
/// | Header |
/// +---------------------+
/// | Question | the question for the name server
/// +---------------------+
/// | Answer | RRs answering the question
/// +---------------------+
/// | Authority | RRs pointing toward an authority
/// +---------------------+
/// | Additional | RRs holding additional information
/// +---------------------+
/// ```
///
/// The function builds a DNS query packet with the following fields:
/// - **Header**: Contains the transaction ID and flags.
/// - **Question**: Specifies the query (e.g., the domain name to look up).
/// - **Answer**: Resource records that answer the question (empty for a query).
/// - **Authority**: Resource records that point toward an authority (empty for a query).
/// - **Additional**: Resource records holding additional information (empty for a query).
///
/// # Returns
///
/// A `Vec<u8>` representing the DNS query packet.
pub fn craft_dns_query_packet() -> Vec<u8> {
let mut packet = Vec::new();
// Transaction ID: Random
packet.extend(&[0x12, 0x34]);
// Flags: Standard query
packet.extend(&[0x01, 0x00]);
// Header ^
// Questions: 1
packet.extend(&[0x00, 0x01]);
// Answer RRs: 0
packet.extend(&[0x00, 0x00]);
// Authority RRs: 0
packet.extend(&[0x00, 0x00]);
// Additional RRs: 0
packet.extend(&[0x00, 0x00]);
// Query: www.google.com
let query_name = "www.google.com";
for part in query_name.split('.') {
packet.push(part.len() as u8);
packet.extend(part.as_bytes());
}
packet.push(0); // End of query name
// Query Type: A (host address)
packet.extend(&[0x00, 0x01]);
// Query Class: IN (internet)
packet.extend(&[0x00, 0x01]);
packet
}
/// Creates the simplest NTP packet possible
/// 0x1b followed by 47 0s, (Version = 3, Mode = 3)
pub fn craft_ntp_packet() -> Vec<u8> {
let mut packet = vec![0u8; 48];
packet[0] = 0x1b;
packet
}
// TODO add more packets for the top 1000 ports
// `sort -r -k3 /usr/share/nmap/nmap-services | grep udp | head -n 1000`
// There has to be a better way to structure this, maybe internal crate for packet payload
// creation
}