Imported Upstream version 1.2
Devon Kearns
11 years ago
0 | #!/usr/bin/env bash | |
1 | # | |
2 | # Tool: TLSSLed.sh | |
3 | # | |
4 | # Description: | |
5 | # Script to extract the most relevant security details from a | |
6 | # target SSL/TLS HTTPS implementation by using sslscan & openssl. | |
7 | # | |
8 | # Author: Raul Siles (raul _AT_ taddong _DOT_ com) | |
9 | # Taddong SL (www.taddong.com) | |
10 | # Date: 2011-10-18 | |
11 | # Version: 1.2 | |
12 | # | |
13 | # - New in version 1.2: | |
14 | # - Mac OS X support: sed regex switch changed - by [ anonymous ]. | |
15 | # - Test if target service speaks SSL/TLS - by Abraham Aranguren (AA). | |
16 | # For performance reasons, this test has been merged with the SSL/TLS | |
17 | # renegotiation test. | |
18 | # - Optimizations by removing cat usage in grepping for findings - by AA. | |
19 | # - New initial tests to check for the tool prerequisites: openssl & sslscan. | |
20 | # - Test for TLS v1.1 and v1.2 support (CVE-2011-3389 aka BEAST). | |
21 | # The tests also include checking for SSLv3 and TLSv1 support. | |
22 | # - Log files names changed from host:port to host_port and ":" removed | |
23 | # from the time portion of the date command, to be able to copy them | |
24 | # to Windows based file systems: | |
25 | # (In Windows ":" is not allowed in a filename, while "_" is). | |
26 | # | |
27 | # - New in version 1.1: | |
28 | # - Cert public key length, subject, issuer, and validiy period. | |
29 | # - Test HTTP(S) secure headers: Strict-Transport-Security (STS), and | |
30 | # cookies with and without the secure flag. | |
31 | # - NOTE: openssl output is now saved to files too. | |
32 | # | |
33 | # - Current SSL/TLS tests: (version 1.0) | |
34 | # SSLv2, NULL cipher, weak ciphers -key length-, strong ciphers -AES-, | |
35 | # MD5 signed cert, and SSL/TLS renegotiation. | |
36 | # | |
37 | # | |
38 | # Requires: | |
39 | # - sslscan | |
40 | # https://sourceforge.net/projects/sslscan/ | |
41 | # - openssl | |
42 | # http://www.openssl.org | |
43 | # | |
44 | # Credits: | |
45 | # - Version 1.0 based on ssl_test.sh by Aung Khant, http://yehg.net. | |
46 | # - Abraham Aranguren (AA) - http://securityconscious.blogspot.com (v1.2) | |
47 | # | |
48 | ||
49 | # | |
50 | # /************************************************************************** | |
51 | # * Copyright 2011 by Taddong SL (Raul Siles) * | |
52 | # * * | |
53 | # * This program is free software; you can redistribute it and/or modify * | |
54 | # * it under the terms of the GNU General Public License as published by * | |
55 | # * the Free Software Foundation; either version 3 of the License, or * | |
56 | # * (at your option) any later version. * | |
57 | # * * | |
58 | # * This program is distributed in the hope that it will be useful, * | |
59 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
60 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
61 | # * GNU General Public License for more details. * | |
62 | # * * | |
63 | # * You should have received a copy of the GNU General Public License * | |
64 | # * along with this program. If not, see <http://www.gnu.org/licenses/>. * | |
65 | # * * | |
66 | # **************************************************************************/ | |
67 | # | |
68 | ||
69 | VERSION=1.2 | |
70 | ||
71 | # This script does not filter the input from certain commands, hence it might | |
72 | # be vulnerable to local input command manipulation, such as in uname. | |
73 | ||
74 | # v1.2: Mac OS X (Darwin) support. | |
75 | # sed regexes in Linux use the -r switch, and in non-GNU systems the -E switch. | |
76 | SED_ARG_REGEX=-r | |
77 | if [ "$(uname)" == "Darwin" ] ; then | |
78 | SED_ARG_REGEX=-E | |
79 | fi | |
80 | ||
81 | echo ------------------------------------------------------ | |
82 | echo " TLSSLed - ($VERSION) based on sslscan and openssl" | |
83 | echo " by Raul Siles (www.taddong.com)" | |
84 | echo ------------------------------------------------------ | |
85 | ||
86 | if [ -z `which openssl` ] ;then echo; echo "ERROR: openssl command not found!"; exit; fi | |
87 | if [ -z `which sslscan` ] ;then echo; echo "ERROR: sslscan command not found!"; exit; fi | |
88 | ||
89 | OPENSSLVERSION=$(openssl version) | |
90 | SSLSCANVERSION=$(sslscan --version | grep version | sed ${SED_ARG_REGEX} "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g") | |
91 | ||
92 | echo + openssl version: $OPENSSLVERSION | |
93 | echo + $SSLSCANVERSION | |
94 | echo ------------------------------------------------------ | |
95 | echo | |
96 | ||
97 | if [ $# -ne 2 ]; then | |
98 | echo Usage: $0 HOSTNAME_or_IP PORT | |
99 | exit | |
100 | fi | |
101 | ||
102 | HOST=$1 | |
103 | PORT=$2 | |
104 | ||
105 | echo [-] Analyzing SSL/TLS on $HOST:$PORT .. | |
106 | echo | |
107 | ||
108 | # Run sslcan once, store the results to a log file and | |
109 | # analyze that file for all the different tests: | |
110 | DATE=$(date +%F_%R:%S | sed 's/://g') | |
111 | TARGET=$HOST\_$PORT | |
112 | LOGFILE=sslscan\_$TARGET\_$DATE.log | |
113 | ERRFILE=sslscan\_$TARGET\_$DATE.err | |
114 | RENEGLOGFILE=openssl\_RENEG\_$TARGET\_$DATE.log | |
115 | RENEGERRFILE=openssl\_RENEG\_$TARGET\_$DATE.err | |
116 | HEADLOGFILE=openssl\_HEAD\_$TARGET\_$DATE.log | |
117 | HEADERRFILE=openssl\_HEAD\_$TARGET\_$DATE.err | |
118 | ||
119 | # Check if the target service speaks SSL/TLS (& check renegotiation) | |
120 | (echo R; sleep 5) | openssl s_client -connect $HOST:$PORT > $RENEGLOGFILE 2> $RENEGERRFILE & | |
121 | pid=$! | |
122 | sleep 5 | |
123 | ||
124 | SSL_HANDSHAKE_LINES=$(cat $RENEGLOGFILE | wc -l) | |
125 | ||
126 | if [ $SSL_HANDSHAKE_LINES -lt 5 ] ; then | |
127 | # SSL handshake failed - Non SSL/TLS service | |
128 | # If the target service does not speak SSL/TLS, openssl does not | |
129 | # terminate | |
130 | kill -s SIGINT ${pid} | |
131 | ||
132 | echo "[+] ERROR: The target service $HOST:$PORT does not seem" | |
133 | echo " to speak SSL/TLS or is not available!!" | |
134 | echo | |
135 | exit | |
136 | else | |
137 | # SSL handshake succeded - Continue | |
138 | echo "[*] The target service $HOST:$PORT seems to speak SSL/TLS..." | |
139 | echo | |
140 | fi | |
141 | ||
142 | ||
143 | echo | |
144 | echo [-] Running sslscan on $HOST:$PORT... | |
145 | sslscan $HOST:$PORT > $LOGFILE 2> $ERRFILE | |
146 | ||
147 | echo | |
148 | echo [*] Testing for SSLv2 ... | |
149 | grep "Accepted SSLv2" $LOGFILE | |
150 | echo | |
151 | echo [*] Testing for NULL cipher ... | |
152 | grep "NULL" $LOGFILE | grep Accepted | |
153 | echo | |
154 | echo [*] Testing for weak ciphers \(based on key length\) ... | |
155 | grep " 40 bits" $LOGFILE | grep Accepted | |
156 | echo | |
157 | grep " 56 bits" $LOGFILE | grep Accepted | |
158 | echo | |
159 | echo [*] Testing for strong ciphers \(AES\) ... | |
160 | grep "AES" $LOGFILE | grep Accepted | |
161 | ||
162 | echo | |
163 | echo [*] Testing for MD5 signed certificate ... | |
164 | #cat $LOGFILE | grep -E 'MD5WithRSAEncryption|md5WithRSAEncryption' | |
165 | grep -i 'MD5WithRSAEncryption' $LOGFILE | |
166 | ||
167 | echo | |
168 | echo [*] Testing for certificate public key length ... | |
169 | grep -i 'RSA Public Key' $LOGFILE | |
170 | ||
171 | echo | |
172 | echo [*] Testing for certificate subject ... | |
173 | grep -i 'Subject:' $LOGFILE | |
174 | ||
175 | echo | |
176 | echo [*] Testing for certificate CA issuer ... | |
177 | grep -i 'Issuer:' $LOGFILE | |
178 | ||
179 | echo | |
180 | echo [*] Testing for certificate validity period ... | |
181 | NOW=$(date -u) | |
182 | echo " Today: $NOW" | |
183 | grep -i 'Not valid' $LOGFILE | |
184 | ||
185 | echo | |
186 | echo [*] Checking preferred server ciphers ... | |
187 | # v1.1: | |
188 | # cat $LOGFILE | sed '/Prefered Server Cipher(s):/,/^$/!d' | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | |
189 | # | |
190 | cat $LOGFILE | sed '/Prefered Server Cipher(s):/,/^$/!d' | sed ${SED_ARG_REGEX} "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | |
191 | ||
192 | echo | |
193 | echo | |
194 | echo [-] Testing for SSLv3/TLSv1 renegotiation vuln. \(CVE-2009-3555\) ... | |
195 | #echo [*] echo R \| openssl s_client -connect $HOST:$PORT \| grep "DONE" | |
196 | # | |
197 | # Renegotiation details go to stderr (2>) | |
198 | # | |
199 | # if $OPENSSLVERSION is updated (version?) it supports RFC5746 and will print: | |
200 | # Secure Renegotiation IS NOT supported | |
201 | # Secure Renegotiation IS supported | |
202 | # | |
203 | ||
204 | # Executed as the first step to check if target service supports SSL/TLS: | |
205 | # | |
206 | # (echo R; sleep 5) | openssl s_client -connect $HOST:$PORT > $RENEGLOGFILE 2> $RENEGERRFILE | |
207 | ||
208 | echo | |
209 | echo [*] Testing for secure renegotiation ... | |
210 | grep -E "Secure Renegotiation IS" $RENEGLOGFILE | |
211 | ||
212 | ||
213 | echo | |
214 | echo | |
215 | echo [-] Testing for TLS v1.1 and v1.2 \(CVE-2011-3389 aka BEAST\) ... | |
216 | ||
217 | # Test for SSLv3 and TLSv1 support first (from sslscan) | |
218 | echo | |
219 | echo [*] Testing for SSLv3 and TLSv1 support first ... | |
220 | grep "Accepted SSLv3" $LOGFILE | |
221 | grep "Accepted TLSv1" $LOGFILE | |
222 | ||
223 | # | |
224 | # Connection details go to stderr (2>) and, therefore, to a variable: | |
225 | # | |
226 | # if $OPENSSLVERSION is updated (version >= 1.0.1-stable) it supports | |
227 | # TLS v1.1 & v1.2, if not, the openssl help is displayed in the command output | |
228 | # | |
229 | # Example of server that supports all SSL and TLS versions: | |
230 | # tls.woodgrovebank.com:443 (Microsoft) (20111012) | |
231 | ||
232 | OUTPUT_TLS1_1=$((sleep 5; echo QUIT) | openssl s_client -tls1_1 -connect $HOST:$PORT 2>&1) | |
233 | OUTPUT_TLS1_2=$((sleep 5; echo QUIT) | openssl s_client -tls1_2 -connect $HOST:$PORT 2>&1) | |
234 | ||
235 | # if "DONE": TLS v1.x supported | |
236 | # else if "wrong version number": TLS v1.x not supported | |
237 | # else if "unknown option": OpenSSL does not support TLS v1.1 or v1.2 | |
238 | ||
239 | echo | |
240 | echo [*] Testing for TLS v1.1 support ... | |
241 | ||
242 | if grep -q DONE <<<$OUTPUT_TLS1_1; then | |
243 | echo "TLS v1.1 IS supported" | |
244 | elif grep -q "wrong version number" <<<$OUTPUT_TLS1_1; then | |
245 | echo "TLS v1.1 IS NOT supported" | |
246 | elif grep -q "unknown option" <<<$OUTPUT_TLS1_1; then | |
247 | echo "The local openssl version does NOT support TLS v1.1" | |
248 | else | |
249 | echo "UNKNOWN" | |
250 | fi | |
251 | ||
252 | echo | |
253 | echo [*] Testing for TLS v1.2 support ... | |
254 | ||
255 | if grep -q DONE <<<$OUTPUT_TLS1_2; then | |
256 | echo "TLS v1.2 IS supported" | |
257 | elif grep -q "wrong version number" <<<$OUTPUT_TLS1_2; then | |
258 | echo "TLS v1.2 IS NOT supported" | |
259 | elif grep -q "unknown option" <<<$OUTPUT_TLS1_2; then | |
260 | echo "The local openssl version does NOT support TLS v1.2" | |
261 | else | |
262 | echo "UNKNOWN" | |
263 | fi | |
264 | ||
265 | echo | |
266 | echo | |
267 | echo [-] Testing for SSL/TLS HTTPS security headers ... | |
268 | # | |
269 | # | |
270 | # | |
271 | (echo -e "HEAD / HTTP/1.0\n\n"; sleep 5) | openssl s_client -connect $HOST:$PORT > $HEADLOGFILE 2> $HEADERRFILE | |
272 | ||
273 | echo | |
274 | echo [*] Testing for Strict-Transport-Security \(STS\) header ... | |
275 | grep -i 'Strict-Transport-Security' $HEADLOGFILE | |
276 | ||
277 | echo | |
278 | echo [*] Testing for cookies with the secure flag ... | |
279 | grep -i 'Set-Cookie' $HEADLOGFILE | grep -i 'secure' | |
280 | ||
281 | echo | |
282 | echo [*] Testing for cookies without the secure flag ... | |
283 | grep -i 'Set-Cookie' $HEADLOGFILE | grep -v -i 'secure' | |
284 | ||
285 | ||
286 | echo | |
287 | echo | |
288 | echo [-] New files created: | |
289 | ls -l $LOGFILE | |
290 | ls -l $HEADLOGFILE | |
291 | ls -l $RENEGLOGFILE | |
292 | ||
293 | # Delete all empty error files: | |
294 | # It could potentially delete other .err zero-size files not created by TLSSLed | |
295 | # find . -size 0 -name '*.err' -delete | |
296 | ||
297 | if [ ! -s $ERRFILE ]; then | |
298 | # Error file is empty | |
299 | rm $ERRFILE | |
300 | else | |
301 | ls -l $ERRFILE | |
302 | fi | |
303 | if [ ! -s $RENEGERRFILE ]; then | |
304 | # Renegotiation error file is empty | |
305 | rm $RENEGERRFILE | |
306 | else | |
307 | ls -l $RENEGERRFILE | |
308 | fi | |
309 | if [ ! -s $HEADERRFILE ]; then | |
310 | # Openssl HEAD error file is empty | |
311 | rm $HEADERRFILE | |
312 | else | |
313 | ls -l $HEADERRFILE | |
314 | fi | |
315 | ||
316 | echo | |
317 | echo | |
318 | echo [-] done | |
319 | echo | |
320 |