diff options
author | Remy <relst@relst.nl> | 2015-05-24 09:35:28 +0200 |
---|---|---|
committer | Remy <relst@relst.nl> | 2015-05-24 09:35:28 +0200 |
commit | 988f08b9eb952404b94817a973d1a19ff7c6524b (patch) | |
tree | b23c940603507f240f377ba9278b49ae97dc6190 | |
parent | 5e7e74fe94062683cce82c189cd43dd18c3aff9b (diff) | |
download | ssl-decoder-988f08b9eb952404b94817a973d1a19ff7c6524b.zip ssl-decoder-988f08b9eb952404b94817a973d1a19ff7c6524b.tar.gz ssl-decoder-988f08b9eb952404b94817a973d1a19ff7c6524b.tar.bz2 |
Add support for specific endpoints
-rw-r--r-- | CHANGELOG.md | 5 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | functions/connection.php | 82 | ||||
-rw-r--r-- | functions/crl.php | 8 | ||||
-rw-r--r-- | functions/json.php | 15 | ||||
-rw-r--r-- | functions/ocsp.php | 11 | ||||
-rw-r--r-- | functions/tls_fallback_scsv.php | 11 | ||||
-rw-r--r-- | functions/variables.php | 127 | ||||
-rw-r--r-- | inc/form.php | 1 | ||||
-rw-r--r-- | index.php | 28 | ||||
-rw-r--r-- | json.php | 16 |
11 files changed, 218 insertions, 94 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f5856b2..d764b6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 2.5 + +- Show specific endpoint picker when multiple A/AAAA records exist. +- Add support for testing specific IP's with specific hostnames (instead of what DNS says) + ## 2.4 - Add SSL Compressio check @@ -32,6 +32,7 @@ Simple PHP script which decodes an SSL connection and/or certificate and display - JSON API - Warnings for bad connection settings or certificate options - Heartbleed test +- SNI specific testing ## Requirements @@ -50,6 +51,8 @@ Unpack and go! Browse to https://your-server/ssl-decoder. +The default timeout for checks is 2 seconds. If this is to fast for your internal services, this can be raised in the `variables.php` file. + ### OpenSSL compilation If you want to use the latest OpenSSL and your distro doesn't shit with it you can compile your own OpenSSL and replace the system one. Do note that this might break stuff. @@ -83,11 +86,10 @@ The SSL Decoder includes Piwik Javascript tracking code. If you self host it, yo Endpoint: `/json.php`. - Accepts: - CSR - Certificate -- Host (+port, default 443) +- Host:ip (+port, default 443) Returns JSON UTF-8 encoded certificate (and connection) data. @@ -276,7 +278,7 @@ Example Response: Params: - - `host` = Hostname or IP address + - `host:ip` = Hostname:IP address - `port` = port to test (443, 993, 465, 8443 etc). - ciphersuites = 1 to enumerate ciphersuites supported by the tested server. Takes longer. If not specified or not 1, ciphersuites will not be tested, used ciphersuite will be reported. diff --git a/functions/connection.php b/functions/connection.php index 60b111f..5cb98ab 100644 --- a/functions/connection.php +++ b/functions/connection.php @@ -27,11 +27,13 @@ function get(&$var, $default=null) { return isset($var) ? $var : $default; } -function server_http_headers($host, $port){ +function server_http_headers($host, $ip, $port){ + global $timeout; // first check if server is http. otherwise long timeout. - $ch = curl_init(("https://" . $host . ":" . $port)); - curl_setopt($ch, CURLOPT_TIMEOUT, 2); + $ch = curl_init(("https://" . $ip . ":" . $port)); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_NOBODY, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, array("Host: $host")); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FAILONERROR, true); curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); @@ -49,23 +51,25 @@ function server_http_headers($host, $port){ array("verify_peer" => false, "capture_session_meta" => true, "verify_peer_name" => false, + "peer_name" => $host, "allow_self_signed" => true, "sni_enabled" => true), 'http' => array( 'method' => 'GET', 'max_redirects' => 1, - 'timeout' => 2 + 'timeout' => $timeout ) ) ); - $headers = get_headers("https://$host:$port", 1); + $headers = get_headers("https://$ip:$port", 1); if (!empty($headers)) { $headers = array_change_key_case($headers, CASE_LOWER); return $headers; } } -function ssl_conn_ciphersuites($host, $port, $ciphersuites){ +function ssl_conn_ciphersuites($host, $ip, $port, $ciphersuites) { + global $timeout; $old_error_reporting = error_reporting(); error_reporting($old_error_reporting ^ E_WARNING); $results = array(); @@ -75,9 +79,10 @@ function ssl_conn_ciphersuites($host, $port, $ciphersuites){ array("verify_peer" => false, "verify_peer_name" => false, "allow_self_signed" => true, + "peer_name" => $host, 'ciphers' => $value, "sni_enabled" => true))); - $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); + $read_stream = stream_socket_client("ssl://$ip:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $stream); if ( $read_stream === false ) { $results[$value] = false; } else { @@ -88,7 +93,7 @@ function ssl_conn_ciphersuites($host, $port, $ciphersuites){ return $results; } -function test_heartbleed($host, $port) { +function test_heartbleed($ip, $port) { global $current_folder; $exitstatus = 0; $output = 0; @@ -100,7 +105,7 @@ function test_heartbleed($host, $port) { # check if python2 is available exec("command -v python2 >/dev/null 2>&1", $cmdoutput, $cmdexitstatus); if ($cmdexitstatus != 1) { - exec("timeout 15 python2 " . getcwd() . "/inc/heartbleed.py " . escapeshellcmd($host) . " --json \"" . $tmpfile . "\" --threads 1 --port " . escapeshellcmd($port) . " --silent", $output, $exitstatus); + exec("timeout 15 python2 " . getcwd() . "/inc/heartbleed.py " . escapeshellcmd($ip) . " --json \"" . $tmpfile . "\" --threads 1 --port " . escapeshellcmd($port) . " --silent", $output, $exitstatus); if (file_exists($tmpfile)) { $json_data = json_decode(file_get_contents($tmpfile),true); foreach ($json_data as $key => $value) { @@ -118,10 +123,11 @@ function test_heartbleed($host, $port) { return $result; } -function test_sslv2($host, $port) { +function test_sslv2($ip, $port) { + global $timeout; $exitstatus = 0; $output = 0; - exec('echo | timeout 2 openssl s_client -connect "' . escapeshellcmd($host) . ':' . escapeshellcmd($port) . '" -ssl2 2>&1 >/dev/null', $output, $exitstatus); + exec('echo | timeout ' . $timeout . ' openssl s_client -connect "' . escapeshellcmd($ip) . ':' . escapeshellcmd($port) . '" -ssl2 2>&1 >/dev/null', $output, $exitstatus); if ($exitstatus == 0) { $result = true; } else { @@ -130,12 +136,12 @@ function test_sslv2($host, $port) { return $result; } -## python2 inc/heartbleed.py 85.222.224.236 --json tmp --max 1 --threads 1 --port 443 - -function conn_compression($host, $port) { +function conn_compression($host, $ip, $port) { + global $timeout; $exitstatus = 0; $output = 0; - exec('echo | timeout 2 openssl s_client -connect "' . escapeshellcmd($host) . ':' . escapeshellcmd($port) . '" -status -tlsextdebug 2>&1 | grep -qe "^Compression: NONE"', $output, $exitstatus); + //pre_dump('echo | timeout ' . $timeout . ' openssl s_client -servername "' . escapeshellcmd($host) . '" -connect "' . escapeshellcmd($ip) . ':' . escapeshellcmd($port) . '" -status -tlsextdebug 2>&1 | grep -qe "^Compression: NONE"'); + exec('echo | timeout ' . $timeout . ' openssl s_client -servername "' . escapeshellcmd($host) . '" -connect "' . escapeshellcmd($ip) . ':' . escapeshellcmd($port) . '" -status -tlsextdebug 2>&1 | grep -qe "^Compression: NONE"', $output, $exitstatus); if ($exitstatus == 0) { $result = false; } else { @@ -144,7 +150,8 @@ function conn_compression($host, $port) { return $result; } -function ssl_conn_protocols($host, $port){ +function ssl_conn_protocols($host, $ip, $port) { + global $timeout; $old_error_reporting = error_reporting(); error_reporting($old_error_reporting ^ E_WARNING); $results = array('sslv2' => false, @@ -159,10 +166,11 @@ function ssl_conn_protocols($host, $port){ array("verify_peer" => false, "capture_session_meta" => true, "verify_peer_name" => false, + "peer_name" => $host, "allow_self_signed" => true, 'crypto_method' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT, "sni_enabled" => true))); - $read_stream_sslv3 = stream_socket_client("sslv3://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_sslv3); + $read_stream_sslv3 = stream_socket_client("sslv3://$ip:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $stream_sslv3); if ( $read_stream_sslv3 === false ) { $results['sslv3'] = false; } else { @@ -173,10 +181,11 @@ function ssl_conn_protocols($host, $port){ array("verify_peer" => false, "capture_session_meta" => true, "verify_peer_name" => false, + "peer_name" => $host, "allow_self_signed" => true, 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_0_CLIENT, "sni_enabled" => true))); - $read_stream_tlsv10 = stream_socket_client("tlsv1.0://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv10); + $read_stream_tlsv10 = stream_socket_client("tlsv1.0://$ip:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $stream_tlsv10); if ( $read_stream_tlsv10 === false ) { $results['tlsv1.0'] = false; } else { @@ -188,9 +197,10 @@ function ssl_conn_protocols($host, $port){ "capture_session_meta" => true, "verify_peer_name" => false, "allow_self_signed" => true, + "peer_name" => $host, 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_1_CLIENT, "sni_enabled" => true))); - $read_stream_tlsv11 = stream_socket_client("tlsv1.1://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv11); + $read_stream_tlsv11 = stream_socket_client("tlsv1.1://$ip:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $stream_tlsv11); if ( $read_stream_tlsv11 === false ) { $results['tlsv1.1'] = false; } else { @@ -202,9 +212,10 @@ function ssl_conn_protocols($host, $port){ "capture_session_meta" => true, "verify_peer_name" => false, "allow_self_signed" => true, + "peer_name" => $host, 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv_1_2_CLIENT, "sni_enabled" => true))); - $read_stream_tlsv12 = stream_socket_client("tlsv1.2://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream_tlsv12); + $read_stream_tlsv12 = stream_socket_client("tlsv1.2://$ip:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $stream_tlsv12); if ( $read_stream_tlsv12 === false ) { $results['tlsv1.2'] = false; } else { @@ -228,7 +239,7 @@ function ssl_conn_metadata($data) { } foreach ($data["warning"] as $key => $value) { echo "<div class='alert alert-danger' role='alert'>"; - echo htmlspecialchars($value); + echo $value; echo "</div>"; } } @@ -525,13 +536,18 @@ function ssl_conn_metadata($data) { -function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { +function ssl_conn_metadata_json($host, $ip, $port, $read_stream, $chain_data=null) { $result = array(); global $random_blurp; global $current_folder; $context = stream_context_get_params($read_stream); $context_meta = stream_context_get_options($read_stream)['ssl']['session_meta']; $cert_data = openssl_x509_parse($context["options"]["ssl"]["peer_certificate"])[0]; + + if (filter_var(preg_replace('/[^A-Za-z0-9\.\:-]/', '', $ip), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 )) { + $result["warning"][] = "You are testing an IPv6 host. Due to <a href=\"https://rt.openssl.org/Ticket/Display.html?id=1365&user=guest&pass=guest\">bugs</a> in OpenSSL's command line tools the results will be inaccurate. Known incorrect are OCSP Stapling, TLS_FALLBACK_SCSV and SSL Compression results, others may also be incorrect."; + } + $result["checked_hostname"] = $host; //chain if (isset($context_meta)) { @@ -573,20 +589,18 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { unlink('/tmp/verify_cert.' . $random_blurp . '.pem'); } // hostname ip port - if (fixed_gethostbyname($host)) { - $result["ip"] = fixed_gethostbyname($host); - $result["hostname"] = gethostbyaddr(fixed_gethostbyname($host)); - $result["port"] = $port; - } + $result["ip"] = $ip; + $result["hostname"] = gethostbyaddr($ip); + $result["port"] = $port; //heartbleed - $result['heartbleed'] = test_heartbleed($host, $port); + $result['heartbleed'] = test_heartbleed($ip, $port); if ($result['heartbleed'] == "vulnerable") { $result["warning"][] = 'Vulnerable to the Heartbleed bug. Please update your OpenSSL ASAP!'; } // compression - $compression = conn_compression($host, $port); + $compression = conn_compression($host, $ip, $port); if ($compression == false) { $result["compression"] = false; } else { @@ -595,7 +609,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { } // protocols - $result["protocols"] = array_reverse(ssl_conn_protocols($host, $port)); + $result["protocols"] = array_reverse(ssl_conn_protocols($host, $ip, $port)); foreach ($result["protocols"] as $key => $value) { if ( $value == true ) { if ( $key == "sslv2") { @@ -731,7 +745,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { 'NULL-SHA256', 'NULL-SHA', 'NULL-MD5'); - $tested_ciphersuites = ssl_conn_ciphersuites($host, $port, $ciphersuites_to_test); + $tested_ciphersuites = ssl_conn_ciphersuites($host, $ip, $port, $ciphersuites_to_test); $result["supported_ciphersuites"] = array(); foreach ($tested_ciphersuites as $key => $value) { if ($value == true) { @@ -744,7 +758,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { $result["used_ciphersuite"]["bits"] = $context_meta['cipher_bits']; } // tls_fallback_scsv - $fallback = tls_fallback_scsv($host, $port); + $fallback = tls_fallback_scsv($host, $ip, $port); if ($fallback['protocol_count'] == 1) { $result["tls_fallback_scsv"] = "Only 1 protocol enabled, fallback not possible, TLS_FALLBACK_SCSV not required."; } else { @@ -756,7 +770,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { } } //hsts - $headers = server_http_headers($host, $port); + $headers = server_http_headers($host, $ip, $port); if ($headers["strict-transport-security"]) { if ( is_array($headers["strict-transport-security"])) { $result["strict_sransport-security"] = substr($headers["strict-transport-security"][0], 0, 50); @@ -785,7 +799,7 @@ function ssl_conn_metadata_json($host, $port, $read_stream, $chain_data=null) { } } // ocsp stapling - $stapling = ocsp_stapling($host,$port); + $stapling = ocsp_stapling($host, $ip, $port); if($stapling["working"] == 1) { $result["ocsp_stapling"] = $stapling; } else { diff --git a/functions/crl.php b/functions/crl.php index 34cc794..35e57a5 100644 --- a/functions/crl.php +++ b/functions/crl.php @@ -15,7 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. function crl_verify($raw_cert_data, $verbose=true) { - global $random_blurp; + global $random_blurp, $timeout; $cert_data = openssl_x509_parse($raw_cert_data); $cert_serial_nm = strtoupper(bcdechex($cert_data['serialNumber'])); $crl_uris = []; @@ -35,7 +35,7 @@ function crl_verify($raw_cert_data, $verbose=true) { if (0 === strpos($uri, 'http')) { $fp = fopen ("/tmp/" . $random_blurp . "." . $key . ".crl", 'w+'); $ch = curl_init(($uri)); - curl_setopt($ch, CURLOPT_TIMEOUT, 2); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_FAILONERROR, true); curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); @@ -100,7 +100,7 @@ function crl_verify($raw_cert_data, $verbose=true) { function crl_verify_json($raw_cert_data) { - global $random_blurp; + global $random_blurp, $timeout; $result = []; $cert_data = openssl_x509_parse($raw_cert_data); $cert_serial_nm = strtoupper(bcdechex($cert_data['serialNumber'])); @@ -121,7 +121,7 @@ function crl_verify_json($raw_cert_data) { $result[$crl_no]["crl_uri"] = $uri; $fp = fopen ("/tmp/" . $random_blurp . "." . $key . ".crl", 'w+'); $ch = curl_init(($uri)); - curl_setopt($ch, CURLOPT_TIMEOUT, 2); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_FAILONERROR, true); curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); diff --git a/functions/json.php b/functions/json.php index bbd9983..0abed70 100644 --- a/functions/json.php +++ b/functions/json.php @@ -15,17 +15,24 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. -function check_json($host,$port) { +function check_json($host,$ip,$port) { + global $timeout; $data = []; $stream = stream_context_create (array("ssl" => array("capture_peer_cert" => true, "capture_peer_cert_chain" => true, "verify_peer" => false, + "peer_name" => $host, "verify_peer_name" => false, "allow_self_signed" => true, "capture_session_meta" => true, "sni_enabled" => true))); - $read_stream = stream_socket_client("ssl://$host:$port", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $stream); + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 )) { + $connect_ip = "[" . $ip . "]"; + } else { + $connect_ip = $ip; + } + $read_stream = stream_socket_client("ssl://$connect_ip:$port", $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $stream); if ( $read_stream === false ) { $data["error"] = ["Failed to connect: " . htmlspecialchars($errstr)]; return $data; @@ -44,8 +51,8 @@ function check_json($host,$port) { $prev = $chain_data[$key-1]; $chain_key = (string)$key+1; if ($key == 0) { - $data["connection"] = ssl_conn_metadata_json($host, $port, $read_stream, $chain_data); - $data["chain"][$chain_key] = cert_parse_json($curr, $next, $host, true); + $data["connection"] = ssl_conn_metadata_json($host, $ip, $port, $read_stream, $chain_data); + $data["chain"][$chain_key] = cert_parse_json($curr, $next, $host, $ip, true); } else { $data["chain"][$chain_key] = cert_parse_json($curr, $next, null, false); } diff --git a/functions/ocsp.php b/functions/ocsp.php index ca8ada6..99b5f2d 100644 --- a/functions/ocsp.php +++ b/functions/ocsp.php @@ -14,9 +14,10 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -function ocsp_stapling($host, $port){ +function ocsp_stapling($host, $ip, $port) { + global $timeout; $result = ""; - $output = shell_exec('echo | timeout 2 openssl s_client -connect "' . escapeshellcmd($host) . ':' . escapeshellcmd($port) . '" -tlsextdebug -status 2>&1 | sed -n "/OCSP response:/,/---/p"'); + $output = shell_exec('echo | timeout ' . $timeout . ' openssl s_client -servername "' . escapeshellcmd($host) . '" -connect "' . escapeshellcmd($ip) . ':' . escapeshellcmd($port) . '" -tlsextdebug -status 2>&1 | sed -n "/OCSP response:/,/---/p"'); if (strpos($output, "no response sent") !== false) { $result = array("working" => 0, "cert_status" => "No response sent"); @@ -45,7 +46,7 @@ function ocsp_stapling($host, $port){ } function ocsp_verify_json($raw_cert_data, $raw_next_cert_data, $ocsp_uri) { - global $random_blurp; + global $random_blurp, $timeout; $result = array(); $tmp_dir = '/tmp/'; $root_ca = getcwd() . '/cacert.pem'; @@ -62,9 +63,9 @@ function ocsp_verify_json($raw_cert_data, $raw_next_cert_data, $ocsp_uri) { //pre_dump('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$isser_loc.' -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1'); - $output = shell_exec('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$isser_loc .' -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1'); + $output = shell_exec('timeout ' . $timeout . ' | openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$isser_loc .' -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1'); - $filter_output = shell_exec('openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$isser_loc .' -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1 | grep -v -e "to get local issuer certificate" -e "signer certificate not found" -e "Response Verify" -e "'. $tmp_dir.$random_blurp.'.cert_client.pem"'); + $filter_output = shell_exec('timeout ' . $timeout . ' | openssl ocsp -no_nonce -CAfile '.$root_ca.' -issuer '.$isser_loc .' -cert '.$tmp_dir.$random_blurp.'.cert_client.pem -url "'. escapeshellcmd($ocsp_uri) . '" -header "HOST" "'. escapeshellcmd($ocsp_host) . '" 2>&1 | grep -v -e "to get local issuer certificate" -e "signer certificate not found" -e "Response Verify" -e "'. $tmp_dir.$random_blurp.'.cert_client.pem"'); $output = preg_replace("/[[:blank:]]+/"," ", $output); $ocsp_status_lines = explode("\n", $output); diff --git a/functions/tls_fallback_scsv.php b/functions/tls_fallback_scsv.php index 3cf0ea1..dc58f11 100644 --- a/functions/tls_fallback_scsv.php +++ b/functions/tls_fallback_scsv.php @@ -14,16 +14,13 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -function tls_fallback_scsv($host,$port) { - +function tls_fallback_scsv($host, $ip, $port) { + global $timeout; $result = []; - $protocols = ssl_conn_protocols($host, $port); + $protocols = ssl_conn_protocols($host, $ip, $port); if (count(array_filter($protocols)) > 1) { $result['protocol_count'] = count(array_filter($protocols)); - $fallback_test = shell_exec("echo | timeout 2 openssl s_client -connect " . escapeshellcmd($host) . ":" . escapeshellcmd($port) . " -fallback_scsv -no_tls1_2 2>&1 >/dev/null"); - // echo "<pre>"; - // var_dump($fallback_test); - // echo "</pre>"; + $fallback_test = shell_exec("echo | timeout $timeout openssl s_client -servername \"" . escapeshellcmd($host) . "\" -connect " . escapeshellcmd($ip) . ":" . escapeshellcmd($port) . " -fallback_scsv -no_tls1_2 2>&1 >/dev/null"); if ( stripos($fallback_test, "alert inappropriate fallback") !== false ) { $result['tls_fallback_scsv_support'] = 1; } diff --git a/functions/variables.php b/functions/variables.php index 28caaa1..7384794 100644 --- a/functions/variables.php +++ b/functions/variables.php @@ -14,10 +14,15 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. +# timeout in seconds +$timeout = 2; + +# Don't change stuff down here. date_default_timezone_set('UTC'); -ini_set('default_socket_timeout', 2); -$version = 2.4; +$version = 2.5; + +ini_set('default_socket_timeout', 2); $random_blurp = rand(1000,99999); @@ -27,24 +32,122 @@ $ev_oids = array("1.3.6.1.4.1.34697.2.1", "1.3.6.1.4.1.34697.2.2", "1.3.6.1.4.1. $current_folder = get_current_folder(); function parse_hostname($u_hostname){ - # format raymii.org:8080 should auto parse port. - # parts[0]=hostname, parts[1]=port + # format raymii.org:1.2.34.56 should do SNI request to that ip. + # parts[0]=host, parts[1]=ip $port = 0; $hostname = 0; - $parts = explode(":", $u_hostname); - if ((1 <= $parts[1]) && ($parts[1] <= 65535)) { - $parts[1] = preg_replace('/\\s+/', '', $parts[1]); - $parts[1] = preg_replace('/[^A-Za-z0-9\._-]/', '', $parts[1]); - $port = mb_strtolower($parts[1]); - } + $parts = explode(":", $u_hostname, 2); + if (idn_to_ascii($parts[0])) { $parts[0] = idn_to_ascii($parts[0]); } $parts[0] = preg_replace('/\\s+/', '', $parts[0]); - $parts[0] = preg_replace('/[^A-Za-z0-9\.-]/', '', $parts[0]); + $parts[0] = preg_replace('/[^A-Za-z0-9\.\:-]/', '', $parts[0]); $hostname = mb_strtolower($parts[0]); - $result = array('hostname' => $hostname, 'port' => $port); + + if (count($parts) > 1) { + $parts[1] = preg_replace('/\\s+/', '', $parts[1]); + $parts[1] = preg_replace('/[^A-Za-z0-9\.\:_-]/', '', $parts[1]); + if (filter_var($parts[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) or filter_var($parts[1], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 )) { + $ip = mb_strtolower($parts[1]); + } else { + $ip = fixed_gethostbyname($hostname); + } + } else { + if (filter_var($hostname, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 )) { + $ip = $hostname; + } else { + $dns_a_records = dns_get_record($hostname, DNS_A); + $dns_aaaa_records = dns_get_record($hostname, DNS_AAAA); + $dns_records = array_merge($dns_a_records, $dns_aaaa_records); + if (count($dns_a_records) > 1 or count($dns_aaaa_records) > 1) { + $result = array('hostname' => $hostname, 'ip' => $ip, 'multiple_ip' => $dns_records); + return $result; + } else { + $ip = fixed_gethostbyname($hostname); + } + } + } + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + $ip = "[" . $ip . "]"; + } + + $result = array('hostname' => $hostname, 'ip' => $ip); return $result; } +function choose_endpoint($ips, $host, $port, $ciphersuites) { + echo "<div id='page-content-wrapper'>\n"; + echo "<div class='container-fluid'>\n"; + echo "<div class='row'>\n"; + // if ajax-ed, don't show header again + if(empty($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest') { + echo "<div class='col-md-10 col-md-offset-1'>\n"; + echo "<div class='page-header'>\n"; + echo "<h1><a style='color:black;' href=\""; + echo(htmlspecialchars($current_folder)); + echo "\">SSL Decoder</a></h1>\n"; + echo "</div>\n"; + } + echo "<div id='preloader'>\n"; + echo "<p>\n"; + echo "<img src=\""; + echo(htmlspecialchars($current_folder)); + echo 'img/ajax-loader.gif" />'; + echo "<br> <br>\n"; + echo "The SSL Decoder is processing your request. Please wait a few moments.<br>\n"; + echo "</p>\n"; + echo "</div>\n"; + echo "<div id='resultDiv'></div>\n"; + + echo "<div class='content'>\n<section id='choose_endpoint'>\n"; + echo "<header>\n<h2>Multiple endpoints for " . htmlspecialchars($host) . "</h2>\n</header>\n"; + echo "<p>We've found multiple results for " . htmlspecialchars($host) . ". Please choose the host you want to scan from the list below:</p>\n<br>\n"; + echo "<ul>\n"; + foreach ($ips as $ip) { + echo "<li>"; + echo "<a href=\""; + echo htmlspecialchars($current_folder); + echo "?host="; + echo htmlspecialchars($host); + echo ":"; + if ($ip['type'] == 'A') { + echo htmlspecialchars($ip['ip']); + } elseif ($ip['type'] == 'AAAA') { + echo "["; + echo htmlspecialchars($ip['ipv6']); + echo "]"; + } + echo "&port="; + echo htmlspecialchars($port); + echo "&ciphersuites="; + if ($ciphersuites == 1) { + echo "1"; + } else { + echo "0"; + } + echo "\">"; + if ($ip['type'] == 'A') { + echo htmlspecialchars($ip['ip']); + } elseif ($ip['type'] == 'AAAA') { + echo "["; + echo htmlspecialchars($ip['ipv6']); + echo "]"; + } + echo " (port: "; + echo htmlspecialchars($port); + echo ")</a>"; + echo "</li>"; + } + + echo "</ul>\n"; + echo "</section></div>\n"; + echo "</div>\n"; + echo "</div>\n"; + echo "</div>\n"; + + require_once("inc/footer.php"); + exit; +} + ?> diff --git a/inc/form.php b/inc/form.php index ef00824..be35a6a 100644 --- a/inc/form.php +++ b/inc/form.php @@ -23,7 +23,6 @@ <div class="col-md-4 col-md-offset-1"> <div class="checkbox"> <label for="ciphersuites"> - <!-- <input type="checkbox" name="ciphersuites" id="ciphersuites" value="1" checked="checked"> --> <input type="checkbox" name="ciphersuites" id="ciphersuites" value="1" checked="checked"> Enumerate Ciphersuites (takes longer) </label> @@ -45,17 +45,17 @@ foreach (glob("functions/*.php") as $filename) { echo '<div id="wrapper">'; $data = []; $hostname = mb_strtolower(get($_GET['host'])); - $host = parse_hostname($hostname); - if ($host['port']) { - $port = $host['port']; - } else { - $port = get($_GET['port'], '443'); - } - $host = $host['hostname']; + $hostname = parse_hostname($hostname); + $host = $hostname['hostname']; + $port = get($_GET['port'], '443'); if ( !is_numeric($port) ) { $port = 443; } - $data["data"] = check_json($host,$port); + if ($hostname['multiple_ip']) { + choose_endpoint($hostname['multiple_ip'], $host, $port, $_GET['ciphersuites']); + } + $ip = $hostname['ip']; + $data["data"] = check_json($host,$ip,$port); if(isset($data["data"]["error"])) { $data["error"] = $data["data"]["error"]; unset($data["data"]); @@ -147,7 +147,7 @@ foreach (glob("functions/*.php") as $filename) { // connection data echo "<div class='content'><section id='conndata'>"; - echo "<header><h2>Connection Data for " . htmlspecialchars($host) . "</h2></header>"; + echo "<header><h2>Connection Data for " . htmlspecialchars($host) . " / " . htmlspecialchars($ip) . "</h2></header>"; ssl_conn_metadata($data["data"]["connection"]); echo "</section></div>"; @@ -184,14 +184,10 @@ foreach (glob("functions/*.php") as $filename) { } } - - - ?> - </div> - </div> - </div> + echo "</div>"; + echo "</div>"; + echo "</div>"; -<?php require_once("inc/footer.php"); if ($write_cache == 1) { @@ -10,13 +10,13 @@ foreach (glob("functions/*.php") as $filename) { if ( isset($_GET['host']) && !empty($_GET['host'])) { $data = []; $hostname = mb_strtolower(get($_GET['host'])); - $host = parse_hostname($hostname); - if ($host['port']) { - $port = $host['port']; - } else { - $port = get($_GET['port'], '443'); - } - $host = $host['hostname']; + $hostname = parse_hostname($hostname); + if ($hostname['multiple_ip']) { + $data["error"] = ["Host format is incorrect. (use \$host:\$ip.)"]; + } + $host = $hostname['hostname']; + $ip = $hostname['ip']; + $port = get($_GET['port'], '443'); if ( !is_numeric($port) ) { $port = 443; } @@ -25,7 +25,7 @@ if ( isset($_GET['host']) && !empty($_GET['host'])) { $hostfilename = preg_replace("([\.]{2,})", '', $host); $hostfilename = preg_replace("([^a-z0-9])", '', $host); $cache_filename = (string) "results/saved." . $hostfilename . "." . $epoch . "." . $random_bla . ".api.json"; - $data["data"] = check_json($host,$port); + $data["data"] = check_json($host, $ip, $port); } elseif(isset($_GET['csr']) && !empty($_GET['csr'])) { $write_cache = 1; $cache_filename = (string) "results/saved.csr." . $epoch . "." . $random_bla . ".api.json"; |