Pair of local privilege escalation vulnerabilities in Pihole <5.0 and <5.1

tl;dr

CVE-2020-12620: edit /etc/pihole/dnsserver.conf to append &&/tmp/reverseshell.sh to an ip address to get root shell on <5.0

CVE-2020-14162: sudo pihole -a setdns 1.1.1.1&&bash to get root shell (need to be able to run pihole with UID 0, www-data can) on <5.1


This discovery started with me running grep -R exec *.php on the source code for AdminLTE to look for command injection vulnerabilities, which lead to me discovering this line of code on line ~411 in savesettings.php

_vulnerable line

Going up the DU chain I didn’t see any point where the $IPs variable is sanitized, however the variable is the result of a file read of /etc/pihole/dnsserver.conf, which means it can’t be exploited by just having access to the web console, you’ll also need write access to that file.

This file is a list of semicolon separated IP addresses that can be selected to be pihole’s upstream DNS server. I tried appending a command to the end of an IP address to see what would happen. The only thing that I could get to work was appending &&/tmp/evil.sh to the end of an IP, where evil.sh is a reverse shell script.

_conf file

The next time the upstream DNS server is saved through the Admin Console with that IP selected, evil.sh will execute.

_revshell

An obscure use case but a vulnerability nonetheless. This was patched on 5.0 and assigned CVE-2020-12620.


What I didn’t notice at first was that this really shouldn’t have returned a root shell. I thought that the command being run was sudo pihole -a setdns 1.1.1.1&&/tmp/evil.sh, which should return a shell as www-data, not root, since sudo doesn’t carry over to the command on the other side of the double ampersands.

You can test this yourself by running sudo whoami&&whoami.

I didn’t think too much of this though, because at the time www-data could run any command with sudo without a password. However, the developers later restricted www-data to only be able to run pihole as root.

Digging deeper it turns out that what is going on here is that the setdns command in pihole is setting an environment variable to be equal to the provided value, which is then sourced. The shell metacharacters in the environment variable’s value is causing code to be executed as it is sourced. The command being run was actually sudo pihole -a setdns "1.1.1.1&&/tmp/evil.sh" and I just didn’t notice the quotation marks.

Which means that we can just run sudo pihole -a setdns "1.1.1.1&&bash" from the command line and get a root shell if we have permission to run that command with sudo and nothing else.

_rootshell.yml

This makes pihole <5.1’s CLI a GTFObin. While GTFObins aren’t normally CVE worthy, www-data having permission to run this with sudo by default makes this a vulnerability, since it effectively turns any RCE in the website into root access. This was assigned CVE-2020-14162.

This also means that the original exploitation method of editing the dnsserver.conf file is actually exploiting both CVEs in parallel (you could technically exploit CVE-2020-12620 by itself by appending " && /tmp/evil.sh instead, but there’s not much of a reason to)


Timeline:

2020-04-22: Contacted Pihole team for initial vulnerability

2020-04-24: Received reply from Pihole

2020-05-01: CVE-2020-12620 assigned, informed Pihole developers

2020-05-03: patch applied for release with 5.0 update

2020-05-10: 5.0 released

2020-06-08: contacted pihole team for second vulnerability

2020-06-13: pihole team replied and applied a patch for release with 5.1 update

2020-07-15: 5.1 released

2020-07-21: published writeup with go-ahead from the developers