summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ssh/README.altprivsep
blob: 73cdeaf80f9d9d69df5334d995138a953bc02452 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
   Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
   Use is subject to license terms.

#ident	"%Z%%M%	%I%	%E% SMI"

	Sun's Alternative "Privilege Separation" for OpenSSH


Table of Contents

1.    Introduction
2.    What is "Privilege?"
3.    Analysis of the SSH Protocols
3.1.  Privileged Resources, Operations, in the SSH Protocols
4.    OpenSSH's Privilege Separation
5.    SUNWssh's Alternative Privilege Separation
6.    Comparison of the OpenSSH and SUNWssh PrivSep Models
7.    Future Directions
8.    Guide to the AltPrivSep Source Code
A.    References





1.  Introduction

    Implementations of SSH servers require some degree of privilege in
    order to function properly.  Often such implementations retain such
    privilege throughout normal operation even while users are logged
    in.  This means that vulnerabilities in the implementation of the
    protocols can be exploited in such ways as to escalate the privilege
    that would normally be accorded to mer-mortal users.

    The OpenSSH team introduced support for "privilege separation" in
    the OpenSSH ssh server some years ago to minimize the extent of
    extant, undiscovered vulnerabilities in the OpenSSH server source
    code.  The basic concept is to have a multi-process server
    implementation where one process, the "monitor" is privileged and
    implements a smaller protocol than the ssh protocols, and thus is,
    hopefully, less likely to sport exploitable security bugs.

    The ssh team at Sun agrees with the basic OpenSSH privilege
    separation concept, but disagrees with its design.

    Here we present our alternative to the OpenSSH design.  We begin
    with the question of just what is "privilege" and follow on with an
    analysis of the SSH protocols vis-a-vis privilege.  Then we briefly
    describe the OpenSSH model, followed by an exposition of our
    alternative model.


2.  What is "Privilege?"

    Privilege, in a traditional Unix sense, is that which the "root"
    user can do that other users cannot directly do.  In Solaris 10
    there is a new approach to this sort of privilege with the aim of
    running much of the operating system with the Least Privilege
    required; root's privilege is broken down into many privileges and
    these are managed through privilege sets.  We won't go into the
    details of Solaris 10's Least Privilege facility here.

    But privilege is also access to data and resources that can be used
    to escalate the privilege of those who have access to them.  For
    example: secret, or private cryptographic keys used in
    authentication.  Network security typically requires the use of
    cryptographic keys for authentication.


3.  Analysis of the SSH Protocols

    There are two or, rather three SSH protocols:

     - version 1
     - version 1.5
     - version 2

    Version 1 and 1.5 are much the same, from our point of view; version
    2 is significantly different from the other two.

    Familiarity by the reader with the specifications for these
    protocols is not assumed, but would be beneficial to the reader.

    Quite roughly, these protocols consist of the following:

	a) initial version exchange (for protocol version negotiation)
	b) a binary encoding of message data
	c) message syntaxes for the protocols' messages
	d) specifications on use of cryptography for transport
	   privacy (encryption) and integrity protection
	e) a key exchange protocol (which also authenticates servers to
	   clients)
	f) a protocol for user authentication
	g) a session protocol
	h) a re-keying protocol (v2-only)

    Some of these parts of the ssh protocols are quite complex, some
    quite straightforward.  Altogether implementation of the ssh
    protocols requires a source code base of significant size.

    The OpenSSH implementation relies on OpenSSL for cryptographic
    service, on libz for compression service and miscellaneous other
    libraries.  Besides these OpenSSH consists of several tens of
    thousands of lines of source code in C.

    SUNWssh is based on OpenSSH, so it is comparable in size and
    complexity to OpenSSH.

    There is, then, plenty of space for security bugs in the OpenSSH,
    and, therefore, also in the SUNWssh source code bases.

    The OpenSSH team designed and implemented a "privilege separation"
    feature in their ssh server to reduce the risk that a security bug
    in OpenSSH could be successfully exploited and an attacker's
    privilege escalated.


3.1.  Privileged Resources, Operations, in the SSH Protocols

    What privileges does an SSH server need then?

    Observation with Solaris 10's ppriv(1) and truss(1) commands as well
    as analysis of the ssh protocols leads to conclude as follows.

    No privilege or privileged resources are needed to implement the
    parts (a)-(d) mentioned in section 3.


    For key exchange and server authentication (e) an ssh server requires:

     - Access to the host's ssh private keys.

     - Access to the host's GSS-API acceptor credentials.  [SSHv2-only]


    An ssh server requires practically all privileges for user
    authentication (f) (at least PAM does), particularly
    PRIV_PROC_SETID, for logging the user in.


    Post-authentication an ssh server requires the following privileges:

     - Those required for auditing a user's subsequent logout.

       That is, PRIV_PROC_AUDIT.


     - Those required for record keeping (i.e., utmpx/wtmpx logging).

       That is, either open file descriptor for those files or
       PRIV_FILE_DAC_WRITE or otherwise access to those files, perhaps
       through a special user id or group id which would be granted
       write access through the ACLs on those files.

       Since SSHv2 allows clients to open many channels with
       pseudo-terminals a server may need to open and close utmpx/wtmpx
       records multiple times in the lifetime of an SSHv2 connection.


     - Those required for accessing the host's ssh private keys for
       SSHv2 re-keying.  [SSHv2-only]

       These keys can be (and are) loaded at server startup time,
       requiring PRIV_FILE_DAC_READ, or access through file ACLs, at
       that time, but not thence.


     - Those required for accessing the host's GSS-API acceptor
       credentials for SSHv2 re-keying.

       These credentials may require a large set of privileges.  The
       Solaris 10 Kerberos V GSS-API mechanism, for example, requires
       PRIV_FILE_DAC_READ (for access to the system keytab) and
       PRIV_FILE_DAC_WRITE (for access to the Kerberos V replay cache).


    It is worth pointing out that because of a wrinkle in the
    specification of the SSHv2 protocol and various implementations,
    access to a host's ssh private keys can allow one not only to
    impersonate the host as a server (which is, in practice, difficult),
    but also to impersonate the host as a client (which is quite easy to
    do) using "hostbased" user authentication.

    It is entirely possible to have one-process server implementation
    that drops most privileges and access to privileged resources after
    user authentication succeeds.  Such an implementation would make
    some privileges, such as PRIV_PROC_SETID, available to any attacker
    that successfully exploited a security bug in the ssh server.

    But such an implementation would also have to retain access to
    resources needed for authenticating the server, which, as described
    above, can be used to impersonate the server, in some cases with
    ease.


4.    OpenSSH's Privilege Separation

    The OpenSSH privilege separation model is quite complex.

    It consists of a monitor, which retains all privileges and access to
    privileged resources, and two processes which run with much less
    privilege: one process running as a special user, "sshd," for
    hosting all phases of the SSH protocols up to and including
    authentication, and one process running as the actual user that logs
    in and which hosts all phases of the SSH protocols post-user-
    authentication.

    The monitor and its companion processes speak a private protocol
    over IPC.  This protocol is intended to be smaller and simpler than
    the SSH wire protocols.

    In practice the OpenSSH monitor protocols relating to user
    authentication are neither smaller nor simpler than the SSH user
    authentication protocols; and though they are different they also
    transport much the same data, including RSA/DSA signatures,
    usernames, PAM conversations, and GSS-API context and MIC tokens.

    The key exchange protocols have been broken down into their
    essentials and the monitor serves only services such as signing
    server replies with private host keys.

    Note also that the OpenSSH monitor protocol uses the same encodings
    as the SSH protocols and uses the same implementation of those
    encodings.


5.  SUNWssh's Alternative Privilege Separation

    The Sun Microsystems ssh team believes that the OpenSSH team has
    reached the point of diminishing returns in attempting to separate
    processing of the user authentication protocols and that the OpenSSH
    approach to privilege separation of the key exchange protocols has
    led to a situation in which the monitor acts as an oracle, willing
    to sign anything provided by the unprivileged processes that talk to
    it.

    The Sun ssh team proposes a somewhat different privilege separation
    implementation that shares with the OpenSSH model the goal of
    minimizing and simplifying the protocol spoken by the monitor, but
    little source code.

    We eschew any temptation to apply the privilege separation concept
    to the version negotiation, initial key exchange and user
    authentication phases of the ssh protocols (but see section 7).

    Instead we focus on separating processing of auditing, record
    keeping and re-keying from processing of the session protocols.  We
    also wish to avoid creating any oracles in the monitor.

    This approach allows us to have a very simple monitor protocol.  Our
    monitor protocol consists of the following operations:

     - record a new pseudo-terminal session
     - record the end of a pseudo-terminal session
     - process a re-key protocol messages
     - get keys negotiated during re-keying to the session process to it
       can use them

    Logout auditing is done when the session process dies and so does
    not require a monitor protocol message.

    By processing all re-key protocol messages in the monitor we prevent
    the creation of oracles in the monitor.  This is so because the
    monitor signs only material which it has generated and over which an
    attacker would have little influence (through the attackers offered
    DH public key, for example).

    Odds and ends:

     - If the monitor receives SIGHUP, SIGTERM or SIGINT it will call
       fatal_cleanup(), and thence will forcibly shutdown(3SOCKET) the
       ssh connection socket, causing its child to exit, and audit a
       logout.

     - The monitor does not attempt to update utmpx/wtmpx independently
       of its child -- it depends on the child asking it to.

     - The child now is unable to chown() ptys back to root.  That's Ok,
       other services on Solaris do the same and everything still works
       because of grantpt(3C).


6.  Comparison of the OpenSSH and SUNWssh PrivSep Models

    The OpenSSH server involves three processes which we will term
    "pre-session," "session" and "monitor."

    The OpenSSH pre-session process implements:

     - the ssh version string exchange
     - the ssh message encoding/decoding
     - most of the initial key exchange protocols
     - transport protection
     - part of the user authentication protocols

    The OpenSSH session process implements:

     - the ssh message encoding/decoding
     - transport protection
     - most of the re-keying protocols
     - the session protocols

    The OpenSSH monitor process implements:

     - the ssh message encoding/decoding
     - parts of the key exchange and re-key protocols (primarily signing
       of server replies with host private keys)
     - most of the user authentication protocols, specifically:

        - evaluation of ~/.ssh/authorized_keys (for pubkey userauth)
        - evaluation of known hosts files (for hostbased userauth)
        - evaluation of .shosts/.rhosts files (for hostbased userauth)
        - verification of signatures w/ public keys (pubkey, hostbased)
	- PAM API calls, conversation function
	- GSS-API calls

       Note that any vulnerabilities in the parsing of authorized_keys,
       known hosts and .shosts/rhosts files are as exploitable in the
       monitor as in a server w/o privilege separation.

       Similarly for any vulnerabilities in PAM modules and GSS-API
       mechanisms.

    The SUNWssh server involves two processes which we will term
    "session" and "monitor."

    The SUNWssh monitor process implements:

     - the ssh version string exchange
     - the ssh message encoding/decoding
     - transport protection
     - all of the key exchange and re-key protocols
     - all of the user authentication protocols

    The SUNWssh session process implements:

     - the ssh message encoding/decoding
     - transport protection
     - the session protocols

    Obviously all of these processes also implement their side of the
    monitor protocols.

    The OpenSSH 3.5p1 monitor protocol, on Solaris, has approximately 20
    monitor request and corresponding response messages.

    The SUNWssh monitor protocol has 3 monitor request and response
    messages; additionally, the monitor processes standard re-key
    messages (but note: the monitor and the session process IPC is
    completely unencrypted), which amounts to about 14 more messages
    altogether.

    Much of the OpenSSH monitor protocol is a variation of the
    on-the-wire ssh protocols, with some contents re-packaging.  We
    believe this does not afford the monitor much additional, if any
    protection from attacks in the key exchange and user authentication
    protocols.

    The re-packaging that is done in the OpenSSH monitor protocol is
    risky business.  By separating the act of signing some blob of data
    from computing that blob of data one can create an oracle; this is
    exactly what happened in the OpenSSH case.

    As you can see in the next section, the SUNWssh privilege separation
    could evolve somewhat in the OpenSSH direction by saving the monitor
    all transport protection work, but we cannot save the monitor much,
    if any work relating to authentication or key exchange.


7.  Future Directions

    The SUNWssh server privilege separation implementation could stand
    several improvements.

    The first improvement would be to have a single system-wide monitor.
    This would reduce resource consumption.  The work needed to
    implement such an enhancement is very similar to the work needed to
    produce an SSH API and library, and it is not trivial.  If this is
    not done then at least dropping PRIV_PROC_SETID and instead setting
    the saved-set-user-id in the monitor to that of the logged in user
    would be nice.

    The second enhancement would be to add a "none" host key algorithm
    to SSHv2 and a corresponding option in SUNWssh to disallow re-keying
    with any other host key algorithm.  This would allow customers to
    configure their server and monitor so that no re-key protocol
    messages need be processed by the monitor.

    A third enhancement would be to enhance the GSS-API mechanisms to
    require fewer privileges.  In practice this means overhauling the
    Kerberos V mechanism's replay cache.  This would allow the monitor
    to run with fewer privileges.

    Further, even without improving the Kerberos V mechanism's replay
    cache it should be possible to drop at least PRIV_PROC_FORK/EXEC/
    SESSION.

    A fourth enhancement would to have the unprivileged process handle
    all transport protection and proxy to the monitor all key exchange
    and user authentication protocol messages.  This is a variation on
    the OpenSSH model, but without the re-packaging of ssh message
    contents seen there.  After authentication succeeds the monitor
    could either change the unprivileged process' credentials (as can be
    done with ppriv(1) or the unprivileged process would, as in OpenSSH,
    pass the session keys/IVs/keystate to the monitor which would then
    pass them to a new process, the session process, that would then run
    as the logged in user.


8.  Guide to the AltPrivSep Source Code


    First, a brief introduction to the SUNWssh/OpenSSH source code.

    The source code is organized as follows:

	$SRC/cmd/ssh/etc/
	    |
	    +-> config files

	$SRC/cmd/ssh/include/
	    |
	    +-> header files (note: none are installed/shipped)

	$SRC/cmd/ssh/libopenbsd-compat/common/
	    |
	    +-> misc. portability source code

	$SRC/cmd/ssh/libssh/common/
	    |
	    +-> implementation of encoding, transport protection,
		various wrappers around cryptography, the key exchange
		and host authentication protocols, the session
		protocols, and misc. other code

		cipher.c
		mac.c
		compress.c
		packet.c
		    |
		    +-> transport protocol

		buffer.c
		bufaux.c
		    |
		    +-> encoding

		channels.c
		nchan.c
		    |
		    +-> session protocol

		kex.c
		kexdh.c
		kexgex.c
		    |
		    +-> key exchange/re-key code common to ssh and sshd

		kexdhs.c
		kexgexs.c
		kexgsss.c
		    |
		    +-> key exchange/re-key code (server only)

		kexdhc.c
		kexgexc.c
		kexgssc.c
		    |
		    +-> key exchange/re-key code (client only)

		dh.c
		rsa.c
		mpaux.c
		ssh-rsa.c
		ssh-dss.c
		ssh-gss.c
		    |
		    +-> crypto wrappers/utilities

		log.c
		    |
		    +-> logging, including debug logging, on stderr or
			syslog


	$SRC/cmd/ssh/ssh/
	    |
	    +-> ssh(1)

	$SRC/cmd/ssh/sshd/
	    |
	    +-> sshd(1M), including auditing, implementation of user
		authentication and the OpenSSH and SUNWssh monitors

		sshd.c
		    |
		    +-> main()

		auth*.c
		    |
		    +-> user authentication

		serverloop.c
		session.c
		    |
		    +-> session protocols

		bsmaudit.[ch]
		sshlogin.c
		loginrec.c
		    |
		    +-> auditing and record-keeping

	$SRC/cmd/ssh/<misc commands>/
	    |
	    +-> scp, sftp, sftp-server, ssh-agent, ssh-add, ...

 
    The SUNWssh altprivsep adds two new source files:

	$SRC/cmd/ssh/include/altprivsep.h
	$SRC/cmd/ssh/sshd/altprivsep.c
	    |
	    +-> monitor start routine, altprivsep_packet_*() routines
		for communication with the monitor, routines to help
		with key exchanges, service procedures for the monitor,
		etc...

    and modifies the following:

	$SRC/cmd/ssh/include/config.h
	    |
	    +> adds cpp define "ALTPRIVSEP"

	$SRC/cmd/ssh/include/ssh2.h
	    |
	    +-> adds private message type "SSH2_PRIV_MSG_ALTPRIVSEP" (254)

	$SRC/cmd/ssh/include/packet.h
	    |
	    +-> adds prototypes for several simple utility functions,
		some of which are specifically meant to avoid having to
		link altprivsep.c into ssh(1)

	$SRC/cmd/ssh/libssh/common/kex.c
	$SRC/cmd/ssh/libssh/common/packet.c
	    |
	    +-> implements the hooks needed to proxy re-key messages
		to/from the monitor

	$SRC/cmd/ssh/sshd/Makefile
	    |
	    +-> adds altprivsep.o to list of objects linked into sshd(1M)

	$SRC/cmd/ssh/sshd/serverloop.c
	    |
	    +-> adds an event loop for the monitor
		modifies the usual event loops for SSHv2

	$SRC/cmd/ssh/sshd/session.c
	    |
	    +-> modifies do_login() and session_pty_cleanup2() to call
		altprivsep_record_login/logout() instead of
		record_login/logout().

		modifies do_exec_pty() so that the server waits for the
		call to altprivsep_record_login() in child process to
		complete before returning so that the server and the
		child processes do not compete for monitor IPC I/O.

	$SRC/cmd/ssh/include/log.h
	$SRC/cmd/ssh/libssh/common/log.c
	    |
	    +-> adds an internal interface, set_log_txt_prefix() so that
		the monitor's debug and log messages get prefixed with a
		string ("monitor ") that indicates they are from the
		monitor

	$SRC/cmd/ssh/sshd/sshd.c
	    |
	    +-> modifies the body of code that follows the user
		authentication phase of the ssh protocols so as to start
		the monitor and move the relevant code into the monitor
		or session processes as appropriate while dropping
		privileges and access to privileged resources in the
		session process

    The monitor uses the packet.h interfaces to communicate with the
    session process as though it were its ssh client peer, but always
    uses the "none" cipher, mac and compression algorithms and installs
    even handlers only for the relevant key exchange messages and the
    private monitor message used for the other monitor services.

    The monitor serves the following services:

     - APS_MSG_NEWKEYS_REQ	-> used to obtain keys/IVs after re-keys
     - APS_MSG_RECORD_LOGIN	-> used to update utmpx/wtmpx
     - APS_MSG_RECORD_LOGOUT	-> used to update utmpx/wtmpx

    The session and monitor processes communicate over a pipe.

    All monitor IPC I/O from the session process is blocking (though the
    pipe is set to non-blocking I/O).  The monitor protocol is entirely
    synchronous and relies on the re-key protocols being entirely
    synchronous also (which they are, unlike the session protocols).

    The kex.c and packet.c files are minimally modified, primarily to
    prevent the monitor from handling SSH_MSG_NEWKEYS messages as a
    normal ssh server should, instead letting the session process
    process SSH_MSG_NEWKEYS messages by requesting the new keys
    negotiated with client from the monitor.

    Note that for SSHv1 no on-the-wire messages are processed by the
    monitor after authentication.  In fact, the monitor thinks it's
    running SSHv2, even if the on-the-wire protocol is v1.


A.  References

    The IETF SECSH Working Group:

	http://www.ietf.org/html.charters/secsh-charter.html

    The SSHv2 architecture, assigned numbers:

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-architecture-16.txt
	http://www.ietf.org/internet-drafts/draft-ietf-secsh-assignednumbers-06.txt

    New cipher modes for SSHv2:

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-newmodes-02.txt

    The SSHv2 "transport," including initial key exchange and re-key
    protocols, but excluding negotiable DH group size and GSS-API-based
    key exchange:

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-transport-18.txt

    Additional key exchange protocols for SSHv2:

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-gsskeyex-08.txt
	http://www.ietf.org/internet-drafts/draft-ietf-secsh-dh-group-exchange-04.txt

    Base user authentication spec for SSHv2 (includes none, password,
    pubkey and hostbased user authentication):

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-userauth-21.txt

    SSHv2 user authentication using PAM-style prompting:

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-auth-kbdinteract-06.txt

    SSHv2 user authentication using the GSS-API:

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-gsskeyex-08.txt

    SSHv2 "session" protocol (i.e., the protocol used for pty sessions,
    port forwarding, agent forwarding, X display forwarding, etc...):

	http://www.ietf.org/internet-drafts/draft-ietf-secsh-connect-19.txt