1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Winshock Vulnerability Test
// MS14-066, CVE-2014-6321
//
// Winshock is a vulnerability in Microsoft's Schannel (Windows TLS/SSL implementation)
// that allows remote code execution. The vulnerability exists in how Schannel processes
// specially crafted TLS packets during the handshake phase.
use crate::Result;
use crate::protocols::Protocol;
use crate::protocols::handshake::ClientHelloBuilder;
use crate::utils::network::Target;
use std::time::Duration;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio::time::timeout;
/// Winshock vulnerability tester
pub struct WinshockTester {
target: Target,
}
impl WinshockTester {
pub fn new(target: Target) -> Self {
Self { target }
}
/// Test for Winshock vulnerability
pub async fn test(&self) -> Result<WinshockTestResult> {
let schannel_detected = self.detect_schannel().await?;
let vulnerable = if schannel_detected {
self.test_malformed_handshake().await?
} else {
false
};
let details = if vulnerable {
"Vulnerable to Winshock (MS14-066, CVE-2014-6321) - Server crashes or behaves abnormally with malformed handshake".to_string()
} else if schannel_detected {
"Schannel detected but Winshock test passed - Likely patched or protected".to_string()
} else {
"Not vulnerable - Schannel not detected".to_string()
};
Ok(WinshockTestResult {
vulnerable,
schannel_detected,
details,
})
}
/// Detect if server is using Microsoft Schannel
async fn detect_schannel(&self) -> Result<bool> {
use openssl::ssl::{SslConnector, SslMethod};
let addr = self.target.socket_addrs()[0];
match timeout(Duration::from_secs(5), TcpStream::connect(addr)).await {
Ok(Ok(stream)) => {
let std_stream = stream.into_std()?;
std_stream.set_nonblocking(false)?;
let connector = SslConnector::builder(SslMethod::tls())?.build();
match connector.connect(&self.target.hostname, std_stream) {
Ok(ssl_stream) => {
// Check cipher and version patterns typical of Schannel
let cipher = ssl_stream
.ssl()
.current_cipher()
.map(|c| c.name().to_string())
.unwrap_or_default();
// Schannel has specific cipher preferences
let schannel_ciphers = [
"ECDHE-RSA-AES256-SHA384",
"ECDHE-RSA-AES128-SHA256",
"AES256-SHA256",
"AES128-SHA256",
];
let likely_schannel =
schannel_ciphers.iter().any(|&sc| cipher.contains(sc));
Ok(likely_schannel)
}
Err(_) => Ok(false),
}
}
_ => Ok(false),
}
}
/// Test with malformed handshake that triggers Winshock
async fn test_malformed_handshake(&self) -> Result<bool> {
let addr = self.target.socket_addrs()[0];
match timeout(Duration::from_secs(5), TcpStream::connect(addr)).await {
Ok(Ok(mut stream)) => {
// Send normal ClientHello first
let client_hello = self.build_client_hello();
stream.write_all(&client_hello).await?;
// Read ServerHello
let mut buffer = vec![0u8; 8192];
match timeout(Duration::from_secs(3), stream.read(&mut buffer)).await {
Ok(Ok(n)) if n > 0 => {
// Send malformed ClientKeyExchange that triggers Winshock
let malformed_cke = self.build_malformed_client_key_exchange();
stream.write_all(&malformed_cke).await?;
// Try to read response
let mut response = vec![0u8; 1024];
match timeout(Duration::from_secs(2), stream.read(&mut response)).await {
Ok(Ok(_)) => {
// Server responded - check for crash indicator
// Connection reset indicates potential vulnerability
Ok(false)
}
Ok(Err(_)) => {
// Connection error might indicate crash
Ok(true)
}
Err(_) => Ok(false), // Timeout
}
}
_ => Ok(false),
}
}
_ => Ok(false),
}
}
/// Build standard ClientHello using ClientHelloBuilder
fn build_client_hello(&self) -> Vec<u8> {
let mut builder = ClientHelloBuilder::new(Protocol::TLS12);
builder.for_rsa_key_exchange();
builder.build_minimal().unwrap_or_else(|_| Vec::new())
}
/// Build malformed ClientKeyExchange that triggers Winshock
fn build_malformed_client_key_exchange(&self) -> Vec<u8> {
let mut msg = vec![
0x16, 0x03, 0x03, // TLS Record: Handshake (TLS 1.2)
0xff, 0xff, // Malformed length (triggers vulnerability)
0x10, // Handshake: ClientKeyExchange
0xff, 0xff, 0xff, // Malformed handshake length
0xff, 0xff, // Encrypted PMS with malformed length
];
// Crafted payload that triggers buffer overflow in Schannel
// This is a simplified version - real exploit would be more sophisticated
msg.extend_from_slice(&[0x41; 256]); // 'A' pattern
msg
}
}
/// Winshock test result
#[derive(Debug, Clone)]
pub struct WinshockTestResult {
pub vulnerable: bool,
pub schannel_detected: bool,
pub details: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_winshock_result() {
let result = WinshockTestResult {
vulnerable: false,
schannel_detected: true,
details: "Test".to_string(),
};
assert!(!result.vulnerable);
assert!(result.schannel_detected);
}
#[test]
fn test_malformed_cke_build() {
let target = Target::with_ips(
"example.com".to_string(),
443,
vec!["93.184.216.34".parse().unwrap()],
)
.unwrap();
let tester = WinshockTester::new(target);
let malformed = tester.build_malformed_client_key_exchange();
assert!(malformed.len() > 10);
assert_eq!(malformed[0], 0x16); // Handshake record
assert_eq!(malformed[5], 0x10); // ClientKeyExchange
}
}