Privilege Escalation Leads to User File Storage leakage on PythonAnywhere.com Web Console
Intro
It’s been a while since I’ve a spare time to write a post. Generally speaking, it’s supposed to be my first time reporting a security bug for Bug Bounty program. Thus, please spare me if there’s something irrelevant on my writing.
I suppose let’s get into it, shall we?
TL;DR
Originally, it was just a pure coincidence that I learned about Dirty Pipe (CVE-2022–0847) a few days later after it’s being disclosed. During that time, I tried to search for any coding platform that has a sandbox functionality to test out the current exploit. It was until I opened python.org that likely has a builtin web console which is currently hosted on PythonAnywhere.com that to my surprise was using 5.8.0-1041
Linux kernel.
PythonAnywhere itself is an online integrated development environment and web hosting service based on the Python programming language. It’s a great platform with a good service that I used to learn a Python back in the past day.
Short story, PythonAnywhere provides a sandbox environment with limited features depending on the account’s plan you have. Furthermore, all accounts have its own isolated environment including /home
, /etc
, /var
, /bin
, and /tmp
directory. Later, I found that it was a chroot-based environment instead of container-based which basically could be jail-broken if only if a user has a root
access. Unfortunately, I didn't have a chance to get deep into it after the bug-fix was implemented.
Therefore, I will only cover a bit of my little finding during that time
Finding
1. Getting into Privilege Escalation
As stated previously, I got a root
access by executing Dirty Pipe Exploit which is can be used to overwrite any file in the page cache. For simplicity I used this code to hijack a SUID binary in order to spawn a crafted shell with SUID & GUID of 0 (root).
Note that PythonAnywhere has a http-squid
server that acts as a HTTP-proxy with its own whitelist. Thus, the code needed to be hosted on a supported domain-name (e.g., pastebin.com) if you want to download it externally. Shortly after, the code could be compiled using builtin gcc
& ready to be executed.
2. Abusing the Sandbox
It’s been a long dream for PythonAnywhere user to be able to make use of apt install
in the console independently. Normally, any user is limited to install any packages/modules natively except using python-pip
or compiling from a source code. There was also an occasion where a user asked admin to install a certain packages in a forum thread.
Based on those circumstances, no wonder if having apt install
is a must do stuff after obtaining a root
access. Unfortunately, the sandbox shell didn't really have a capability to execute this command properly due to /etc/passwd
and /etc/group
being stripped significantly. This issue was quickly resolved by adding root
and _apt
user into /etc/passwd
& adding some default entries from /etc/group
skel.
By doing so, it could potentially give user more flexibility to do some malicious stuff to the console environment
3. Scanning the Internal Network
By resolving the apt
issue, I managed to install nmap
& scanned the internal services. Normally, it could also be done by forwarding the SSH SOCKS proxy but I would like to skip the trouble.
During this process, I checked /etc/hosts
beforehand and managed to found that log.server
has an open NFS service
that could only be accessed within 10.0.0.0/8
subnet.
By installing nfs-common
package, I managed to mount the NFS drive directly from the console. To my surprise it even has rw
permission which is certainly could be tampered maliciously.
4. Accessing other User’s File Storage
Having found the NFS service of log.server
made me believe that may be there's a NFS service for user file storage
too. Thus, I checked the mount point and found that my assumption was indeed true. Moreover, it has the same rw
permission as the previous one, thus made an ineligible user to potentially access/modify/remove other user's file storage.
5. Escaping the Jail
I won’t go even further with this one. I realized that it could be a chroot
environment since I’d seen chroots_templates
from /proc/mounts
.
Basically, it could be accomplished by executing chdir
as much as you can until it escapes the chroot shell. As a result, user could access the primary server with root
access. Here's a screenshot of having executed command on jailbroken
shell.
Impact
- User can fully make use of the limited console that should not supposed to be allowed by doing privilege escalation to
root
user - User can access/modify/remove other user’s file storage by mounting the NFS directory as
root
user - The exploit itself isn’t only limited to registered user’s console, but also can be accessed and used on Python.org console as
anonymous user
. This can be achieved by spawning a bash shell
Conclusion
Timeline
- March 9, 15:56 UTC: Bug found and reported to PythonAnywhere
- March 9, 18:23 UTC: Submitted report marked as a valid bug
- March 9, 18:35 UTC: Initial shell mitigation started
- March 10, 17:38 UTC: New kernel update implemented
- March 11, 02:59 UTC: System is no longer vulnerable to CVE-2022–0847
- March 11, 20:48 UTC: PythonAnywhere offered a bounty worth $$$$