1 /* Copyright (C) 2019 Open Information Security Foundation
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // Author: Zach Kelly <zach.kelly@lmco.com>
20 //! RDP application layer
22 use crate::applayer::{self, *};
23 use crate::core::{AppProto, Flow, ALPROTO_UNKNOWN, IPPROTO_TCP};
24 use crate::rdp::parser::*;
27 use tls_parser::{parse_tls_plaintext, TlsMessage, TlsMessageHandshake, TlsRecordType};
29 static mut ALPROTO_RDP: AppProto = ALPROTO_UNKNOWN;
35 #[derive(Debug, PartialEq)]
36 pub struct CertificateBlob {
40 #[derive(Debug, PartialEq)]
41 pub enum RdpTransactionItem {
42 X224ConnectionRequest(X224ConnectionRequest),
43 X224ConnectionConfirm(X224ConnectionConfirm),
44 McsConnectRequest(McsConnectRequest),
45 McsConnectResponse(McsConnectResponse),
46 TlsCertificateChain(Vec<CertificateBlob>),
49 #[derive(Debug, PartialEq)]
50 pub struct RdpTransaction {
52 pub item: RdpTransactionItem,
53 // managed by macros `export_tx_get_detect_state!` and `export_tx_set_detect_state!`
54 tx_data: AppLayerTxData,
57 impl Transaction for RdpTransaction {
64 fn new(id: u64, item: RdpTransactionItem) -> Self {
68 tx_data: AppLayerTxData::new(),
74 pub unsafe extern "C" fn rs_rdp_state_get_tx(
75 state: *mut std::os::raw::c_void, tx_id: u64,
76 ) -> *mut std::os::raw::c_void {
77 let state = cast_pointer!(state, RdpState);
78 match state.get_tx(tx_id) {
80 return tx as *const _ as *mut _;
83 return std::ptr::null_mut();
89 pub unsafe extern "C" fn rs_rdp_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
90 let state = cast_pointer!(state, RdpState);
95 pub extern "C" fn rs_rdp_tx_get_progress(
96 _tx: *mut std::os::raw::c_void, _direction: u8,
97 ) -> std::os::raw::c_int {
98 // tx complete when `rs_rdp_tx_get_progress(...) == rs_rdp_tx_get_progress_complete(...)`
99 // here, all transactions are immediately complete on insert
107 #[derive(Debug, PartialEq)]
108 pub struct RdpState {
110 transactions: Vec<RdpTransaction>,
112 bypass_parsing: bool,
115 impl State<RdpTransaction> for RdpState {
116 fn get_transactions(&self) -> &[RdpTransaction] {
125 transactions: Vec::new(),
127 bypass_parsing: false,
131 fn free_tx(&mut self, tx_id: u64) {
132 let len = self.transactions.len();
133 let mut found = false;
136 let tx = &self.transactions[ii];
144 self.transactions.remove(index);
148 fn get_tx(&self, tx_id: u64) -> Option<&RdpTransaction> {
149 for tx in &self.transactions {
157 fn new_tx(&mut self, item: RdpTransactionItem) -> RdpTransaction {
159 let tx = RdpTransaction::new(self.next_id, item);
163 /// parse buffer captures from client to server
164 fn parse_ts(&mut self, input: &[u8]) -> AppLayerResult {
165 // no need to process input buffer
166 if self.bypass_parsing {
167 return AppLayerResult::ok();
169 let mut available = input;
172 if available.len() == 0 {
173 return AppLayerResult::ok();
175 if self.tls_parsing {
176 match parse_tls_plaintext(available) {
177 Ok((remainder, _tls)) => {
178 // bytes available for futher parsing are what remain
179 available = remainder;
182 Err(nom::Err::Incomplete(_)) => {
183 // nom need not compatible with applayer need, request one more byte
184 return AppLayerResult::incomplete(
185 (input.len() - available.len()) as u32,
186 (available.len() + 1) as u32,
190 Err(nom::Err::Failure(_)) | Err(nom::Err::Error(_)) => {
191 return AppLayerResult::err();
195 // every message should be encapsulated within a T.123 tpkt
196 match parse_t123_tpkt(available) {
198 Ok((remainder, t123)) => {
199 // bytes available for futher parsing are what remain
200 available = remainder;
201 // evaluate message within the tpkt
203 // X.224 connection request
204 T123TpktChild::X224ConnectionRequest(x224) => {
206 self.new_tx(RdpTransactionItem::X224ConnectionRequest(x224));
207 self.transactions.push(tx);
210 // X.223 data packet, evaluate what it encapsulates
211 T123TpktChild::Data(x223) => {
213 X223DataChild::McsConnectRequest(mcs) => {
215 self.new_tx(RdpTransactionItem::McsConnectRequest(mcs));
216 self.transactions.push(tx);
218 // unknown message in X.223, skip
223 // unknown message in T.123, skip
228 Err(nom::Err::Incomplete(_)) => {
229 // nom need not compatible with applayer need, request one more byte
230 return AppLayerResult::incomplete(
231 (input.len() - available.len()) as u32,
232 (available.len() + 1) as u32,
236 Err(nom::Err::Failure(_)) | Err(nom::Err::Error(_)) => {
237 if probe_tls_handshake(available) {
238 self.tls_parsing = true;
239 let r = self.parse_ts(available);
241 //adds bytes already consumed to incomplete result
242 let consumed = (input.len() - available.len()) as u32;
243 return AppLayerResult::incomplete(r.consumed + consumed, r.needed);
248 return AppLayerResult::err();
256 /// parse buffer captures from server to client
257 fn parse_tc(&mut self, input: &[u8]) -> AppLayerResult {
258 // no need to process input buffer
259 if self.bypass_parsing {
260 return AppLayerResult::ok();
262 let mut available = input;
265 if available.len() == 0 {
266 return AppLayerResult::ok();
268 if self.tls_parsing {
269 match parse_tls_plaintext(available) {
270 Ok((remainder, tls)) => {
271 // bytes available for futher parsing are what remain
272 available = remainder;
273 for message in &tls.msg {
275 TlsMessage::Handshake(TlsMessageHandshake::Certificate(
278 let mut chain = Vec::new();
279 for cert in &contents.cert_chain {
280 chain.push(CertificateBlob {
281 data: cert.data.to_vec(),
285 self.new_tx(RdpTransactionItem::TlsCertificateChain(chain));
286 self.transactions.push(tx);
287 self.bypass_parsing = true;
294 Err(nom::Err::Incomplete(_)) => {
295 // nom need not compatible with applayer need, request one more byte
296 return AppLayerResult::incomplete(
297 (input.len() - available.len()) as u32,
298 (available.len() + 1) as u32,
302 Err(nom::Err::Failure(_)) | Err(nom::Err::Error(_)) => {
303 return AppLayerResult::err();
307 // every message should be encapsulated within a T.123 tpkt
308 match parse_t123_tpkt(available) {
310 Ok((remainder, t123)) => {
311 // bytes available for futher parsing are what remain
312 available = remainder;
313 // evaluate message within the tpkt
315 // X.224 connection confirm
316 T123TpktChild::X224ConnectionConfirm(x224) => {
318 self.new_tx(RdpTransactionItem::X224ConnectionConfirm(x224));
319 self.transactions.push(tx);
322 // X.223 data packet, evaluate what it encapsulates
323 T123TpktChild::Data(x223) => {
325 X223DataChild::McsConnectResponse(mcs) => {
327 .new_tx(RdpTransactionItem::McsConnectResponse(mcs));
328 self.transactions.push(tx);
329 self.bypass_parsing = true;
330 return AppLayerResult::ok();
333 // unknown message in X.223, skip
338 // unknown message in T.123, skip
343 Err(nom::Err::Incomplete(_)) => {
344 // nom need not compatible with applayer need, request one more byte
345 return AppLayerResult::incomplete(
346 (input.len() - available.len()) as u32,
347 (available.len() + 1) as u32,
351 Err(nom::Err::Failure(_)) | Err(nom::Err::Error(_)) => {
352 if probe_tls_handshake(available) {
353 self.tls_parsing = true;
354 let r = self.parse_tc(available);
356 //adds bytes already consumed to incomplete result
357 let consumed = (input.len() - available.len()) as u32;
358 return AppLayerResult::incomplete(r.consumed + consumed, r.needed);
363 return AppLayerResult::err();
373 pub extern "C" fn rs_rdp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
374 let state = RdpState::new();
375 let boxed = Box::new(state);
376 return Box::into_raw(boxed) as *mut _;
380 pub extern "C" fn rs_rdp_state_free(state: *mut std::os::raw::c_void) {
381 std::mem::drop(unsafe { Box::from_raw(state as *mut RdpState) });
385 pub unsafe extern "C" fn rs_rdp_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
386 let state = cast_pointer!(state, RdpState);
387 state.free_tx(tx_id);
394 /// probe for T.123 type identifier, as each message is encapsulated in T.123
395 fn probe_rdp(input: &[u8]) -> bool {
396 input.len() > 0 && input[0] == TpktVersion::T123 as u8
399 /// probe for T.123 message, whether to client or to server
401 pub unsafe extern "C" fn rs_rdp_probe_ts_tc(
402 _flow: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
404 if !input.is_null() {
405 // probe bytes for `rdp` protocol pattern
406 let slice = build_slice!(input, input_len as usize);
408 // Some sessions immediately (first byte) switch to TLS/SSL, e.g.
409 // https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=view&target=rdp-ssl.pcap.gz
410 // but this callback will not be exercised, so `probe_tls_handshake` not needed here.
411 if probe_rdp(slice) {
415 return ALPROTO_UNKNOWN;
419 fn probe_tls_handshake(input: &[u8]) -> bool {
420 input.len() > 0 && input[0] == u8::from(TlsRecordType::Handshake)
428 pub unsafe extern "C" fn rs_rdp_parse_ts(
429 _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
430 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
431 ) -> AppLayerResult {
432 let state = cast_pointer!(state, RdpState);
433 let buf = build_slice!(input, input_len as usize);
434 // attempt to parse bytes as `rdp` protocol
435 return state.parse_ts(buf);
439 pub unsafe extern "C" fn rs_rdp_parse_tc(
440 _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
441 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
442 ) -> AppLayerResult {
443 let state = cast_pointer!(state, RdpState);
444 let buf = build_slice!(input, input_len as usize);
445 // attempt to parse bytes as `rdp` protocol
446 return state.parse_tc(buf);
449 export_tx_data_get!(rs_rdp_get_tx_data, RdpTransaction);
455 const PARSER_NAME: &'static [u8] = b"rdp\0";
458 pub unsafe extern "C" fn rs_rdp_register_parser() {
459 let default_port = std::ffi::CString::new("[3389]").unwrap();
460 let parser = RustParser {
461 name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
462 default_port: default_port.as_ptr(),
463 ipproto: IPPROTO_TCP,
464 probe_ts: Some(rs_rdp_probe_ts_tc),
465 probe_tc: Some(rs_rdp_probe_ts_tc),
468 state_new: rs_rdp_state_new,
469 state_free: rs_rdp_state_free,
470 tx_free: rs_rdp_state_tx_free,
471 parse_ts: rs_rdp_parse_ts,
472 parse_tc: rs_rdp_parse_tc,
473 get_tx_count: rs_rdp_state_get_tx_count,
474 get_tx: rs_rdp_state_get_tx,
477 tx_get_progress: rs_rdp_tx_get_progress,
479 get_eventinfo_byid: None,
480 localstorage_new: None,
481 localstorage_free: None,
483 get_tx_iterator: Some(applayer::state_get_tx_iterator::<RdpState, RdpTransaction>),
484 get_tx_data: rs_rdp_get_tx_data,
485 apply_tx_config: None,
486 flags: APP_LAYER_PARSER_OPT_UNIDIR_TXS,
490 let ip_proto_str = std::ffi::CString::new("tcp").unwrap();
492 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
493 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
494 ALPROTO_RDP = alproto;
495 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
496 let _ = AppLayerRegisterParser(&parser, alproto);
504 use crate::rdp::parser::{RdpCookie, X224ConnectionRequest};
507 fn test_probe_rdp() {
508 let buf: &[u8] = &[0x03, 0x00];
509 assert_eq!(true, probe_rdp(buf));
513 fn test_probe_rdp_other() {
514 let buf: &[u8] = &[0x04, 0x00];
515 assert_eq!(false, probe_rdp(buf));
519 fn test_probe_tls_handshake() {
520 let buf: &[u8] = &[0x16, 0x00];
521 assert_eq!(true, probe_tls_handshake(buf));
525 fn test_probe_tls_handshake_other() {
526 let buf: &[u8] = &[0x17, 0x00];
527 assert_eq!(false, probe_tls_handshake(buf));
531 fn test_parse_ts_rdp() {
532 let buf_1: &[u8] = &[0x03, 0x00, 0x00, 0x25, 0x20, 0xe0, 0x00, 0x00];
533 let buf_2: &[u8] = &[
534 0x03, 0x00, 0x00, 0x25, 0x20, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6f,
535 0x6b, 0x69, 0x65, 0x3a, 0x20, 0x6d, 0x73, 0x74, 0x73, 0x68, 0x61, 0x73, 0x68, 0x3d,
536 0x75, 0x73, 0x65, 0x72, 0x31, 0x32, 0x33, 0x0d, 0x0a,
538 let mut state = RdpState::new();
539 // will consume 0, request length + 1
540 assert_eq!(AppLayerResult::incomplete(0, 9), state.parse_ts(buf_1));
541 assert_eq!(0, state.transactions.len());
542 // exactly aligns with transaction
543 assert_eq!(AppLayerResult::ok(), state.parse_ts(buf_2));
544 assert_eq!(1, state.transactions.len());
545 let item = RdpTransactionItem::X224ConnectionRequest(X224ConnectionRequest {
551 cookie: Some(RdpCookie {
552 mstshash: String::from("user123"),
554 negotiation_request: None,
557 assert_eq!(item, state.transactions[0].item);
561 fn test_parse_ts_other() {
562 let buf: &[u8] = &[0x03, 0x00, 0x00, 0x01, 0x00];
563 let mut state = RdpState::new();
564 assert_eq!(AppLayerResult::err(), state.parse_ts(buf));
568 fn test_parse_tc_rdp() {
569 let buf_1: &[u8] = &[0x03, 0x00, 0x00, 0x09, 0x02];
570 let buf_2: &[u8] = &[0x03, 0x00, 0x00, 0x09, 0x02, 0xf0, 0x80, 0x7f, 0x66];
571 let mut state = RdpState::new();
572 // will consume 0, request length + 1
573 assert_eq!(AppLayerResult::incomplete(0, 6), state.parse_tc(buf_1));
574 assert_eq!(0, state.transactions.len());
575 // exactly aligns with transaction
576 assert_eq!(AppLayerResult::ok(), state.parse_tc(buf_2));
577 assert_eq!(1, state.transactions.len());
578 let item = RdpTransactionItem::McsConnectResponse(McsConnectResponse {});
579 assert_eq!(item, state.transactions[0].item);
583 fn test_parse_tc_other() {
584 let buf: &[u8] = &[0x03, 0x00, 0x00, 0x01, 0x00];
585 let mut state = RdpState::new();
586 assert_eq!(AppLayerResult::err(), state.parse_tc(buf));
590 fn test_state_new_tx() {
591 let mut state = RdpState::new();
592 let item0 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
593 children: Vec::new(),
595 let item1 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
596 children: Vec::new(),
598 let tx0 = state.new_tx(item0);
599 let tx1 = state.new_tx(item1);
600 assert_eq!(2, state.next_id);
601 state.transactions.push(tx0);
602 state.transactions.push(tx1);
603 assert_eq!(2, state.transactions.len());
604 assert_eq!(1, state.transactions[0].id);
605 assert_eq!(2, state.transactions[1].id);
606 assert_eq!(false, state.tls_parsing);
607 assert_eq!(false, state.bypass_parsing);
611 fn test_state_get_tx() {
612 let mut state = RdpState::new();
613 let item0 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
614 children: Vec::new(),
616 let item1 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
617 children: Vec::new(),
619 let item2 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
620 children: Vec::new(),
622 let tx0 = state.new_tx(item0);
623 let tx1 = state.new_tx(item1);
624 let tx2 = state.new_tx(item2);
625 state.transactions.push(tx0);
626 state.transactions.push(tx1);
627 state.transactions.push(tx2);
628 assert_eq!(Some(&state.transactions[1]), state.get_tx(2));
632 fn test_state_free_tx() {
633 let mut state = RdpState::new();
634 let item0 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
635 children: Vec::new(),
637 let item1 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
638 children: Vec::new(),
640 let item2 = RdpTransactionItem::McsConnectRequest(McsConnectRequest {
641 children: Vec::new(),
643 let tx0 = state.new_tx(item0);
644 let tx1 = state.new_tx(item1);
645 let tx2 = state.new_tx(item2);
646 state.transactions.push(tx0);
647 state.transactions.push(tx1);
648 state.transactions.push(tx2);
650 assert_eq!(3, state.next_id);
651 assert_eq!(2, state.transactions.len());
652 assert_eq!(2, state.transactions[0].id);
653 assert_eq!(3, state.transactions[1].id);
654 assert_eq!(None, state.get_tx(1));