diff --git a/CHANGELOG.md b/CHANGELOG.md index f285931..360b9d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 0.1.1 (2020-04-11) +#### Features +* Remove dependency of rust-crypto +* Fix parameter name +* Fix overflow in packet computation + ### 0.1.0 (2020-04-11) #### Features * Initial release \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 429f332..07d020c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,6 @@ md4 = "^0.8" hmac = "^0.7" md-5 = "^0.8" rand = "^0.7" -rust-crypto = "^0.2" num-bigint = "^0.2" x509-parser = "0.6.5" num_enum = "0.4.3" diff --git a/src/bin/mstsc-rs.rs b/src/bin/mstsc-rs.rs index cf92562..e9328e1 100644 --- a/src/bin/mstsc-rs.rs +++ b/src/bin/mstsc-rs.rs @@ -231,7 +231,7 @@ fn to_scancode(key: Key) -> u16 { /// Create a tcp stream from main args fn tcp_from_args(args: &ArgMatches) -> RdpResult { - let ip = args.value_of("target").expect("You need to provide a target argument"); + let ip = args.value_of("host").expect("You need to provide a target argument"); let port = args.value_of("port").unwrap_or_default(); // TCP connection @@ -449,10 +449,10 @@ fn main() { .version("0.1.0") .author("Sylvain Peyrefitte ") .about("Secure Remote Desktop Client in RUST") - .arg(Arg::with_name("target") - .long("target") + .arg(Arg::with_name("host") + .long("host") .takes_value(true) - .help("Target IP of the server")) + .help("host IP of the target machine")) .arg(Arg::with_name("port") .long("port") .takes_value(true) @@ -469,7 +469,7 @@ fn main() { .default_value("600") .help("Screen height")) .arg(Arg::with_name("domain") - .long("dom") + .long("domain") .takes_value(true) .default_value("") .help("Windows domain")) @@ -479,7 +479,7 @@ fn main() { .default_value("") .help("Username")) .arg(Arg::with_name("password") - .long("pass") + .long("password") .takes_value(true) .default_value("") .help("Password")) @@ -506,7 +506,7 @@ fn main() { .help("Check the target SSL certificate")) .arg(Arg::with_name("disable_nla") .long("ssl") - .help("Disable Netwoek Level Authentication and only use SSL")) + .help("Disable Network Level Authentication and only use SSL")) .arg(Arg::with_name("name") .long("name") .default_value("mstsc-rs") diff --git a/src/core/tpkt.rs b/src/core/tpkt.rs index b4027ad..8651c47 100644 --- a/src/core/tpkt.rs +++ b/src/core/tpkt.rs @@ -105,17 +105,17 @@ impl Client { /// panic!("unexpected result") /// } /// - /// tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![0, 6, 0, 0, 0, 0])))); + /// tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![0, 7, 0, 0, 0, 0, 0])))); /// if let tpkt::Payload::FastPath(_, c) = tpkt.read().unwrap() { - /// assert_eq!(c.into_inner(), vec![0, 0, 0, 0]) + /// assert_eq!(c.into_inner(), vec![0, 0, 0, 0, 0]) /// } /// else { /// panic!("unexpected result") /// } /// - /// tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![0, 0x80, 7, 0, 0, 0, 0])))); + /// tpkt = tpkt::Client::new(link::Link::new(link::Stream::Raw(Cursor::new(vec![0, 0x80, 8, 0, 0, 0, 0, 0])))); /// if let tpkt::Payload::FastPath(_, c) = tpkt.read().unwrap() { - /// assert_eq!(c.into_inner(), vec![0, 0, 0, 0]) + /// assert_eq!(c.into_inner(), vec![0, 0, 0, 0, 0]) /// } /// else { /// panic!("unexpected result") @@ -136,9 +136,15 @@ impl Client { let mut size = U16::BE(0); size.read(&mut buffer)?; - // now wait for body - Ok(Payload::Raw(Cursor::new(self.transport.read(size.inner() as usize - 4)?))) - + // Minimal size must be 7 + // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/18a27ef9-6f9a-4501-b000-94b1fe3c2c10 + if size.inner() < 7 { + Err(Error::RdpError(RdpError::new(RdpErrorKind::InvalidSize, "Invalid minimal size for TPKT"))) + } + else { + // now wait for body + Ok(Payload::Raw(Cursor::new(self.transport.read(size.inner() as usize - 4)?))) + } } else { // fast path let sec_flag = (action >> 6) & 0x3; @@ -147,12 +153,20 @@ impl Client { if short_length & 0x80 != 0 { let mut hi_length: u8 = 0; hi_length.read(&mut Cursor::new(self.transport.read(1)?))?; - let length :u16 = ((short_length & !0x80) as u16) << 8; + let length: u16 = ((short_length & !0x80) as u16) << 8; let length = length | hi_length as u16; - Ok(Payload::FastPath(sec_flag, Cursor::new(self.transport.read(length as usize - 3)?))) + if length < 7 { + Err(Error::RdpError(RdpError::new(RdpErrorKind::InvalidSize, "Invalid minimal size for TPKT"))) + } else { + Ok(Payload::FastPath(sec_flag, Cursor::new(self.transport.read(length as usize - 3)?))) + } } else { - Ok(Payload::FastPath(sec_flag, Cursor::new(self.transport.read(short_length as usize - 2)?))) + if short_length < 7 { + Err(Error::RdpError(RdpError::new(RdpErrorKind::InvalidSize, "Invalid minimal size for TPKT"))) + } else { + Ok(Payload::FastPath(sec_flag, Cursor::new(self.transport.read(short_length as usize - 2)?))) + } } } } @@ -210,6 +224,7 @@ mod test { use super::*; use std::io::Cursor; use model::data::{U32, DataType}; + use model::link::Stream; /// Test the tpkt header type in write context #[test] @@ -233,4 +248,29 @@ mod test { assert_eq!(cast!(DataType::U16, message["size"]).unwrap(), 8); assert_eq!(cast!(DataType::U8, message["action"]).unwrap(), Action::FastPathActionX224 as u8); } + + fn process(data: &[u8]) { + let cur = Cursor::new(data.to_vec()); + let link = Link::new(Stream::Raw(cur)); + let mut client = Client::new(link); + let _ = client.read(); + } + + #[test] + fn test_tpkt_size_overflow_case_1() { + let buf = b"\x00\x00\x03\x00\x00\x00"; + process(buf); + } + + #[test] + fn test_tpkt_size_overflow_case_2() { + let buf = b"\x00\x80\x00\x00\x00\x00"; + process(buf); + } + + #[test] + fn test_tpkt_size_overflow_case_3() { + let buf = b"\x03\xe8\x00\x00\x80\x00"; + process(buf); + } } diff --git a/src/lib.rs b/src/lib.rs index 29862d4..d636315 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ extern crate md4; extern crate hmac; extern crate md5; extern crate rand; -extern crate crypto; extern crate num_bigint; extern crate x509_parser; extern crate num_enum; diff --git a/src/nla/mod.rs b/src/nla/mod.rs index a68cc84..6b45edd 100644 --- a/src/nla/mod.rs +++ b/src/nla/mod.rs @@ -3,3 +3,4 @@ pub mod asn1; pub mod cssp; pub mod ntlm; pub mod sspi; +pub mod rc4; diff --git a/src/nla/ntlm.rs b/src/nla/ntlm.rs index bcf13a3..3680c69 100644 --- a/src/nla/ntlm.rs +++ b/src/nla/ntlm.rs @@ -7,8 +7,7 @@ use md4::{Md4, Digest}; use hmac::{Hmac, Mac}; use md5::{Md5}; use model::rnd::{random}; -use crypto::rc4::{Rc4}; -use crypto::symmetriccipher::SynchronousStreamCipher; +use nla::rc4::{Rc4}; use num_enum::TryFromPrimitive; use std::convert::TryFrom; @@ -651,9 +650,8 @@ impl NTLMv2SecurityInterface { /// /// # Example /// ```no_run - /// extern crate crypto; /// use rdp::nla::ntlm::NTLMv2SecurityInterface; - /// use crypto::rc4::Rc4; + /// use rdp::nla::rc4::Rc4; /// let interface = NTLMv2SecurityInterface::new(Rc4::new(b"encrypt"), Rc4::new(b"decrypt"), b"signing".to_vec(), b"verify".to_vec()); /// ``` pub fn new(encrypt: Rc4, decrypt: Rc4, signing_key: Vec, verify_key: Vec) -> Self { @@ -673,9 +671,8 @@ impl GenericSecurityService for NTLMv2SecurityInterface { /// /// # Example /// ``` - /// extern crate crypto; /// use rdp::nla::ntlm::NTLMv2SecurityInterface; - /// use crypto::rc4::Rc4; + /// use rdp::nla::rc4::Rc4; /// use rdp::nla::sspi::GenericSecurityService; /// let mut interface = NTLMv2SecurityInterface::new(Rc4::new(b"encrypt"), Rc4::new(b"decrypt"), b"signing".to_vec(), b"verify".to_vec()); /// assert_eq!(interface.gss_wrapex(b"foo").unwrap(), [1, 0, 0, 0, 142, 146, 37, 160, 247, 244, 100, 58, 0, 0, 0, 0, 87, 164, 208]); @@ -694,9 +691,8 @@ impl GenericSecurityService for NTLMv2SecurityInterface { /// /// # Example /// ``` - /// extern crate crypto; /// use rdp::nla::ntlm::NTLMv2SecurityInterface; - /// use crypto::rc4::Rc4; + /// use rdp::nla::rc4::Rc4; /// use rdp::nla::sspi::GenericSecurityService; /// let mut interface = NTLMv2SecurityInterface::new(Rc4::new(b"decrypt"), Rc4::new(b"encrypt"), b"verify".to_vec(), b"signing".to_vec()); /// assert_eq!(interface.gss_unwrapex(&vec![1, 0, 0, 0, 142, 146, 37, 160, 247, 244, 100, 58, 0, 0, 0, 0, 87, 164, 208]).unwrap(), b"foo"); diff --git a/src/nla/rc4.rs b/src/nla/rc4.rs new file mode 100644 index 0000000..1197a2e --- /dev/null +++ b/src/nla/rc4.rs @@ -0,0 +1,35 @@ +pub struct Rc4 { + i: u8, + j: u8, + state: [u8; 256] +} + +impl Rc4 { + pub fn new(key: &[u8]) -> Rc4 { + assert!(key.len() >= 1 && key.len() <= 256); + let mut rc4 = Rc4 { i: 0, j: 0, state: [0; 256] }; + for (i, x) in rc4.state.iter_mut().enumerate() { + *x = i as u8; + } + let mut j: u8 = 0; + for i in 0..256 { + j = j.wrapping_add(rc4.state[i]).wrapping_add(key[i % key.len()]); + rc4.state.swap(i, j as usize); + } + rc4 + } + fn next(&mut self) -> u8 { + self.i = self.i.wrapping_add(1); + self.j = self.j.wrapping_add(self.state[self.i as usize]); + self.state.swap(self.i as usize, self.j as usize); + let k = self.state[(self.state[self.i as usize].wrapping_add(self.state[self.j as usize])) as usize]; + k + } + + pub fn process(&mut self, input: &[u8], output: &mut [u8]) { + assert!(input.len() == output.len()); + for (x, y) in input.iter().zip(output.iter_mut()) { + *y = *x ^ self.next(); + } + } +} \ No newline at end of file