sullo / nikto

Nikto web server scanner
Other
8.34k stars 1.21k forks source link

case sensitive header checks cause false negatives #214

Closed ghost closed 9 years ago

ghost commented 9 years ago

I receive these warnings when running Nikto v2.1.6 against my site which uses HSTS to force everything over TLSv1.2

X-Frame-Options header is not present X-Content-Type-Options header is not set X-XSS-Protection header is not defined

source: program/plugins/nikto_headers.plugin

SPDY is on my site, so all headers are lowercase.

These headers were confirmed to be present:

x-content-type-options:nosniff x-frame-options:deny x-xss-protection:1; mode=block

thanks

sullo commented 9 years ago

Can you send some (sanitized) Debug output for that request or a similar one? It should not mismatch on case as all incoming headers are made lowercase, and the actual match is: if (defined $result->{'x-frame-options'}) {

so something else is going on.

You can use -DS to debug output and scrub hostnames/ips from the results. Can you paste in the headers your site is sending?

Thanks Sullo

On Thu, Feb 5, 2015 at 2:09 AM, shimmyshack notifications@github.com wrote:

I receive these warnings when running Nikto v2.1.6 against my site which uses HSTS to force everything over TLSv1.2

X-Frame-Options header is not present X-Content-Type-Options header is not set X-XSS-Protection header is not defined

source: program/plugins/nikto_headers.plugin

SPDY is on my site, so all headers are lowercase.

These headers were confirmed to be present:

x-content-type-options:nosniff x-frame-options:deny x-xss-protection:1; mode=block

thanks

— Reply to this email directly or view it on GitHub https://github.com/sullo/nikto/issues/214.

http://cirt.net | http://richsec.com/

ghost commented 9 years ago

Yes you're right of course :) I have no reason to withhold my server hostname, IP address, or encryption protocols etc.. so the attached files are 1000 lines using head, of Debug logs.

TLSv1.2 (attachment output-yy400.txt, 1000 lines)

Nikto doesn't operate over TLSv1.2, and following the failed handshake all subsequent communication is plain text over port 443, producing 400s with minimal headers.

Nikto correctly reports that the headers in the bug report aren't present. Line 271 in attached debug output.

TLSv1 (attachment output-yy400tlsv1.txt, 1000 lines)

I don't understand the pair of lines from the tlsv1 attachment 246, 304. It seems as though the header x-content-type-options: nosniff is present and correct in line 246, but reported not to be in 304.

If this is my mistake I apologise.

[Seperately I have also seen false positives when trying to detect XSS, nginx correctly urlencodes <,> etc.. and these are printing urlescaped %3D etc in my HTML pages, just not as HTML entities < etc.. Nikto reports XSS is present, but I can't see how.. Perhaps some cunning payload that I didn't spot Nikto testing for in the logs? fails as do any similar double/single quote, html char combinations]

D:Thu Feb 5 21:27:47 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_parked_strings D:Thu Feb 5 21:27:47 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_404_strings D:Thu Feb 5 21:27:47 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_outdated D:Thu Feb 5 21:27:47 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_variables D:Thu Feb 5 21:27:47 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_tests

- Nikto v2.1.6

D:Thu Feb 5 21:27:47 2015 WARNING: No init found for nikto_core D:Thu Feb 5 21:27:48 2015 'Request Hash' = { 'Host' => 'yahvehyireh.com', 'User-Agent' => 'Mozilla/5.00', 'Connection' => 'Keep-Alive', 'whisker' => { 'lowercase_incoming_headers' => 1, 'uri_prefix' => '', 'retry' => 0, 'http_space2' => ' ', 'method' => 'HEAD', 'ssl' => 1, 'ignore_duplicate_headers' => 1, 'force_close' => 0, 'uri_postfix' => '', 'keep-alive' => 1, 'uri' => '/', 'trailing_slurp' => 0, 'protocol' => 'HTTP', 'normalize_incoming_headers' => 1, 'ssl_rsacertfile' => undef, 'include_host_in_uri' => 0, 'ssl_certfile' => undef, 'http_eol' => "\r\n", 'http_space1' => ' ', 'uri_param_sep' => '?', 'force_bodysnatch' => 0, 'ssl_save_info' => 1, 'timeout' => 10, 'max_size' => 0, 'version' => '1.1', 'invalid_protocol_return_value' => 1, 'MAGIC' => 31339, 'require_newline_after_headers' => 0, 'host' => 'yahvehyireh.com', 'port' => 443, 'force_open' => 0 } }; D:Thu Feb 5 21:27:48 2015 'Result Hash' = { 'whisker' => { 'uri' => '/', 'error' => "sending request: SSL error: ssl_write_all 32490: 1 - SSL_ERROR_SSL(-1,1,error:00000001:lib(0):func(0):reason(1),)\nSSL_write 32490: 1 - error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure\n", 'ssl_cipher' => '(NONE)', 'MAGIC' => 31340 } }; D:Thu Feb 5 21:27:48 2015 'Request Hash' = { 'whisker' => { 'uri_postfix' => '', 'force_close' => 0, 'keep-alive' => 1, 'uri' => '/', 'trailing_slurp' => 0, 'normalize_incoming_headers' => 1, 'ssl_rsacertfile' => undef, 'protocol' => 'HTTP', 'ssl_certfile' => undef, 'http_eol' => "\r\n", 'include_host_in_uri' => 0, 'lowercase_incoming_headers' => 1, 'uri_prefix' => '', 'method' => 'HEAD', 'ssl' => 0, 'ignore_duplicate_headers' => 1, 'http_space2' => ' ', 'retry' => 0, 'invalid_protocol_return_value' => 1, 'MAGIC' => 31339, 'port' => 443, 'force_open' => 0, 'host' => 'yahvehyireh.com', 'require_newline_after_headers' => 0, 'force_bodysnatch' => 0, 'uri_param_sep' => '?', 'http_space1' => ' ', 'timeout' => 10, 'ssl_save_info' => 1, 'max_size' => 0, 'version' => '1.1' }, 'Connection' => 'Keep-Alive', 'User-Agent' => 'Mozilla/5.00', 'Host' => 'yahvehyireh.com' }; D:Thu Feb 5 21:27:48 2015 'Result Hash' = { 'date' => 'Thu, 05 Feb 2015 21:27:48 GMT', 'whisker' => { 'http_space2' => ' ', 'lowercase_incoming_headers' => 1, 'http_data_sent' => 1, 'header_order' => [ 'server', 'date', 'content-type', 'content-length', 'connection' ], 'stats_syns' => 1, 'uri_requested' => '/', 'uri' => '/', 'http_eol' => "\r\n", 'protocol' => 'HTTP', 'http_space1' => ' ', 'version' => '1.1', 'code' => 400, 'message' => 'Bad Request', 'stats_reqs' => 1, 'MAGIC' => 31340, 'socket_state' => 0 }, 'connection' => 'close', 'content-type' => 'text/html; charset=UTF-8', 'server' => 'nginx', 'content-length' => 264 }; D:Thu Feb 5 21:27:48 2015 - HTTP Server found: yahvehyireh.com:443 nginx D:Thu Feb 5 21:27:48 2015 'Request Hash' = { 'whisker' => { 'invalid_protocol_return_value' => 1, 'MAGIC' => 31339, 'host' => 'yahvehyireh.com', 'require_newline_after_headers' => 0, 'port' => 443, 'force_open' => 0, 'http_space1' => ' ', 'uri_param_sep' => '?', 'force_bodysnatch' => 0, 'timeout' => 10, 'ssl_save_info' => 1, 'max_size' => 0, 'version' => '1.1', 'force_close' => 0, 'uri_postfix' => '', 'uri' => '/', 'keep-alive' => 1, 'trailing_slurp' => 0, 'protocol' => 'HTTP', 'ssl_rsacertfile' => undef, 'normalize_incoming_headers' => 1, 'ssl_certfile' => undef, 'http_eol' => "\r\n", 'include_host_in_uri' => 0, 'lowercase_incoming_headers' => 1, 'uri_prefix' => '', 'retry' => 0, 'http_space2' => ' ', 'ignore_duplicate_headers' => 1, 'ssl' => 0, 'method' => 'GET' }, 'Connection' => 'Keep-Alive', 'User-Agent' => 'Mozilla/5.00', 'Host' => 'yahvehyireh.com' }; D:Thu Feb 5 21:27:48 2015 'Result Hash' = { 'content-length' => 264, 'server' => 'nginx', 'content-type' => 'text/html; charset=UTF-8', 'connection' => 'close', 'whisker' => { 'uri' => '/', 'http_eol' => "\r\n", 'protocol' => 'HTTP', 'http_space2' => ' ', 'header_order' => [ 'server', 'date', 'content-type', 'content-length', 'connection' ], 'http_data_sent' => 1, 'lowercase_incoming_headers' => 1, 'stats_syns' => 2, 'uri_requested' => '/', 'data' => "\r\n400 The plain HTTP request was sent to HTTPS port\r\n<body bgcolor=\"white\">\r\n

400 Bad Request

\r\n
The plain HTTP request was sent to HTTPS port
\r\n
nginx
\r\n\r\n\r\n", 'stats_reqs' => 2, 'message' => 'Bad Request', 'MAGIC' => 31340, 'socket_state' => 0, 'http_space1' => ' ', 'code' => 400, 'version' => '1.1' }, 'date' => 'Thu, 05 Feb 2015 21:27:48 GMT' };

+ Start Time: 2015-02-05 21:27:48 (GMT0)

D:Thu Feb 5 21:45:21 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_parked_strings D:Thu Feb 5 21:45:21 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_404_strings D:Thu Feb 5 21:45:21 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_outdated D:Thu Feb 5 21:45:21 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_variables D:Thu Feb 5 21:45:21 2015 - Loading DB: /Users/moomoo/Downloads/nikto-master/program/databases/db_tests

- Nikto v2.1.6

D:Thu Feb 5 21:45:21 2015 WARNING: No init found for nikto_core D:Thu Feb 5 21:45:21 2015 'Request Hash' = { 'User-Agent' => 'Mozilla/5.00', 'Connection' => 'Keep-Alive', 'Host' => 'yahvehyireh.com', 'whisker' => { 'uri_prefix' => '', 'ignore_duplicate_headers' => 1, 'ssl_save_info' => 1, 'retry' => 0, 'max_size' => 0, 'timeout' => 10, 'ssl_rsacertfile' => undef, 'method' => 'HEAD', 'trailing_slurp' => 0, 'http_eol' => "\r\n", 'require_newline_after_headers' => 0, 'http_space1' => ' ', 'MAGIC' => 31339, 'lowercase_incoming_headers' => 1, 'include_host_in_uri' => 0, 'keep-alive' => 1, 'port' => 443, 'uri' => '/', 'force_bodysnatch' => 0, 'version' => '1.1', 'host' => 'yahvehyireh.com', 'ssl' => 1, 'force_close' => 0, 'protocol' => 'HTTP', 'uri_postfix' => '', 'uri_param_sep' => '?', 'ssl_certfile' => undef, 'invalid_protocol_return_value' => 1, 'force_open' => 0, 'normalize_incoming_headers' => 1, 'httpspace2' => ' ' } }; D:Thu Feb 5 21:45:21 2015 'Result Hash' = { 'p3p' => 'CP=YY has no P3P policy, why? https://yahvehyireh.com/manage/p3p/', 'timing-allow-origin' => '', 'strict-transport-security' => 'max-age=16070400; includesubdomains; preload', 'vary' => 'Accept-Encoding', 'date' => 'Thu, 05 Feb 2015 21:45:21 GMT', 'content-type' => 'text/html; charset=UTF-8', 'x-content-type-options' => 'nosniff', 'x-frame-options' => 'deny', 'x-xss-protection' => '1; mode=block', 'content-security-policy' => 'default-src \'none\'; connect-src \'self\'; font-src \'self\'; frame-src \'none\'; img-src \'self\' https://www.google-analytics.com; media-src \'self\'; object-src https://yahvehyireh.com/resources/dawn-mag-archive/; script-src \'self\' https://www.google-analytics.com; style-src \'self\';', 'server' => 'nginx', 'whisker' => { 'lowercase_incoming_headers' => 1, 'code' => 200, 'ssl_cert_subject' => '/OU=Domain Control Validated/OU=PositiveSSL/CN=yahvehyireh.com', 'header_order' => [ 'server', 'date', 'content-type', 'connection', 'vary', 'strict-transport-security', 'x-frame-options', 'x-xss-protection', 'x-content-type-options', 'content-security-policy', 'p3p', 'timing-allow-origin' ], 'message' => 'OK', 'uri' => '/', 'ssl_cert_issuer' => '/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA', 'version' => '1.1', 'protocol' => 'HTTP', 'http_data_sent' => 1, 'ssl_cert_altnames' => [ 2, 'yahvehyireh.com', 2, 'www.yahvehyireh.com' ], 'http_space2' => ' ', 'socket_state' => 0, 'ssl_cipher' => 'DHE-RSA-AES256-SHA', 'uri_requested' => '/', 'stats_reqs' => 1, 'stats_syns' => 1, 'http_eol' => "\r\n", 'http_space1' => ' ', 'MAGIC' => 31340 }, 'connection' => 'keep-alive' }; D:Thu Feb 5 21:45:21 2015 - HTTPS Server found: yahvehyireh.com:443 nginx D:Thu Feb 5 21:45:22 2015 'Request Hash' = { 'Host' => 'yahvehyireh.com', 'User-Agent' => 'Mozilla/5.00', 'Connection' => 'Keep-Alive', 'whisker' => { 'ignore_duplicate_headers' => 1, 'uri_prefix' => '', 'max_size' => 0, 'timeout' => 10, 'retry' => 0, 'ssl_save_info' => 1, 'http_eol' => "\r\n", 'trailing_slurp' => 0, 'method' => 'GET', 'ssl_rsacertfile' => undef, 'MAGIC' => 31339, 'require_newline_after_headers' => 0, 'http_space1' => ' ', 'port' => 443, 'keep-alive' => 1, 'lowercase_incoming_headers' => 1, 'include_host_in_uri' => 0, 'version' => '1.1', 'host' => 'yahvehyireh.com', 'force_bodysnatch' => 0, 'uri' => '/', 'invalid_protocol_return_value' => 1, 'ssl_certfile' => undef, 'uri_postfix' => '', 'uri_param_sep' => '?', 'protocol' => 'HTTP', 'force_close' => 0, 'ssl' => 1, 'http_space2' => ' ', 'normalize_incoming_headers' => 1, 'force_open' => 0 } }; D:Thu Feb 5 21:45:22 2015 'Result Hash' = { 'content-security-policy' => 'default-src \'none\'; connect-src \'self\'; font-src \'self\'; frame-src \'none\'; img-src \'self\' https://www.google-analytics.com; media-src \'self\'; object-src https://yahvehyireh.com/resources/dawn-mag-archive/; script-src \'self\' https://www.google-analytics.com; style-src \'self\';', 'server' => 'nginx', 'whisker' => { 'stats_syns' => 2, 'stats_reqs' => 2, 'uri_requested' => '/', 'ssl_cipher' => 'DHE-RSA-AES256-SHA', 'MAGIC' => 31340, 'http_space1' => ' ', 'http_eol' => "\r\n", 'data' => "<!doctype html>\n\n\n\t<meta charset=\"UTF-8\">\n\tYahveh Yireh - Freely Give\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"//yahvehyireh.com/assets/css/styles.css\">\n\t<script type=\"text/javascript\" src=\"//yahvehyireh.com/assets/js/main.js\">\n\t<link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"//yahvehyireh.com/apple-touch-icon-57x57.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"//yahvehyireh.com/apple-touch-icon-114x114.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"72x72\" href=\"//yahvehyireh.com/apple-touch-icon-72x72.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"144x144\" href=\"//yahvehyireh.com/apple-touch-icon-144x144.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"60x60\" href=\"//yahvehyireh.com/apple-touch-icon-60x60.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"120x120\" href=\"//yahvehyireh.com/apple-touch-icon-120x120.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"76x76\" href=\"//yahvehyireh.com/apple-touch-icon-76x76.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"152x152\" href=\"//yahvehyireh.com/apple-touch-icon-152x152.png\">\n\t<link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"//yahvehyireh.com/apple-touch-icon-180x180.png\">\n\t<link rel=\"icon\" type=\"image/png\" href=\"//yahvehyireh.com/favicon-192x192.png\" sizes=\"192x192\">\n\t<link rel=\"icon\" type=\"image/png\" href=\"//yahvehyireh.com/favicon-160x160.png\" sizes=\"160x160\">\n\t<link rel=\"icon\" type=\"image/png\" href=\"//yahvehyireh.com/favicon-96x96.png\" sizes=\"96x96\">\n\t<link rel=\"icon\" type=\"image/png\" href=\"//yahvehyireh.com/favicon-16x16.png\" sizes=\"16x16\">\n\t<link rel=\"icon\" type=\"image/png\" href=\"//yahvehyireh.com/favicon-32x32.png\" sizes=\"32x32\">\n\t<meta name=\"apple-mobile-web-app-title\" content=\"Yahveh\">\n\t<meta name=\"application-name\" content=\"Yahveh\">\n\t<meta name=\"msapplication-TileColor\" content=\"#2b5797\">\n\t<meta name=\"msapplication-TileImage\" content=\"//yahvehyireh.com/mstile-144x144.png\">\n\n\n\t

\n\t\t
\n\t\n", 'version' => '1.1', 'uri' => '/', 'ssl_cert_issuer' => '/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA', 'header_order' => [ 'server', 'date', 'content-type', 'transfer-encoding', 'connection', 'vary', 'strict-transport-security', 'x-frame-options', 'x-xss-protection', 'x-content-type-options', 'content-security-policy', 'p3p', 'timing-allow-origin' ], 'message' => 'OK', 'ssl_cert_subject' => '/OU=Domain Control Validated/OU=PositiveSSL/CN=yahvehyireh.com', 'lowercase_incoming_headers' => 1, 'code' => 200, 'socket_state' => 0, 'http_space2' => ' ', 'ssl_cert_altnames' => [ 2, 'yahvehyireh.com', 2, 'www.yahvehyireh.com' ], 'http_datasent' => 1, 'protocol' => 'HTTP' }, 'connection' => 'keep-alive', 'x-frame-options' => 'deny', 'x-xss-protection' => '1; mode=block', 'x-content-type-options' => 'nosniff', 'content-type' => 'text/html; charset=UTF-8', 'date' => 'Thu, 05 Feb 2015 21:45:22 GMT', 'transfer-encoding' => 'chunked', 'p3p' => 'CP=YY has no P3P policy, why? https://yahvehyireh.com/manage/p3p/', 'strict-transport-security' => 'max-age=16070400; includesubdomains; preload', 'timing-allow-origin' => '', 'vary' => 'Accept-Encoding' };

+ Target Port: 443

+ Start Time: 2015-02-05 21:45:21 (GMT0)

mauipete commented 9 years ago

Version 2.1.6 - getting a Header missing for "X-Content-Type-Options" even though it's defined.

In nikto_headers.plugin I believe

This line : if (!defined $result->{'X-Content-Type-Options'}) {

should be: if (!defined $result->{'x-content-type-options'}) {

Thanks for your work on this program

ghost commented 9 years ago

Seems this was partly fixed by https://github.com/sullo/nikto/commit/ab9560cb3808d931b0ca408b5a4436c981a63882 ?

tautology0 commented 9 years ago

Yeah; sorry I fixed it whilst I was there. I just needed to fully test it before I close off the call (which I should be doing tomorrow).

ghost commented 9 years ago

No worries, just wanted to make @shimmyshack aware of this possible fix. Maybe should have noted that. :-)

tautology0 commented 9 years ago

It appears to work fully with tests against real world servers; so I'm going to close this as fixed. @shimmyshack, if you're still getting the problem with trunk, could you open up the call again and we'll do some more digging. Thanks!

ghost commented 9 years ago

The only header still acting like this is the anti-clickjacking X-Frame-Options header, which is reported as not present, when in fact it is present as:

x-frame-options: deny

Everything else seems fine :) thank you for your work!

Using brew install nikto just now, v2.1.5 inspecting a vhost equal to host, port 443. Server is nginx/SPDY

tautology0 commented 9 years ago

[BTW I had to edit your comment as your mobile number was in the email footer]

I'll be honest; I've tried to reproduce the issue, even using the domain above, and am not succeeding. Burp definitely shows that you're using the right headers, but I can't get Nikto to alert on it.

Though now I see that I have to add support for public key pinning too :-)

ghost commented 9 years ago

Thanks for the edit! Oh yeah pkp what fun!

It could be that one or two pages (maybe error pages) don't have the header. I'll dump some packets, recheck and report back.