Privilege Escalation Leads to User File Storage leakage on PythonAnywhere.com Web Console

PythonAnywhere

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.

Popping a root shell using Dirty pipe

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.

Neofetch package installed
net-tools package installed

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.

Scanning for NFS service mount point
Mounting the NFS directory
Write a file into NFS directory

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.

Checking console mount points
Simulating the attack by accessing & modifying other’s user code directly from NFS service

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_templatesfrom /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 $$$$

References

--

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Muhammad Faqih Jihan Insani

Muhammad Faqih Jihan Insani

More from Medium

Design Flaw — A Tale of Permanent DOS

XSS Vulnerability Part 2

Burp Suite Extensions: How to simplify AuthZ & AuthN tests using Auto Repeater and Autorize

Writeup: CSRF where Referer validation depends on header being present @ PortSwigger Academy