From 20707ef7688bed44fec39c4673a8823211e94149 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 16 Apr 2015 16:12:49 +0200 Subject: ssh: added id_string option for server and client For limiting Banner Grabbing attempts. --- lib/ssh/doc/src/ssh.xml | 17 ++++++ lib/ssh/src/ssh.erl | 6 +++ lib/ssh/src/ssh_transport.erl | 34 +++++++++--- lib/ssh/test/ssh_basic_SUITE.erl | 109 +++++++++++++++++++++++++++++++++++++++ lib/ssh/vsn.mk | 2 +- 5 files changed, 161 insertions(+), 7 deletions(-) diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 0e7e3848ad..72dafc0c09 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -180,6 +180,15 @@

If true, the client will not print out anything on authorization.

+ + + +

The string that the client presents to a connected server initially. The default value is "Erlang/VSN" where VSN is the ssh application version number. +

+

The value random will cause a random string to be created at each connection attempt. This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version. +

+
+

Allow an existing file descriptor to be used @@ -344,6 +353,14 @@

+ + +

The string the daemon will present to a connecting peer initially. The default value is "Erlang/VSN" where VSN is the ssh application version number. +

+

The value random will cause a random string to be created at each connection attempt. This is to make it a bit more difficult for a malicious peer to find the ssh software brand and version. +

+
+

Module implementing the behaviour ssh_server_key_api. diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 51ad691ba2..d4b02a024e 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -347,6 +347,8 @@ handle_option([parallel_login|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]); handle_option([{minimal_remote_max_packet_size, _} = Opt|Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{id_string, _ID} = Opt|Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions). @@ -439,6 +441,10 @@ handle_ssh_option({idle_time, Value} = Opt) when is_integer(Value), Value > 0 -> Opt; handle_ssh_option({rekey_limit, Value} = Opt) when is_integer(Value) -> Opt; +handle_ssh_option({id_string, random}) -> + {id_string, {random,2,5}}; %% 2 - 5 random characters +handle_ssh_option({id_string, ID} = Opt) when is_list(ID) -> + Opt; handle_ssh_option(Opt) -> throw({error, {eoptions, Opt}}). diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index 76fa776113..8669be570e 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -44,12 +44,34 @@ versions(client, Options)-> Vsn = proplists:get_value(vsn, Options, ?DEFAULT_CLIENT_VERSION), - Version = format_version(Vsn), - {Vsn, Version}; + {Vsn, format_version(Vsn, software_version(Options))}; versions(server, Options) -> Vsn = proplists:get_value(vsn, Options, ?DEFAULT_SERVER_VERSION), - Version = format_version(Vsn), - {Vsn, Version}. + {Vsn, format_version(Vsn, software_version(Options))}. + +software_version(Options) -> + case proplists:get_value(id_string, Options) of + undefined -> + "Erlang"++ssh_vsn(); + {random,Nlo,Nup} -> + random_id(Nlo,Nup); + ID -> + ID + end. + +ssh_vsn() -> + try {ok,L} = application:get_all_key(ssh), + proplists:get_value(vsn,L,"") + of + "" -> ""; + VSN when is_list(VSN) -> "/" ++ VSN; + _ -> "" + catch + _:_ -> "" + end. + +random_id(Nlo, Nup) -> + [crypto:rand_uniform($a,$z+1) || _<- lists:duplicate(crypto:rand_uniform(Nlo,Nup+1),x) ]. hello_version_msg(Data) -> [Data,"\r\n"]. @@ -77,9 +99,9 @@ is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm, yes_no(Ssh, Prompt) -> (Ssh#ssh.io_cb):yes_no(Prompt, Ssh). -format_version({Major,Minor}) -> +format_version({Major,Minor}, SoftwareVersion) -> "SSH-" ++ integer_to_list(Major) ++ "." ++ - integer_to_list(Minor) ++ "-Erlang". + integer_to_list(Minor) ++ "-" ++ SoftwareVersion. handle_hello_version(Version) -> try diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 81c7b5cd15..f5f8991acc 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -52,6 +52,12 @@ all() -> ssh_connect_arg4_timeout, packet_size_zero, ssh_daemon_minimal_remote_max_packet_size_option, + id_string_no_opt_client, + id_string_own_string_client, + id_string_random_client, + id_string_no_opt_server, + id_string_own_string_server, + id_string_random_server, {group, hardening_tests} ]. @@ -816,6 +822,66 @@ ssh_daemon_minimal_remote_max_packet_size_option(Config) -> ssh:close(Conn), ssh:stop_daemon(Server). +%%-------------------------------------------------------------------- +id_string_no_opt_client(Config) -> + {Server, Host, Port} = fake_daemon(Config), + {error,_} = ssh:connect(Host, Port, []), + receive + {id,Server,"SSH-2.0-Erlang/"++Vsn} -> + true = expected_ssh_vsn(Vsn); + {id,Server,Other} -> + ct:fail("Unexpected id: ~s.",[Other]) + end. + +%%-------------------------------------------------------------------- +id_string_own_string_client(Config) -> + {Server, Host, Port} = fake_daemon(Config), + {error,_} = ssh:connect(Host, Port, [{id_string,"Pelle"}]), + receive + {id,Server,"SSH-2.0-Pelle\r\n"} -> + ok; + {id,Server,Other} -> + ct:fail("Unexpected id: ~s.",[Other]) + end. + +%%-------------------------------------------------------------------- +id_string_random_client(Config) -> + {Server, Host, Port} = fake_daemon(Config), + {error,_} = ssh:connect(Host, Port, [{id_string,random}]), + receive + {id,Server,Id="SSH-2.0-Erlang"++_} -> + ct:fail("Unexpected id: ~s.",[Id]); + {id,Server,Rnd="SSH-2.0-"++_} -> + ct:log("Got ~s.",[Rnd]); + {id,Server,Id} -> + ct:fail("Unexpected id: ~s.",[Id]) + end. + +%%-------------------------------------------------------------------- +id_string_no_opt_server(Config) -> + {_Server, Host, Port} = std_daemon(Config, []), + {ok,S1}=gen_tcp:connect(Host,Port,[{active,false}]), + {ok,"SSH-2.0-Erlang/"++Vsn} = gen_tcp:recv(S1, 0, 2000), + true = expected_ssh_vsn(Vsn). + +%%-------------------------------------------------------------------- +id_string_own_string_server(Config) -> + {_Server, Host, Port} = std_daemon(Config, [{id_string,"Olle"}]), + {ok,S1}=gen_tcp:connect(Host,Port,[{active,false}]), + {ok,"SSH-2.0-Olle\r\n"} = gen_tcp:recv(S1, 0, 2000). + +%%-------------------------------------------------------------------- +id_string_random_server(Config) -> + {_Server, Host, Port} = std_daemon(Config, [{id_string,random}]), + {ok,S1}=gen_tcp:connect(Host,Port,[{active,false}]), + {ok,"SSH-2.0-"++Rnd} = gen_tcp:recv(S1, 0, 2000), + case Rnd of + "Erlang"++_ -> ct:log("Id=~p",[Rnd]), + {fail,got_default_id}; + "Olle\r\n" -> {fail,got_previous_tests_value}; + _ -> ct:log("Got ~s.",[Rnd]) + end. + %%-------------------------------------------------------------------- ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true). ssh_connect_negtimeout_sequential(Config) -> ssh_connect_negtimeout(Config,false). @@ -1095,3 +1161,46 @@ do_shell(IO, Shell) -> %% {'EXIT', Shell, killed} -> %% ok %% end. + + +std_daemon(Config, ExtraOpts) -> + SystemDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + {_Server, _Host, _Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2} | ExtraOpts]). + +expected_ssh_vsn(Str) -> + try + {ok,L} = application:get_all_key(ssh), + proplists:get_value(vsn,L,"")++"\r\n" + of + Str -> true; + "\r\n" -> true; + _ -> false + catch + _:_ -> true %% ssh not started so we dont't know + end. + + +fake_daemon(_Config) -> + Parent = self(), + %% start the server + Server = spawn(fun() -> + {ok,Sl} = gen_tcp:listen(0,[]), + {ok,{Host,Port}} = inet:sockname(Sl), + Parent ! {sockname,self(),Host,Port}, + Rsa = gen_tcp:accept(Sl), + ct:log("Server gen_tcp:accept got ~p",[Rsa]), + {ok,S} = Rsa, + receive + {tcp, S, Id} -> Parent ! {id,self(),Id} + end + end), + %% Get listening host and port + receive + {sockname,Server,ServerHost,ServerPort} -> {Server, ServerHost, ServerPort} + end. + diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index fec8dacab7..b2b85a717f 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,4 +1,4 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 3.2.1 +SSH_VSN = 3.2.2 APP_VSN = "ssh-$(SSH_VSN)" -- cgit v1.2.3 From ab9c37a30c960cbc5e5b72c73a3a315afc4c3920 Mon Sep 17 00:00:00 2001 From: Hans Nilsson Date: Thu, 16 Apr 2015 16:40:06 +0200 Subject: inets: Add value 'none' in server_tokens config When the Server header has empty info (or 'none' in config), it is not generated. This is for limiting Banner Grabbing attempts. --- lib/inets/doc/src/httpd.xml | 3 ++- lib/inets/src/http_server/httpd_conf.erl | 8 +++++--- lib/inets/src/http_server/httpd_response.erl | 7 +++++-- lib/inets/vsn.mk | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml index 20c8a6b1b1..e40660ab39 100644 --- a/lib/inets/doc/src/httpd.xml +++ b/lib/inets/doc/src/httpd.xml @@ -315,7 +315,7 @@ text/plain asc txt - {server_tokens, prod|major|minor|minimal|os|full|{private, string()}} + {server_tokens, none|prod|major|minor|minimal|os|full|{private, string()}}

ServerTokens defines how the value of the server header should look.

@@ -323,6 +323,7 @@ text/plain asc txt here is what the server header string could look like for the different values of server-tokens:

+none                  ""  % A Server: header will not be generated
 prod                  "inets"
 major                 "inets/5"
 minor                 "inets/5.8"
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index 78dda794db..dbdc1be272 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -219,14 +219,14 @@ load("ServerName " ++ ServerName, []) ->
 
 load("ServerTokens " ++ ServerTokens, []) ->
     %% These are the valid *plain* server tokens: 
-    %%     sprod, major, minor, minimum, os, full
+    %%     none, prod, major, minor, minimum, os, full
     %% It can also be a "private" server token: private:
     case string:tokens(ServerTokens, [$:]) of
 	["private", Private] ->
 	    {ok,[], {server_tokens, clean(Private)}};
 	[TokStr] ->
 	    Tok = list_to_atom(clean(TokStr)),
-	    case lists:member(Tok, [prod, major, minor, minimum, os, full]) of
+	    case lists:member(Tok, [none, prod, major, minor, minimum, os, full]) of
 		true ->
 		    {ok,[], {server_tokens, Tok}};
 		false ->
@@ -850,6 +850,8 @@ server(full = _ServerTokens) ->
     OS = os_info(full), 
     lists:flatten(
       io_lib:format("~s ~s OTP/~s", [?SERVER_SOFTWARE, OS, OTPRelease]));
+server(none = _ServerTokens) ->
+    "";
 server({private, Server} = _ServerTokens) when is_list(Server) -> 
     %% The user provide its own 
     Server;
@@ -1299,7 +1301,7 @@ ssl_ca_certificate_file(ConfigDB) ->
     end.
 
 plain_server_tokens() ->
-    [prod, major, minor, minimum, os, full].
+    [none, prod, major, minor, minimum, os, full].
 
 error_report(Where,M,F,Error) ->
     error_logger:error_report([{?MODULE, Where}, 
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index 0895729d05..2fa91d47a0 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -287,8 +287,11 @@ create_header(ConfigDb, KeyValueTupleHeaders) ->
     ContentType = "text/html", 
     Server      = server(ConfigDb),
     NewHeaders  = add_default_headers([{"date",         Date},
-				       {"content-type", ContentType},
-				       {"server",       Server}], 
+				       {"content-type", ContentType}
+				       | if Server=="" -> [];
+					    true -> [{"server",       Server}]
+					 end
+				      ], 
 				       KeyValueTupleHeaders),
     lists:map(fun fix_header/1, NewHeaders).
 
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index e5b63a6446..e9ecb2632a 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,6 +18,6 @@
 # %CopyrightEnd%
 
 APPLICATION = inets
-INETS_VSN   = 5.10.6
+INETS_VSN   = 5.10.7
 PRE_VSN     =
 APP_VSN     = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
-- 
cgit v1.2.3


From 0bdd37192dd76acdf575a2482eabaeba99d4fdf6 Mon Sep 17 00:00:00 2001
From: Erlang/OTP 
Date: Wed, 22 Apr 2015 13:39:56 +0200
Subject: Update release notes

---
 lib/inets/doc/src/notes.xml | 23 ++++++++++++++++++++++-
 lib/ssh/doc/src/notes.xml   | 21 +++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 2c3ee79f31..12bbc2b736 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,7 +32,28 @@
     notes.xml
   
   
-  
Inets 5.10.6 +
Inets 5.10.7 + +
Improvements and New Features + + +

+ New value in server_tokens config for limiting + banner grabbing attempts.

+

+ By setting {server_tokens, none} in + ServiceConfig for inets:start(httpd, + ServiceConfig), the "Server:" header will not be set + in messages from the server.

+

+ Own Id: OTP-12661 Aux Id: seq12840

+
+
+
+ +
+ +
Inets 5.10.6
Fixed Bugs and Malfunctions diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index acbf3124ef..41885c684c 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -29,6 +29,27 @@ notes.xml +
Ssh 3.2.2 + +
Improvements and New Features + + +

+ New option id_string for ssh:daemon and + ssh:connect for limiting banner grabbing attempts.

+

+ The possible values are: {id_string,string()} and + {id_string,random}. The latter will make ssh + generate a random nonsence id-string for each new + connection.

+

+ Own Id: OTP-12659

+
+
+
+ +
+
Ssh 3.2.1
Fixed Bugs and Malfunctions -- cgit v1.2.3 From ff1e0b2fe44a347670a5d72c45c061fefa6abc7f Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Wed, 22 Apr 2015 13:39:56 +0200 Subject: Updated OTP version --- OTP_VERSION | 2 +- otp_versions.table | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/OTP_VERSION b/OTP_VERSION index 9cbaf23720..808ab16bea 100644 --- a/OTP_VERSION +++ b/OTP_VERSION @@ -1 +1 @@ -17.5.1 +17.5.2 diff --git a/otp_versions.table b/otp_versions.table index a82f535ea1..4bf6cb93b2 100644 --- a/otp_versions.table +++ b/otp_versions.table @@ -1,3 +1,4 @@ +OTP-17.5.2 : inets-5.10.7 ssh-3.2.2 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5.1 : ssh-3.2.1 # asn1-3.0.4 common_test-1.10 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.6 jinterface-1.5.12 kernel-3.2 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16 sasl-2.4.1 snmp-5.1.1 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 : OTP-17.5 : asn1-3.0.4 common_test-1.10 compiler-5.0.4 crypto-3.5 debugger-4.0.3 dialyzer-2.7.4 diameter-1.9 eldap-1.1.1 erts-6.4 hipe-3.11.3 inets-5.10.6 kernel-3.2 mnesia-4.12.5 observer-2.0.4 os_mon-2.3.1 public_key-0.23 runtime_tools-1.8.16 ssh-3.2 ssl-6.0 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8 tools-2.7.2 wx-1.3.3 # cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 edoc-0.7.16 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 ic-4.3.6 jinterface-1.5.12 megaco-3.17.3 odbc-2.10.22 orber-3.7.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 reltool-0.6.6 sasl-2.4.1 snmp-5.1.1 typer-0.9.8 webtool-0.8.10 xmerl-1.3.7 : OTP-17.4.1 : erts-6.3.1 inets-5.10.5 # asn1-3.0.3 common_test-1.9 compiler-5.0.3 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.4.2 debugger-4.0.2 dialyzer-2.7.3 diameter-1.8 edoc-0.7.16 eldap-1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.2 ic-4.3.6 jinterface-1.5.12 kernel-3.1 megaco-3.17.3 mnesia-4.12.4 observer-2.0.3 odbc-2.10.22 orber-3.7.1 os_mon-2.3 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.22.1 reltool-0.6.6 runtime_tools-1.8.15 sasl-2.4.1 snmp-5.1.1 ssh-3.1 ssl-5.3.8 stdlib-2.3 syntax_tools-1.6.17 test_server-3.7.2 tools-2.7.1 typer-0.9.8 webtool-0.8.10 wx-1.3.2 xmerl-1.3.7 : -- cgit v1.2.3