RCE via failed regex check — One dot to rule ’em all!

Let’s learn about how a failed regex check led to RCE in PiHole Admin panel.

SecurityGOAT
6 min readAug 11, 2021

Introduction

Straight from the Github page of pi-hole AdminLTE project:

Pi-hole®’s Web interface (based off of AdminLTE) provides a central location to manage your Pi-hole and review the statistics generated by FTLDNS.

Great, so this is an admin panel for managing Pi-hole, which is:

The Pi-hole® is a DNS sinkhole that protects your devices from unwanted content, without installing any client-side software.

https://github.com/pi-hole/AdminLTE

Interestingly enough, I found a tweet and an advisory mentioning how a single dot lead to RCE in the admin panel for Pi-hole! We will dive deeper into the details of this in the next section.

The Issues

As you can see in the advisory screenshot, RCE is possible in Web Interface 5.5!

In more granular terms, the validDomainWildcard preg_match filter allows a malicious character through and that
can be used to:
- execute code,
- list directories,
- and overwrite sensitive files

Vulnerable Code

This vulnerability happens in 2 steps/stages.

Step 1 is where the attacker’s commands get added to a config file and Step 2 is where their commands get executed since the config file gets source’d!

The above code contains a regex that is responsible for the first stage of this vulnerability:

$validChars = preg_match(“/^((\*.)?…

As you can see there’s a dot (.) which, loosely speaking, is a special character used to match any one character.

And this vulnerable function is called in 2 places, one of which contains a non-so-appealing sink — a sink which adds the contents of their choice to a config file (pihole_execute) which is highlighted in the image below!

Now as you can see in the above code, the vulnerable function is used to check if the value passed for the $client variable is following the pattern specified in the regex or not. If it does, then it goes to the execution sink that would set the value for a config variable, which at the end of the malicious request would contain a command execution payload.

So a sample request would look something like this:

Payload: *;ls

The payload went through all the checks, I suppose! Don’t see any errors or complains from the server, do we? :)

If you check the config file — “/etc/pihole/setupvars.conf”:

Now you might be things, yes fine, you got this value into the file! It’s good but where is the RCE, you promised?

Unless you manually go and source the file, I don’t see any issue there… So we are safe then? No… we aren’t!

To trigger the sourcing we simply need to run go to the gravity endpoint
“/admin/gravity.php” and click update. And (bam!) shell started to rains!

Hahahaha, okay maybe not the rain, but the command injection output does indeed shows up!

So we get the output of the command as well!

So, recapping the stuff we did till now were helpful in command execution.

Now File overwrite!

If you send a payload of *>FILENAME, then you can effectively overwrite any file in “/var/www/html/admin/scripts/pi-hole/php/” directory, effectively breaking PiHole if some important file gets emptied out!

You can even overwrite the files for other users like root for instance (if PiHole application runs as that user) by setting the domains & clients parameter in the request to the following payload:

domains=*;cd&clients=*>.bashrc

So the payload in the domains parameter would result in changing directory to the root user (assuming PiHole is running as root) and the other half (setting the client) would empty the .bashrc file for that user.

You can get creative now and runs any commands that you wish!

The researcher who reported this issue also posted the script to automate this attack to avoid the manual effort of intercepting and modifying the requests!

You can check more on that here in the Proof of Concept section.

Extra Bits

Another important thing to be noted would be that the regex pattern used by the application was quite complex and thus a malicious user could send arbitrarily large or crafted input that can hang up the PiHole server due to it processing this complex regex which results in a lot of input states (attributed to the complexity of the regex ofcourse!).

So that would be ReDoS attack, nothing flashy, a simple DoS leveraging the complex regex definition which can accept any arbitrary input and can have a lot of resulting states and thus, if you send an invalid and complex pattern, it leads to taking up server processing time and memory!

Feel free to read more on ReDoS here.

Prevention

To avoid this attack in the first place, the regex must be amended so that the dot (.) is escaped since it is currently interpreted as a special character in regex!

An important thing to note would be that this attack happened because of a regex that seemed correct but it turned out to be doing more that expected. And thus one should also test out their regex before adding them to their scripts.

Regex are complex to write and can lead to heavy computation too, and if overused they can result in ReDoS attacks quite easily and thus try not to use them if you don’t need them and if you do need them, then make sure to test the regex pattern thoroughly with proper unit tests and also avoid accepting large inputs in the first place before passing the seemingly huge input for regex matching!

Closing Thoughts

So with that, I would close this post. I hope this post was informational and fun to read. In case you enjoyed it, please share it among your friends in the infosec community :)

I felt there were some things that I understood much better while writing this article and so I guess in the end it was worth it, and not merely a repetition of the work that the researcher did in the advisory :)

Let me know your feedback in the comments below and feel free to connect on twitter: @_SecurityGOAT

You can also send any topic you wish to learn more about. Send me DM on Twitter or let me know in the comments :)

Lastly, the line which should mostly be a plain ol’ boring one which I have to copy from my previous post every single time!!!! — if you have been enjoying my work and would love to support me, consider checking my Patreon page or you can even Buy Me a Coffee :)

See ya!
Until next time my friend, keep learning and happy hacking.

--

--