/* Copyright (C) 2020-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * version 2 along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ // Author: Frank Honza use nom7::bytes::streaming::tag; use nom7::bytes::streaming::take; use nom7::combinator::map_res; use nom7::number::streaming::*; use nom7::*; use std::fmt; use std::str; #[derive(Debug, PartialEq)] pub enum RFBGlobalState { TCServerProtocolVersion, TCSupportedSecurityTypes, TCVncChallenge, TCServerInit, TCFailureReason, TSClientProtocolVersion, TCServerSecurityType, TSSecurityTypeSelection, TSVncResponse, TCSecurityResult, TSClientInit, Skip, } impl fmt::Display for RFBGlobalState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { RFBGlobalState::TCServerProtocolVersion => write!(f, "TCServerProtocolVersion"), RFBGlobalState::TCSupportedSecurityTypes => write!(f, "TCSupportedSecurityTypes"), RFBGlobalState::TCVncChallenge => write!(f, "TCVncChallenge"), RFBGlobalState::TCServerInit => write!(f, "TCServerInit"), RFBGlobalState::TCFailureReason => write!(f, "TCFailureReason"), RFBGlobalState::TSClientProtocolVersion => write!(f, "TSClientProtocolVersion"), RFBGlobalState::TSSecurityTypeSelection => write!(f, "TSSecurityTypeSelection"), RFBGlobalState::TSVncResponse => write!(f, "TSVncResponse"), RFBGlobalState::TCSecurityResult => write!(f, "TCSecurityResult"), RFBGlobalState::TCServerSecurityType => write!(f, "TCServerSecurityType"), RFBGlobalState::TSClientInit => write!(f, "TSClientInit"), RFBGlobalState::Skip => write!(f, "Skip"), } } } pub struct ProtocolVersion { pub major: String, pub minor: String, } pub struct SupportedSecurityTypes { pub number_of_types: u8, pub types: Vec, } pub struct SecurityTypeSelection { pub security_type: u8, } pub struct ServerSecurityType { pub security_type: u32, } pub struct SecurityResult { pub status: u32, } pub struct FailureReason { pub reason_string: String, } pub struct VncAuth { pub secret: Vec, } pub struct ClientInit { pub shared: u8, } pub struct PixelFormat { pub bits_per_pixel: u8, pub depth: u8, pub big_endian_flag: u8, pub true_colour_flag: u8, pub red_max: u16, pub green_max: u16, pub blue_max: u16, pub red_shift: u8, pub green_shift: u8, pub blue_shift: u8, } pub struct ServerInit { pub width: u16, pub height: u16, pub pixel_format: PixelFormat, pub name_length: u32, pub name: Vec, } pub fn parse_protocol_version(i: &[u8]) -> IResult<&[u8], ProtocolVersion> { let (i, _) = tag("RFB ")(i)?; let (i, major) = map_res(take(3_usize), str::from_utf8)(i)?; let (i, _) = tag(".")(i)?; let (i, minor) = map_res(take(3_usize), str::from_utf8)(i)?; let (i, _) = tag("\n")(i)?; Ok(( i, ProtocolVersion { major: major.to_string(), minor: minor.to_string(), }, )) } pub fn parse_supported_security_types(i: &[u8]) -> IResult<&[u8], SupportedSecurityTypes> { let (i, number_of_types) = be_u8(i)?; let (i, types) = take(number_of_types as usize)(i)?; Ok(( i, SupportedSecurityTypes { number_of_types, types: types.to_vec(), }, )) } pub fn parse_server_security_type(i: &[u8]) -> IResult<&[u8], ServerSecurityType> { let (i, security_type) = be_u32(i)?; Ok((i, ServerSecurityType { security_type })) } pub fn parse_vnc_auth(i: &[u8]) -> IResult<&[u8], VncAuth> { let (i, secret) = take(16_usize)(i)?; Ok(( i, VncAuth { secret: secret.to_vec(), }, )) } pub fn parse_security_type_selection(i: &[u8]) -> IResult<&[u8], SecurityTypeSelection> { let (i, security_type) = be_u8(i)?; Ok((i, SecurityTypeSelection { security_type })) } pub fn parse_security_result(i: &[u8]) -> IResult<&[u8], SecurityResult> { let (i, status) = be_u32(i)?; Ok((i, SecurityResult { status })) } pub fn parse_failure_reason(i: &[u8]) -> IResult<&[u8], FailureReason> { let (i, reason_length) = be_u32(i)?; let (i, reason_string) = map_res(take(reason_length as usize), str::from_utf8)(i)?; Ok(( i, FailureReason { reason_string: reason_string.to_string(), }, )) } pub fn parse_client_init(i: &[u8]) -> IResult<&[u8], ClientInit> { let (i, shared) = be_u8(i)?; Ok((i, ClientInit { shared })) } pub fn parse_pixel_format(i: &[u8]) -> IResult<&[u8], PixelFormat> { let (i, bits_per_pixel) = be_u8(i)?; let (i, depth) = be_u8(i)?; let (i, big_endian_flag) = be_u8(i)?; let (i, true_colour_flag) = be_u8(i)?; let (i, red_max) = be_u16(i)?; let (i, green_max) = be_u16(i)?; let (i, blue_max) = be_u16(i)?; let (i, red_shift) = be_u8(i)?; let (i, green_shift) = be_u8(i)?; let (i, blue_shift) = be_u8(i)?; let (i, _) = take(3_usize)(i)?; let format = PixelFormat { bits_per_pixel, depth, big_endian_flag, true_colour_flag, red_max, green_max, blue_max, red_shift, green_shift, blue_shift, }; Ok((i, format)) } pub fn parse_server_init(i: &[u8]) -> IResult<&[u8], ServerInit> { let (i, width) = be_u16(i)?; let (i, height) = be_u16(i)?; let (i, pixel_format) = parse_pixel_format(i)?; let (i, name_length) = be_u32(i)?; let (i, name) = take(name_length as usize)(i)?; let init = ServerInit { width, height, pixel_format, name_length, name: name.to_vec(), }; Ok((i, init)) } #[cfg(test)] mod tests { use super::*; /// Simple test of some valid data. #[test] fn test_parse_version() { let buf = b"RFB 003.008\n"; let result = parse_protocol_version(buf); match result { Ok((remainder, message)) => { // Check the first message. assert_eq!(message.major, "003"); // And we should have 0 bytes left. assert_eq!(remainder.len(), 0); } Err(Err::Incomplete(_)) => { panic!("Result should not have been incomplete."); } Err(Err::Error(err)) | Err(Err::Failure(err)) => { panic!("Result should not be an error: {:?}.", err); } } } #[test] fn test_parse_server_init() { let buf = [ 0x05, 0x00, 0x03, 0x20, 0x20, 0x18, 0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x61, 0x6e, 0x65, 0x61, 0x67, 0x6c, 0x65, 0x73, 0x40, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, ]; let result = parse_server_init(&buf); match result { Ok((remainder, message)) => { // Check the first message. assert_eq!(message.width, 1280); assert_eq!(message.height, 800); assert_eq!(message.pixel_format.bits_per_pixel, 32); // And we should have 0 bytes left. assert_eq!(remainder.len(), 0); } Err(Err::Incomplete(_)) => { panic!("Result should not have been incomplete."); } Err(Err::Error(err)) | Err(Err::Failure(err)) => { panic!("Result should not be an error: {:?}.", err); } } } #[test] fn test_parse_pixel_format() { let buf = [ 0x20, /* Bits per pixel: 32 */ 0x18, /* Depth: 24 */ 0x00, /* Big endian flag: False */ 0x01, /* True color flag: True */ 0x00, 0xff, /* Red maximum: 255 */ 0x00, 0xff, /* Green maximum: 255 */ 0x00, 0xff, /* Blue maximum: 255 */ 0x10, /* Red shift: 16 */ 0x08, /* Green shift: 8 */ 0x00, /* Blue shift: 0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0, ]; let result = parse_pixel_format(&buf); match result { Ok((remainder, message)) => { assert_eq!(message.bits_per_pixel, 32); assert_eq!(message.depth, 24); assert_eq!(message.big_endian_flag, 0); assert_eq!(message.true_colour_flag, 1); assert_eq!(message.red_max, 255); assert_eq!(message.green_max, 255); assert_eq!(message.blue_max, 255); assert_eq!(message.red_shift, 16); assert_eq!(message.green_shift, 8); assert_eq!(message.blue_shift, 0); assert_eq!(remainder.len(), 5); } Err(Err::Incomplete(_)) => { panic!("Result should not have been incomplete."); } Err(Err::Error(err)) | Err(Err::Failure(err)) => { panic!("Result should not be an error: {:?}.", err); } } } #[test] fn test_parse_supported_security_types() { let buf = [ 0x01, /* Number of security types: 1 */ 0x02, /* Security type: VNC (2) */ 0x00, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa0, ]; let result = parse_supported_security_types(&buf); match result { Ok((remainder, message)) => { assert_eq!(message.number_of_types, 1); assert_eq!(message.types[0], 2); assert_eq!(remainder.len(), 19); } Err(Err::Incomplete(_)) => { panic!("Result should not have been incomplete."); } Err(Err::Error(err)) | Err(Err::Failure(err)) => { panic!("Result should not be an error: {:?}.", err); } } } #[test] fn test_parse_vnc_auth() { let buf = [ 0x54, 0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a, 0x4e, 0xc5, /* Authentication challenge: 547b7a6f36a154db03a2575c6f2a4ec5 */ 0x00, 0x00, 0x00, 0x01, 0xa0, ]; let result = parse_vnc_auth(&buf); match result { Ok((remainder, message)) => { assert_eq!( hex::encode(message.secret), "547b7a6f36a154db03a2575c6f2a4ec5" ); assert_eq!(remainder.len(), 5); } Err(Err::Incomplete(_)) => { panic!("Result should not have been incomplete."); } Err(Err::Error(err)) | Err(Err::Failure(err)) => { panic!("Result should not be an error: {:?}.", err); } } } #[test] fn test_parse_client_init() { let buf = [ 0x00, /*Share desktop flag: False*/ 0x7b, 0x7a, 0x6f, 0x36, 0xa1, 0x54, 0xdb, 0x03, 0xa2, 0x57, 0x5c, 0x6f, 0x2a, 0x4e, 0xc5, 0x00, 0x00, 0x00, 0x01, 0xa0, ]; let result = parse_client_init(&buf); match result { Ok((remainder, message)) => { assert_eq!(message.shared, 0); assert_eq!(remainder.len(), 20); } Err(Err::Incomplete(_)) => { panic!("Result should not have been incomplete."); } Err(Err::Error(err)) | Err(Err::Failure(err)) => { panic!("Result should not be an error: {:?}.", err); } } } }