Add TCB argument to repl functions in protos

This commit is contained in:
_Frky 2021-12-23 09:05:40 +01:00
parent f1368df0de
commit fe2fd6ca5b
6 changed files with 46 additions and 24 deletions

View file

@ -21,6 +21,7 @@ use flate2::write::ZlibEncoder;
use flate2::Compression; use flate2::Compression;
use crate::client::ClientInfo; use crate::client::ClientInfo;
use crate::proto::TCPControlBlock;
use crate::Masscanned; use crate::Masscanned;
pub const GHOST_PATTERN_SIGNATURE: &[u8; 5] = b"Gh0st"; pub const GHOST_PATTERN_SIGNATURE: &[u8; 5] = b"Gh0st";
@ -29,6 +30,7 @@ pub fn repl<'a>(
_data: &'a [u8], _data: &'a [u8],
_masscanned: &Masscanned, _masscanned: &Masscanned,
_client_info: &mut ClientInfo, _client_info: &mut ClientInfo,
_tcb: Option<&mut TCPControlBlock>,
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
debug!("receiving Gh0st data, sending one null byte payload"); debug!("receiving Gh0st data, sending one null byte payload");
// Packet structure: // Packet structure:

View file

@ -25,6 +25,7 @@ use crate::smack::{
Smack, SmackFlags, BASE_STATE, NO_MATCH, SMACK_CASE_INSENSITIVE, UNANCHORED_STATE, Smack, SmackFlags, BASE_STATE, NO_MATCH, SMACK_CASE_INSENSITIVE, UNANCHORED_STATE,
}; };
use crate::Masscanned; use crate::Masscanned;
use crate::proto::{TCPControlBlock};
pub const HTTP_VERBS: [&str; 9] = [ pub const HTTP_VERBS: [&str; 9] = [
"GET", "PUT", "POST", "HEAD", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH", "GET", "PUT", "POST", "HEAD", "DELETE", "CONNECT", "OPTIONS", "TRACE", "PATCH",
@ -62,7 +63,7 @@ const HTTP_STATE_CONTENT: usize = 64;
const HTTP_STATE_FAIL: usize = 0xFFFF; const HTTP_STATE_FAIL: usize = 0xFFFF;
struct ProtocolState { pub struct ProtocolState {
state: usize, state: usize,
state_bis: usize, state_bis: usize,
smack_state: usize, smack_state: usize,
@ -223,6 +224,7 @@ pub fn repl<'a>(
data: &'a [u8], data: &'a [u8],
_masscanned: &Masscanned, _masscanned: &Masscanned,
_client_info: &ClientInfo, _client_info: &ClientInfo,
_tcb: Option<&mut TCPControlBlock>,
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
debug!("receiving HTTP data"); debug!("receiving HTTP data");
let mut pstate = ProtocolState::new(); let mut pstate = ProtocolState::new();

View file

@ -25,7 +25,7 @@ use crate::smack::{Smack, SmackFlags, BASE_STATE, NO_MATCH, SMACK_CASE_SENSITIVE
use crate::Masscanned; use crate::Masscanned;
mod http; mod http;
use http::HTTP_VERBS; use http::{ProtocolState as HTTPProtocolState, HTTP_VERBS};
mod stun; mod stun;
use stun::{STUN_PATTERN_CHANGE_REQUEST, STUN_PATTERN_EMPTY, STUN_PATTERN_MAGIC}; use stun::{STUN_PATTERN_CHANGE_REQUEST, STUN_PATTERN_EMPTY, STUN_PATTERN_MAGIC};
@ -37,7 +37,7 @@ mod ghost;
use ghost::GHOST_PATTERN_SIGNATURE; use ghost::GHOST_PATTERN_SIGNATURE;
mod rpc; mod rpc;
use rpc::{RPC_CALL_TCP, RPC_CALL_UDP}; use rpc::{ProtocolState as RPCProtocolState, RPC_CALL_TCP, RPC_CALL_UDP};
mod smb; mod smb;
use smb::{SMB1_PATTERN_MAGIC, SMB2_PATTERN_MAGIC}; use smb::{SMB1_PATTERN_MAGIC, SMB2_PATTERN_MAGIC};
@ -51,8 +51,16 @@ const PROTO_RPC_UDP: usize = 6;
const PROTO_SMB1: usize = 7; const PROTO_SMB1: usize = 7;
const PROTO_SMB2: usize = 8; const PROTO_SMB2: usize = 8;
struct TCPControlBlock { enum ProtocolState {
proto_state: usize, HTTPProtocolState,
RPCProtocolState,
}
pub struct TCPControlBlock {
/* state used to detect protocols (not specific) */
smack_state: usize,
/* internal state of protocol parser (e.g., HTTP parsing) */
proto_state: Option<ProtocolState>,
} }
lazy_static! { lazy_static! {
@ -126,26 +134,29 @@ pub fn repl<'a>(
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
debug!("packet payload: {:?}", data); debug!("packet payload: {:?}", data);
let mut id; let mut id;
let mut ct = CONTABLE.lock().unwrap();
let mut tcb = None;
if client_info.transport == Some(IpNextHeaderProtocols::Tcp) && client_info.cookie == None { if client_info.transport == Some(IpNextHeaderProtocols::Tcp) && client_info.cookie == None {
error!("Unexpected empty cookie"); error!("Unexpected empty cookie");
return None; return None;
} else if client_info.cookie != None { } else if client_info.cookie != None {
/* proto over TCP */ /* proto over TCP */
let cookie = client_info.cookie.unwrap(); let cookie = client_info.cookie.unwrap();
let mut ct = CONTABLE.lock().unwrap();
if !ct.contains_key(&cookie) { if !ct.contains_key(&cookie) {
ct.insert( ct.insert(
cookie, cookie,
TCPControlBlock { TCPControlBlock {
proto_state: BASE_STATE, smack_state: BASE_STATE,
proto_state: None,
}, },
); );
} }
let mut i = 0; let mut i = 0;
let mut tcb = ct.get_mut(&cookie).unwrap(); let mut t = ct.get_mut(&cookie).unwrap();
let mut state = tcb.proto_state; let mut state = t.smack_state;
id = PROTO_SMACK.search_next(&mut state, data, &mut i); id = PROTO_SMACK.search_next(&mut state, data, &mut i);
tcb.proto_state = state; t.smack_state = state;
tcb = Some(t);
} else { } else {
/* proto over else (e.g., UDP) */ /* proto over else (e.g., UDP) */
let mut i = 0; let mut i = 0;
@ -158,14 +169,14 @@ pub fn repl<'a>(
} }
/* proto over else (e.g., UDP) */ /* proto over else (e.g., UDP) */
match id { match id {
PROTO_HTTP => http::repl(data, masscanned, client_info), PROTO_HTTP => http::repl(data, masscanned, client_info, tcb),
PROTO_STUN => stun::repl(data, masscanned, &mut client_info), PROTO_STUN => stun::repl(data, masscanned, &mut client_info, tcb),
PROTO_SSH => ssh::repl(data, masscanned, &mut client_info), PROTO_SSH => ssh::repl(data, masscanned, &mut client_info, tcb),
PROTO_GHOST => ghost::repl(data, masscanned, &mut client_info), PROTO_GHOST => ghost::repl(data, masscanned, &mut client_info, tcb),
PROTO_RPC_TCP => rpc::repl_tcp(data, masscanned, &mut client_info), PROTO_RPC_TCP => rpc::repl_tcp(data, masscanned, &mut client_info, tcb),
PROTO_RPC_UDP => rpc::repl_udp(data, masscanned, &mut client_info), PROTO_RPC_UDP => rpc::repl_udp(data, masscanned, &mut client_info, tcb),
PROTO_SMB1 => smb::repl_smb1(data, masscanned, &mut client_info), PROTO_SMB1 => smb::repl_smb1(data, masscanned, &mut client_info, tcb),
PROTO_SMB2 => smb::repl_smb2(data, masscanned, &mut client_info), PROTO_SMB2 => smb::repl_smb2(data, masscanned, &mut client_info, tcb),
_ => { _ => {
debug!("id: {}", id); debug!("id: {}", id);
None None

View file

@ -19,6 +19,7 @@ use std::convert::TryInto;
use std::net::IpAddr; use std::net::IpAddr;
use crate::client::ClientInfo; use crate::client::ClientInfo;
use crate::proto::TCPControlBlock;
use crate::Masscanned; use crate::Masscanned;
// last fragment (1 bit) + fragment len (31 bits) / length XID (random) / message type: call (0) / RPC version (0-255) / Program: Portmap (99840 - 100095) / Program version (*, random versions used, see below) / / Procedure: ??? (0-255) // last fragment (1 bit) + fragment len (31 bits) / length XID (random) / message type: call (0) / RPC version (0-255) / Program: Portmap (99840 - 100095) / Program version (*, random versions used, see below) / / Procedure: ??? (0-255)
@ -47,7 +48,7 @@ enum RpcState {
} }
#[derive(Debug)] #[derive(Debug)]
struct ProtocolState { pub struct ProtocolState {
state: RpcState, state: RpcState,
last_frag: bool, last_frag: bool,
frag_len: u32, frag_len: u32,
@ -373,6 +374,7 @@ pub fn repl_tcp<'a>(
data: &'a [u8], data: &'a [u8],
_masscanned: &Masscanned, _masscanned: &Masscanned,
client_info: &ClientInfo, client_info: &ClientInfo,
_tcb: Option<&mut TCPControlBlock>,
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
let mut pstate = ProtocolState::new(); let mut pstate = ProtocolState::new();
rpc_parse(&mut pstate, data); rpc_parse(&mut pstate, data);
@ -402,6 +404,7 @@ pub fn repl_udp<'a>(
data: &'a [u8], data: &'a [u8],
_masscanned: &Masscanned, _masscanned: &Masscanned,
client_info: &ClientInfo, client_info: &ClientInfo,
_tcb: Option<&mut TCPControlBlock>,
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
let mut pstate = ProtocolState::new(); let mut pstate = ProtocolState::new();
pstate.state = RpcState::Xid; pstate.state = RpcState::Xid;

View file

@ -19,6 +19,7 @@ use log::*;
use std::str; use std::str;
use crate::client::ClientInfo; use crate::client::ClientInfo;
use crate::proto::TCPControlBlock;
use crate::Masscanned; use crate::Masscanned;
pub const SSH_PATTERN_CLIENT_PROTOCOL: &[u8; 7] = b"SSH-2.0"; pub const SSH_PATTERN_CLIENT_PROTOCOL: &[u8; 7] = b"SSH-2.0";
@ -27,6 +28,7 @@ pub fn repl<'a>(
data: &'a [u8], data: &'a [u8],
_masscanned: &Masscanned, _masscanned: &Masscanned,
mut _client_info: &mut ClientInfo, mut _client_info: &mut ClientInfo,
_tcb: Option<&mut TCPControlBlock>,
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
debug!("receiving SSH data"); debug!("receiving SSH data");
let repl_data = b"SSH-2.0-1\r\n".to_vec(); let repl_data = b"SSH-2.0-1\r\n".to_vec();

View file

@ -24,6 +24,7 @@ use byteorder::{BigEndian, ByteOrder};
use std::io; use std::io;
use crate::client::ClientInfo; use crate::client::ClientInfo;
use crate::proto::TCPControlBlock;
use crate::Masscanned; use crate::Masscanned;
/* RFC 5389: The magic cookie field MUST contain the fixed value 0x2112A442 in /* RFC 5389: The magic cookie field MUST contain the fixed value 0x2112A442 in
@ -354,6 +355,7 @@ pub fn repl<'a>(
data: &'a [u8], data: &'a [u8],
_masscanned: &Masscanned, _masscanned: &Masscanned,
mut client_info: &mut ClientInfo, mut client_info: &mut ClientInfo,
_tcb: Option<&mut TCPControlBlock>,
) -> Option<Vec<u8>> { ) -> Option<Vec<u8>> {
debug!("receiving STUN data"); debug!("receiving STUN data");
let stun_req: StunPacket = if let Ok(s) = StunPacket::new(&data) { let stun_req: StunPacket = if let Ok(s) = StunPacket::new(&data) {
@ -443,7 +445,7 @@ mod tests {
ip_addresses: Some(&ips), ip_addresses: Some(&ips),
log: MetaLogger::new(), log: MetaLogger::new(),
}; };
let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info) { let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info, None) {
r r
} else { } else {
panic!("expected an answer, got None"); panic!("expected an answer, got None");
@ -507,7 +509,7 @@ mod tests {
client_info.ip.dst = Some(IpAddr::V6(masscanned_ip_addr)); client_info.ip.dst = Some(IpAddr::V6(masscanned_ip_addr));
client_info.port.src = Some(55000); client_info.port.src = Some(55000);
client_info.port.dst = Some(65000); client_info.port.dst = Some(65000);
let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info) { let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info, None) {
r r
} else { } else {
panic!("expected an answer, got None"); panic!("expected an answer, got None");
@ -559,7 +561,7 @@ mod tests {
client_info.ip.dst = Some(IpAddr::V4(masscanned_ip_addr)); client_info.ip.dst = Some(IpAddr::V4(masscanned_ip_addr));
client_info.port.src = Some(55000); client_info.port.src = Some(55000);
client_info.port.dst = Some(65000); client_info.port.dst = Some(65000);
let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info) { let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info, None) {
r r
} else { } else {
panic!("expected an answer, got None"); panic!("expected an answer, got None");
@ -609,7 +611,7 @@ mod tests {
client_info.ip.dst = Some(IpAddr::V4(masscanned_ip_addr)); client_info.ip.dst = Some(IpAddr::V4(masscanned_ip_addr));
client_info.port.src = Some(55000); client_info.port.src = Some(55000);
client_info.port.dst = Some(65535); client_info.port.dst = Some(65535);
let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info) { let payload_resp = if let Some(r) = repl(payload, &masscanned, &mut client_info, None) {
r r
} else { } else {
panic!("expected an answer, got None"); panic!("expected an answer, got None");