From 1e5f5d405ffa05c56e0959fdfd6fe223fe9a0d97 Mon Sep 17 00:00:00 2001 From: Pierre Chifflier Date: Tue, 17 Apr 2018 09:31:04 +0200 Subject: [PATCH] Kerberos 5: add support for TCP as well --- doc/userguide/rules/intro.rst | 1 + rust/src/krb/krb5.rs | 70 +++++++++++++++++++++++++++++++++-- src/output-json-krb5.c | 1 + 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/doc/userguide/rules/intro.rst b/doc/userguide/rules/intro.rst index 55ac9b57f9..64604f0970 100644 --- a/doc/userguide/rules/intro.rst +++ b/doc/userguide/rules/intro.rst @@ -79,6 +79,7 @@ you can pick from. These are: * enip (disabled by default) * nfs (depends on rust availability) * ikev2 (depends on rust availability) +* krb5 (depends on rust availability) * ntp (depends on rust availability) The availability of these protocols depends on whether the protocol is enabled in the configuration file suricata.yaml. diff --git a/rust/src/krb/krb5.rs b/rust/src/krb/krb5.rs index b3f70fbb77..6e11b840b9 100644 --- a/rust/src/krb/krb5.rs +++ b/rust/src/krb/krb5.rs @@ -20,7 +20,7 @@ use libc; use std; use std::ffi::{CStr,CString}; -use nom::IResult; +use nom::{IResult,be_u32}; use der_parser::der_read_element_header; use kerberos_parser::krb5_parser; use kerberos_parser::krb5::{EncryptionType,MessageType,PrincipalName,Realm}; @@ -410,6 +410,24 @@ pub extern "C" fn rs_krb5_probing_parser(_flow: *const Flow, input:*const libc:: } } +#[no_mangle] +pub extern "C" fn rs_krb5_probing_parser_tcp(_flow: *const Flow, input:*const libc::uint8_t, input_len: u32, _offset: *const u32) -> AppProto { + let slice = build_slice!(input,input_len as usize); + if slice.len() <= 14 { return unsafe{ALPROTO_FAILED}; } + match be_u32(slice) { + IResult::Done(rem, record_mark) => { + if record_mark != rem.len() as u32 { return unsafe{ALPROTO_FAILED}; } + return rs_krb5_probing_parser(_flow, rem.as_ptr(), rem.len() as u32, _offset); + }, + IResult::Incomplete(_) => { + return ALPROTO_UNKNOWN; + }, + IResult::Error(_) => { + return unsafe{ALPROTO_FAILED}; + }, + } +} + #[no_mangle] pub extern "C" fn rs_krb5_parse_request(_flow: *const core::Flow, state: *mut libc::c_void, @@ -434,13 +452,41 @@ pub extern "C" fn rs_krb5_parse_response(_flow: *const core::Flow, state.parse(buf, STREAM_TOCLIENT) } +#[no_mangle] +pub extern "C" fn rs_krb5_parse_request_tcp(_flow: *const core::Flow, + state: *mut libc::c_void, + _pstate: *mut libc::c_void, + input: *const libc::uint8_t, + input_len: u32, + _data: *const libc::c_void) -> i8 { + if input_len < 4 { return -1; } + let buf = build_slice!(input,input_len as usize); + let state = cast_pointer!(state,KRB5State); + // skip the record mark + state.parse(&buf[4..], STREAM_TOSERVER) +} + +#[no_mangle] +pub extern "C" fn rs_krb5_parse_response_tcp(_flow: *const core::Flow, + state: *mut libc::c_void, + _pstate: *mut libc::c_void, + input: *const libc::uint8_t, + input_len: u32, + _data: *const libc::c_void) -> i8 { + if input_len < 4 { return -1; } + let buf = build_slice!(input,input_len as usize); + let state = cast_pointer!(state,KRB5State); + // skip the record mark + state.parse(&buf[4..], STREAM_TOCLIENT) +} + const PARSER_NAME : &'static [u8] = b"krb5\0"; #[no_mangle] pub unsafe extern "C" fn rs_register_krb5_parser() { let default_port = CString::new("88").unwrap(); - let parser = RustParser { + let mut parser = RustParser { name : PARSER_NAME.as_ptr() as *const libc::c_char, default_port : default_port.as_ptr(), ipproto : libc::IPPROTO_UDP, @@ -469,6 +515,7 @@ pub unsafe extern "C" fn rs_register_krb5_parser() { set_tx_mpm_id : None, get_files : None, }; + // register UDP parser let ip_proto_str = CString::new("udp").unwrap(); if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let alproto = AppLayerRegisterProtocolDetection(&parser, 1); @@ -478,6 +525,23 @@ pub unsafe extern "C" fn rs_register_krb5_parser() { let _ = AppLayerRegisterParser(&parser, alproto); } } else { - SCLogDebug!("Protocol detecter and parser disabled for KRB5."); + SCLogDebug!("Protocol detecter and parser disabled for KRB5/UDP."); + } + // register TCP parser + parser.ipproto = libc::IPPROTO_TCP; + parser.probe_ts = rs_krb5_probing_parser_tcp; + parser.probe_tc = rs_krb5_probing_parser_tcp; + parser.parse_ts = rs_krb5_parse_request_tcp; + parser.parse_tc = rs_krb5_parse_response_tcp; + let ip_proto_str = CString::new("tcp").unwrap(); + if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { + let alproto = AppLayerRegisterProtocolDetection(&parser, 1); + // store the allocated ID for the probe function + ALPROTO_KRB5 = alproto; + if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { + let _ = AppLayerRegisterParser(&parser, alproto); + } + } else { + SCLogDebug!("Protocol detecter and parser disabled for KRB5/TCP."); } } diff --git a/src/output-json-krb5.c b/src/output-json-krb5.c index 84b592c48e..08ddb109bf 100644 --- a/src/output-json-krb5.c +++ b/src/output-json-krb5.c @@ -128,6 +128,7 @@ static OutputInitResult OutputKRB5LogInitSub(ConfNode *conf, SCLogDebug("KRB5 log sub-module initialized."); + AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_KRB5); AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_KRB5); result.ctx = output_ctx;