Local users becoming root using su without password authentication due to wrong PAM config

Written by - 1 comments

Published on - Listed in Linux Security


Today I had to investigate a weird behaviour on an Ubuntu 18.04 server, which was installed a couple of months ago but (luckily) was not yet taken into production. The problem on this particular server? Every local user could just become root using the su command, without further authentication or password. 

Note: su is not the same as sudo!

Becoming root using su

On a machine behaving normally, running su asks for the root password:

admck@WM2856l ~ $ su -
Password: ***********
WM2856l ~ # 

But on this Ubuntu 18.04 server, it looked different:

admck@ubuntu:~$ su -
root@ubuntu:~# whoami
root

No password prompt - you're in. That easy. Too easy. Not good!

And because it wasn't me who configured that particular server, I was not sure if a bad configuration or, worse, a hack would be the source of this behaviour. 

Spotting the diff when running su

To figure out what actually happens in the background, I ran the su command on two Ubuntu 18.04 servers and on a second terminal used strace on the bash process of my user.

Note: The output is huge (what did you expect, it's strace!), so I only show the relevant part.

On the correctly behaving server:

[pid 22730] stat("/etc/pam.d", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid 22730] openat(AT_FDCWD, "/etc/pam.d/common-auth", O_RDONLY) = 4
[pid 22730] fstat(4, {st_mode=S_IFREG|0644, st_size=1249, ...}) = 0
[pid 22730] read(4, "#\n# /etc/pam.d/common-auth - authentication settings common to all services\n#\n# This file is included from other service-specific PAM config files,\n# and should contain a list of the authentication modules that define\n# the central authentication scheme for use on the system\n# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the\n# traditional Unix authentication mechanisms.\n#\n# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.\n# To take advantage of this, it is recommended that you configure any\n# local modules either before or after the default block, and use\n# pam-auth-update to manage selection of other modules.  See\n# pam-auth-update(8) for details.\n\n# here are the per-package modules (the \"Primary\" block)\nauth\t[success=1 default=ignore]\tpam_unix.so nullok_secure\n# here's the fallback if no module succeeds\nauth\trequisite\t\t\tpam_deny.so\n# prime the stack with a positive return value if there isn't one already;\n# this avoids us returning an error "..., 4096) = 1249
[pid 22730] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/security/pam_unix.so", O_RDONLY|O_CLOEXEC) = 5
[pid 22730] read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000)\0\0\0\0\0\0@\0\0\0\0\0\0\0\260\344\0\0\0\0\0\0\0\0\0\0@\0008\0\7\0@\0\33\0\32\0\1\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\224\315\0\0\0\0\0\0\224\315\0\0\0\0\0\0\0\0 \0\0\0\0\0\1\0\0\0\6\0\0\0\320\332\0\0\0\0\0\0\320\332 \0\0\0\0\0\320\332 \0\0\0\0\0\264\10\0\0\0\0\0\0000\311\0\0\0\0\0\0\0\0 \0\0\0\0\0\2\0\0\0\6\0\0\0\260\335\0\0\0\0\0\0\260\335 \0\0\0\0\0\260\335 \0\0\0\0\0\20\2\0\0\0\0\0\0\20\2\0\0\0\0\0\0\10\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0\310\1\0\0\0\0\0\0\310\1\0\0\0\0\0\0\310\1\0\0\0\0\0\0$\0\0\0\0\0\0\0$\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0P\345td\4\0\0\0\370\275\0\0\0\0\0\0\370\275\0\0\0\0\0\0\370\275\0\0\0\0\0\0\304\1\0\0\0\0\0\0\304\1\0\0\0\0\0\0\4\0\0\0\0\0\0\0Q\345td\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0R\345td\4\0\0\0\320\332\0\0\0\0\0\0\320\332 \0\0\0\0\0\320\332 \0\0\0\0\0000\5\0\0\0\0\0\0000\5\0\0\0\0\0\0\1\0\0\0\0\0\0\0\4\0\0\0\24\0\0\0\3\0\0\0GNU\0S\367\24\357\246\321\340W \22\273\273\353\271>\352\2253\241q\0\0\0\0\10\0\0\0s\0\0\0\1\0\0\0\6\0\0\0\3\30\201\r \200@\0s\0\0\0\0\0\0\0u\0\0\0v\0\0\0w\0\0\0\0\0\0\0x\0\0\0\0\0\0\0P`^B\301\225Y\346\333\253a\374\313\306\36\377\r\226z2w\371=L\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\234\4\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0I\1\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0z\0\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\272\1\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\261\3\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\r\3\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\232\0\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\336\3\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0c\0\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\333\1\0\0\22\0\0\0\0\0\0\0\0\0\0\0", 832) = 832

On the server behaving abnormal:

[pid   709] stat("/etc/pam.d", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
[pid   709] openat(AT_FDCWD, "/etc/pam.d/common-auth", O_RDONLY) = 4
[pid   709] fstat(4, {st_mode=S_IFREG|0644, st_size=2299, ...}) = 0
[pid   709] read(4, "#\n# /etc/pam.d/common-auth - authentication settings common to all services\n#\n# This file is included from other service-specific PAM config files,\n# and should contain a list of the authentication modules that define\n# the central authentication scheme for use on the system\n# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the\n# traditional Unix authentication mechanisms.\n#\n# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.\n# To take advantage of this, it is recommended that you configure any\n# local modules either before or after the default block, and use\n# pam-auth-update to manage selection of other modules.  See\n# pam-auth-update(8) for details.\n\n# pre_auth-client-config # # here are the per-package modules (the \"Primary\" block)\n# pre_auth-client-config # auth\t[success=5 default=ignore]\tpam_krb5.so minimum_uid=1000\n# pre_auth-client-config # auth\t[success=4 default=ignore]\tpam_unix.so nullok_secure try_first_pass\n# pre_auth-client-config # "..., 4096) = 2299
[pid   709] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/security/pam_krb5.so", O_RDONLY|O_CLOEXEC) = 5
[pid   709] read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20.\0\0\0\0\0\0@\0\0\0\0\0\0\0(\341\0\0\0\0\0\0\0\0\0\0@\0008\0\7\0@\0\32\0\31\0\1\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\304\313\0\0\0\0\0\0\304\313\0\0\0\0\0\0\0\0 \0\0\0\0\0\1\0\0\0\6\0\0\0\260\320\0\0\0\0\0\0\260\320 \0\0\0\0\0\260\320 \0\0\0\0\0X\17\0\0\0\0\0\0`\17\0\0\0\0\0\0\0\0 \0\0\0\0\0\2\0\0\0\6\0\0\0P\332\0\0\0\0\0\0P\332 \0\0\0\0\0P\332 \0\0\0\0\0\20\2\0\0\0\0\0\0\20\2\0\0\0\0\0\0\10\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0\310\1\0\0\0\0\0\0\310\1\0\0\0\0\0\0\310\1\0\0\0\0\0\0$\0\0\0\0\0\0\0$\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0P\345td\4\0\0\0\270\270\0\0\0\0\0\0\270\270\0\0\0\0\0\0\270\270\0\0\0\0\0\0l\2\0\0\0\0\0\0l\2\0\0\0\0\0\0\4\0\0\0\0\0\0\0Q\345td\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0R\345td\4\0\0\0\260\320\0\0\0\0\0\0\260\320 \0\0\0\0\0\260\320 \0\0\0\0\0P\17\0\0\0\0\0\0P\17\0\0\0\0\0\0\1\0\0\0\0\0\0\0\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\241\230\310\r\10\314\352d\360\216&\276\317\177\205+\321\212\253n\0\0\0\0\3\0\0\0p\0\0\0\1\0\0\0\6\0\0\0\3\30\201\r \200@\0p\0\0\0t\0\0\0u\0\0\0\332\253a\374P`^Bv\371=L\301\225Y\346\r\226z2\313\306\36\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\223\7\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\324\3\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0R\6\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\311\2\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<\3\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0&\2\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\261\7\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\313\0\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\3\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\7\0\0\22\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\20\0\0\0 \0\0\0", 832) = 832

A difference can be seen right after opening /etc/pam.d/common-auth:

Correct server: /etc/pam.d -> /etc/pam.d/common-auth -> /lib/x86_64-linux-gnu/security/pam_unix.so

Incorrect server: /etc/pam.d -> /etc/pam.d/common-auth -> /lib/x86_64-linux-gnu/security/pam_krb5.so

The question now is: Why does /etc/pam.d/common-auth load the pam_krb5.so (Kerberos auth) module instead of the standard pam_unix.so (local Unix account) module?

Comparing /etc/pam.d/common-auth

Obviously something must be different in /etc/pam.d/common-auth. A side by side comparison reveled quite a difference:

admck@WM2856l ~ $ diff /tmp/common-auth-correct /tmp/common-auth-weird
16,19c16,23
< # here are the per-package modules (the "Primary" block)
< auth    [success=1 default=ignore]    pam_unix.so nullok_secure
< # here's the fallback if no module succeeds
< auth    requisite            pam_deny.so
---
> # pre_auth-client-config # # here are the per-package modules (the "Primary" block)
> # pre_auth-client-config # auth    [success=5 default=ignore]    pam_krb5.so minimum_uid=1000
> # pre_auth-client-config # auth    [success=4 default=ignore]    pam_unix.so nullok_secure try_first_pass
> # pre_auth-client-config # auth    [success=3 default=ignore]    pam_sss.so use_first_pass
> # pre_auth-client-config # auth    [success=2 default=ignore]    pam_ccreds.so minimum_uid=1000 action=validate use_first_pass
> # pre_auth-client-config # auth    [default=ignore]        pam_ccreds.so minimum_uid=1000 action=update
> # pre_auth-client-config # # here's the fallback if no module succeeds
> # pre_auth-client-config # auth    requisite            pam_deny.so
23,26c27,36
< auth    required            pam_permit.so
< # and here are more per-package modules (the "Additional" block)
< auth    optional            pam_cap.so
< # end of pam-auth-update config
---
> # pre_auth-client-config # auth    required            pam_permit.so
> # pre_auth-client-config # # and here are more per-package modules (the "Additional" block)
> # pre_auth-client-config # auth    optional            pam_ccreds.so minimum_uid=1000 action=store
> # pre_auth-client-config # auth    optional            pam_cap.so
> # pre_auth-client-config # # end of pam-auth-update config
> auth    [authinfo_unavail=ignore success=1 default=2] pam_krb5.so use_first_pass ignore_root debug
> auth    [success=done default=ignore]   pam_unix.so nullok_secure debug
> auth    [default=done]  pam_ccreds.so action=validate use_first_pass
> auth    [default=done]  pam_ccreds.so action=store
> auth    [default=bad]   pam_ccreds.so action=update

But what did cause the change of /etc/pam.d/common-auth?

The auth-client-config did it!

At least there are quite a few comments in /etc/pam.d/common-auth pointing to "auth-client-config". Checking the apt history of that server, this package was indeed manually installed:

Start-Date: 2019-01-22  13:40:56
Commandline: apt install krb5-user libpam-krb5 libpam-ccreds auth-client-config
Requested-By: nzzadmin (1000)
Install: libpam-ccreds:amd64 (10-6ubuntu1), libkdb5-9:amd64 (1.16-2ubuntu0.1, automatic), krb5-user:amd64 (1.16-2ubuntu0.1), libkadm5srv-mit11:amd64 (1.16-2ubuntu0.1, automatic), libgssrpc4:amd64 (1.16-2ubuntu0.1, automatic), libpam-krb5:amd64 (4.8-1), krb5-config:amd64 (2.6, automatic), libkadm5clnt-mit11:amd64 (1.16-2ubuntu0.1, automatic), auth-client-config:amd64 (0.9ubuntu1)
End-Date: 2019-01-22  13:40:59

And in the bash history a few commands after the installation I came across the actual command which changed the pam configs:

root@ubuntu:~# history| grep auth-client
   49  apt install krb5-user libpam-krb5 libpam-ccreds auth-client-config
   58  sudo auth-client-config -a -p kerberos_example

So is the use of auth-client-config a security risk?

This issue is old...

During my research I came across an old Ubuntu bug (#526999) from 2010 which describes exactly this problem. The bug was never fixed, instead it was closed as invalid:

This is not a security vulnerability as the file you are using is an example and not intended for production use. It says right in the profile /etc/auth-client-config/profile.d/acc-default:
#
# this example is for using kerberos to authenticate. Has been used with nss-updatedb, libpam-krb5 and libpam-ccreds. Sould also work with libpam-heimdal. This is only an example, and you may have to create your own profiles to authenticate with your system.
#
[kerberos_example]

I will verify that the example works as intended.

But if this is such an old issue, why would the administrator who installed the servers, run this "evil" command in the first place?

... yet shows up in updated official documentations

It turns out that this command is mentioned in the official Ubuntu 18.04 Kerberos Server Guide:

Next, use the auth-client-config to configure the libpam-krb5 module to request a ticket during login:

sudo auth-client-config -a -p kerberos_example

You will should now receive a ticket upon successful login authentication.

One learns from the Ubuntu bug above that using the kerberos_example profile is a bad idea. But showing it on the official Ubuntu Server Guide isn't much of help either.

OK, now that we understood who and how these changes happened, it's time to fix it. 

Fixing /etc/pam.d/common-auth

Let's go through each line which was added by auth-client-config in /etc/pam.d/common-auth. 

auth    [authinfo_unavail=ignore success=1 default=2] pam_krb5.so use_first_pass ignore_root debug

This line with krb5.so is the actual bad boy. It allows an immediate login as root without password prompt:

admck@ubuntu:~$ su -
root@ubuntu:~# whoami
root

After disabling/commenting it a password prompt came up. However I was able to become root by just hitting [Enter] instead of typing in a password.

admck@ubuntu:~$ su -
Password:
You have been logged on using cached credentials.
root@ubuntu:~# whoami
root

That's almost as bad as not having to enter a password at all. The reason for this are cached credentials, caused by these lines:

auth    [default=done]  pam_ccreds.so action=validate use_first_pass
auth    [default=done]  pam_ccreds.so action=store
auth    [default=bad]   pam_ccreds.so action=update

These lines are responsible for caching the credentials. After disabling them I could not run su - anymore:

admck@ubuntu:~$ su -
su: Permission denied
admck@ubuntu:~$

So I added the default auth from lines from a standard installation at the end:

auth    requisite                       pam_deny.so
auth    required                        pam_permit.so
auth    optional                        pam_cap.so

But now I just got Authentication failure without ever getting a password prompt:

That's obvious because my local Unix account was not checked. So before these 3 lines I added another one which checks for Unix account:

auth    [success=1 default=ignore]      pam_unix.so nullok_secure
auth    requisite                       pam_deny.so
auth    required                        pam_permit.so
auth    optional                        pam_cap.so

Note: This is the default config of /etc/pam.d/common-auth.

Now I get a password prompt. Testing if I can login with an empty password:

admck@ubuntu:~$ su -
Password:
su: Authentication failure

That looks better, the empty password was refused. What about the correct password:

admck@ubuntu:~$ su -
Password: ********
root@ubuntu:~# whoami
root

Great. Now it's the same behaviour as expected.

But what about the Kerberos users?

That's actually the big question. Why was Kerberos installed in the first place? On this server there's a Samba server running which was integrated into the local Active Directory. AD-users should authenticate and be able to connect to the Samba shares using their AD credentials; using Kerberos as authentication mechanism.

However it turns out that /etc/pam.d/common-auth has no effect Samba authentication so this change was not necessary at all. By setting common-auth to the default (see above), AD users were still able to authenticate using their AD credentials yet security for local users was re-established. 

If this isn't enough proof to raise some sane skepticism concerning documentations on the Internet, whether they are official or not, I don't know what is. 


Add a comment

Show form to leave a comment

Comments (newest first)

Felipe from Great article!! wrote on Aug 21st, 2019:

Really helped me find out what was happening with my Kerberos SSH setup.
I had followed the official Ubuntu and after a week of testing someone came and showed it to me that no password was needed anymore... what a shame! shame on ubuntu documentations..
I found very little on the internet about this topic.
I will post on my site how I did my setup.
Thanks a million for the clarification


RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder