[erlang-questions] 'ssh' security issue

OvermindDL1 overminddl1@REDACTED
Wed Dec 11 19:49:06 CET 2013


I can build erlang from git whenever the changes are available if you want
me to test it with a running application, just tell me when.  Thanks for
the assistance, it put me right on the right track.  I love the help that
is available here!
On Dec 11, 2013 1:25 AM, "Ingela Andin" <ingela.andin@REDACTED> wrote:

> Hi!
>
> As I mentioned in my previous post, ssh will change quite a lot in the
> upcoming release so please
> try it when it comes and let me now if there are any further improvements
> that you need.
>
> Regards Ingela Erlang/OTP team - Ericsson AB
>
>
> 2013/12/10 OvermindDL1 <overminddl1@REDACTED>
>
>> Be calling the option with Exec added to it with a fixed
>> handle_ssh_option test to test for if a fun as well.
>>
>> On Tue, Dec 10, 2013 at 3:15 PM, OvermindDL1 <overminddl1@REDACTED>
>> wrote:
>> > Nevermind, and for future documentation I found this in ssh_cli.erl:
>> > ```
>> > start_shell(_ConnectionHandler, Cmd, #state{exec={M, F, A}} = State) ->
>> >     Group = group:start(self(), {M, F, A++[Cmd]}, [{echo, false}]),
>> >     State#state{group = Group, buf = empty_buf()};
>> > start_shell(ConnectionHandler, Cmd, #state{exec=Shell} = State) when
>> > is_function(Shell) ->
>> >
>> >     ConnectionInfo = ssh_connection_handler:info(ConnectionHandler,
>> >                                                  [peer, user]),
>> >     {ok, User} =
>> >         proplists:get_value(user, ConnectionInfo),
>> >     ShellFun =
>> >         case erlang:fun_info(Shell, arity) of
>> >             {arity, 1} ->
>> >                 fun() -> Shell(Cmd) end;
>> >             {arity, 2} ->
>> >                 fun() -> Shell(Cmd, User) end;
>> >             {arity, 3} ->
>> >                 [{_, PeerAddr}] =
>> >                     proplists:get_value(peer, ConnectionInfo),
>> >                 fun() -> Shell(Cmd, User, PeerAddr) end;
>> >             _ ->
>> >                 Shell
>> >         end,
>> >     Echo = get_echo(State#state.pty),
>> >     Group = group:start(self(), ShellFun, [{echo,Echo}]),
>> >     State#state{group = Group, buf = empty_buf()}.
>> > ```
>> > The exec property of the state record is set on init, so I figured I
>> > could just pass in a fun instead like I can the shell option:
>> > ```
>> > {error,{eoptions,{exec,#Fun<msw_ssh_server.2.72054487>}}
>> > ```
>> > Nope.  But yet it looks like it should accept a fun fine, so... what
>> > is going on.
>> > I take a look at where ssh_cli is called and found this in
>> > ssh_connection_handler.erl:
>> > ```
>> >     Shell = proplists:get_value(shell, Opts),
>> >     Exec = proplists:get_value(exec, Opts),
>> >     CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell]}),
>> >     State#state{starter = Pid, connection_state = Connection#connection{
>> >                                                     cli_spec = CliSpec,
>> >                                                     exec = Exec,
>> >                                                     system_supervisor
>> > = SystemSup,
>> >
>> > sub_system_supervisor = SubSystemSup,
>> >
>> > connection_supervisor = ConnectionSup
>> >                                                    }}.
>> > ```
>> > So, it seems the exec is set here as an option to the connection
>> > state, and the exec is filtered on this in ssh.erl:
>> > ```
>> >
>> > handle_ssh_option({exec, {Module, Function, _}} = Opt) when
>> is_atom(Module),
>> >
>> is_atom(Function) ->
>> >
>> >     Opt;
>> > ```
>> > And that looks like it should work, but wait, remember what I said
>> > about exec only being set on init in ssh_cli.erl, and look at the line
>> > above that sets the default ssh_cli option:
>> > ```
>> >     CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell]}),
>> > ```
>> > Hmm, so it never sets the exec option in the ssh_cli, if it did then
>> > it should actually be calling:
>> > ```
>> >     CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell,
>> Exec]}),
>> > ```
>> > Yet it is not.  So I removed my shell and exec options from ssh:daemon
>> > and replaced it with a single option of:
>> > ```
>> >     {ssh_cli, {ssh_cli, [
>> >         fun(User, PeerAddr) -> msw_ssh_server_shell:start(User,
>> PeerAddr) end,
>> >         fun(Cmd, User, PeerAddr) -> msw_ssh_server_shell:exec(Cmd,
>> > User, PeerAddr) end]}},
>> > ```
>> > And badda bing it works.  I am not sure if this is the 'proper' way to
>> > do it (and I would love to learn of a proper way if it exists), but it
>> > works with both setting a shell, exec, and getting the User and
>> > PeerAddress in both cases as well.
>> >
>> > On Tue, Dec 10, 2013 at 2:26 PM, OvermindDL1 <overminddl1@REDACTED>
>> wrote:
>> >> Another question while I am at it with this exec option, the 'shell'
>> >> option gets a User and PeerAddr passed in, any way to do that with
>> >> exec?  If I can at least get the User then I can allow them to issue
>> >> one-off commands this way too, which would be quite useful for remote
>> >> scripting.
>> >>
>> >> On Tue, Dec 10, 2013 at 2:22 PM, OvermindDL1 <overminddl1@REDACTED>
>> wrote:
>> >>> Ah all you are amazing, I never saw that option in the docs indeed and
>> >>> looks like it should do what I want.  Thanks much for all the help!
>> >>>
>> >>> On Tue, Dec 10, 2013 at 10:20 AM, Jakob Cederlund <jakobce@REDACTED>
>> wrote:
>> >>>> Actually, the sample cli module works quite all right. The problem
>> is that
>> >>>> the default implementation in ssh_cli for the "exec" thing in ssh is
>> >>>> actually to execute it (using erl_scan and erl_eval and stuff).
>> There is an
>> >>>> undocumented option to ssh (actually to the ssh_cli module) that can
>> be used
>> >>>> to customize this. The option {exec, {M, F, []}} takes an exported
>> function
>> >>>> (M:F/1) that is called with the parameters given to the ssh commands
>> as a
>> >>>> string. This function should spawn a process that writes the desired
>> output
>> >>>> on stdout.
>> >>>>
>> >>>> So to avoid the strange eval phenomenon, and provide another
>> function that
>> >>>> just echoes the parameters back, you can write a module x:
>> >>>> -module(x).
>> >>>> -export([exec/1]).
>> >>>> exec(A) -> spawn(fun() -> io:format("~p\n", [A]), exit(normal) end).
>> >>>>
>> >>>> and specify the function x:exec/1 as a call-back for the exec option:
>> >>>> B=ssh_sample_cli:listen(8323, [{subsystems, []}, {exec, x, exec,
>> ""]).
>> >>>>
>> >>>> And then when you do:
>> >>>>> ssh -p 8323 to.the.host 'lists:reverse("test").'
>> >>>>
>> >>>> You get back:
>> >>>> "list:reverse(\"test\")."
>> >>>>
>> >>>> Hope this helps. (And sorry for the mess…)
>> >>>> /Jakob
>> >>>>
>> >>>>
>> >>>>
>> >>>> 2013/12/10 Ingela Andin <ingela.andin@REDACTED>
>> >>>>>
>> >>>>> Hi!
>> >>>>>
>> >>>>> The CLI example in the SSH application must be seen as a hack. We
>> intend
>> >>>>> to clean it up and
>> >>>>> extend the SSH documentation, when it gets prioritized I can not
>> say. Well
>> >>>>> anyway your CLI
>> >>>>> implementation must take care of SSH exec request as well.  You can
>> also
>> >>>>> look at the ssh_cli.erl  module.
>> >>>>> If I remember correctly there was a bug, before ssh-2.1.7, with
>> regards to
>> >>>>> the exec request  so that  it was not forwarded to CLI process but
>> rather
>> >>>>> always interpreted in the erlang shell environment.
>> >>>>>
>> >>>>> Regards Ingela Erlang/OTP team - Ericsson AB
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> 2013/12/7 OvermindDL1 <overminddl1@REDACTED>
>> >>>>>>
>> >>>>>> Greetings,
>> >>>>>>
>> >>>>>> I am attempting to just create an SSH shell to connect to a system
>> by
>> >>>>>> users so they can do commands without the web interface, and as
>> such I
>> >>>>>> certainly do not want things like port forwarding or being able to
>> run
>> >>>>>> arbitrary erlang code, however I do not seem to be able to disable
>> >>>>>> running arbitrary erlang code.  An example of the ssh_sample_cli
>> >>>>>> included with erlang:
>> >>>>>> """
>> >>>>>> $ erl
>> >>>>>> Erlang R16B02 (erts-5.10.3) [source] [64-bit] [smp:8:8]
>> >>>>>> [async-threads:10] [hipe] [kernel-poll:false]
>> >>>>>>
>> >>>>>> Eshell V5.10.3  (abort with ^G)
>> >>>>>> 1> c(ssh_sample_cli).
>> >>>>>> ssh_sample_cli.erl:146: Warning: this expression will fail with a
>> >>>>>> 'badarith' exception
>> >>>>>> {ok,ssh_sample_cli}
>> >>>>>> 2> B=ssh_sample_cli:listen(8323, [{subsystems, []}]).
>> >>>>>> {ok,<0.67.0>}
>> >>>>>> """
>> >>>>>>
>> >>>>>> And from another shell/computer:
>> >>>>>> """
>> >>>>>> $ ssh -p 8321 to.the.host
>> >>>>>> myusername@REDACTED's password:
>> >>>>>> Enter command
>> >>>>>> CLI> help
>> >>>>>> CLI Sample
>> >>>>>> crash                  crash the cli
>> >>>>>> exit                   exit application
>> >>>>>> factors    <int>       prime factors of <int>
>> >>>>>> gcd        <int> <int> greatest common divisor
>> >>>>>> help                   help text
>> >>>>>> host                   print host addr
>> >>>>>> lcm        <int> <int> least common multiplier
>> >>>>>> prime      <int>       check for primality
>> >>>>>> primes     <int>       print all primes up to <int>
>> >>>>>> rho        <int>       prime factors using rho's alg.
>> >>>>>> self                   print my pid
>> >>>>>> user                   print name of user
>> >>>>>>
>> >>>>>> ---> ok
>> >>>>>> CLI> exit
>> >>>>>> ---> done
>> >>>>>> Connection to to.the.host closed.
>> >>>>>> """
>> >>>>>>
>> >>>>>> So far so good (the main program where I have this implemented has
>> a
>> >>>>>> well running shell of its own), but lets try a couple other things:
>> >>>>>> """
>> >>>>>> $ sftp -P 8321 to.the.host
>> >>>>>> myusername@REDACTED's password:
>> >>>>>> subsystem request failed on channel 0
>> >>>>>> Connection closed
>> >>>>>> """
>> >>>>>>
>> >>>>>> Also good, no file transfers can be done since the option
>> subsystem is
>> >>>>>> set to [], but notice:
>> >>>>>> """
>> >>>>>> $ ssh -p 8323 to.the.host 'lists:reverse("!?ti pots I od woh dna
>> ereh
>> >>>>>> gnineppah si tahw woN").'
>> >>>>>> myusername@REDACTED's password:
>> >>>>>> "Now what is happening here and how do I stop it?!"
>> >>>>>> """
>> >>>>>>
>> >>>>>> So... I can still run arbitrary erlang commands, how do I stop
>> this?
>> >>>>>> Unable to find an option to pass in or anything through a quick
>> code
>> >>>>>> perusal to no avail.  Help?
>> >>>>>> _______________________________________________
>> >>>>>> erlang-questions mailing list
>> >>>>>> erlang-questions@REDACTED
>> >>>>>> http://erlang.org/mailman/listinfo/erlang-questions
>> >>>>>
>> >>>>>
>> >>>>>
>> >>>>> _______________________________________________
>> >>>>> erlang-questions mailing list
>> >>>>> erlang-questions@REDACTED
>> >>>>> http://erlang.org/mailman/listinfo/erlang-questions
>> >>>>>
>> >>>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20131211/cae256c3/attachment.htm>


More information about the erlang-questions mailing list