Asana takes security seriously, and ourΒ Security teamΒ also knows how to have fun. When we shifted to working remotely during the pandemic, we wanted to create space to continue toΒ socialize and have funΒ with our team. We started a tradition of having a monthly βfunβ activityβfrom playing classic board games, to video games,Β to even painting together. Last month, we chose to participate in theΒ Central InfoSecΒ Capture-The-Flag hacking event. After the competition is over, teams often share their solutions to some of the trickier problems in the CTF. Take a look at how our team (βTeam Yetiβ) solved two of the pen testing challenges, or pwn challenges, together: βHack Not Rootβ and βHack Rootβ.Β
A CTF is an information security (InfoSec) hacking contest in which teams compete to build their security skills through hands-on activities that lead them toΒ flagsΒ that are worth points. AΒ flagΒ is a secret code word that is revealed when you solve a challenge. The team with the most points at the end of the competition wins. The activities run the gamut: game show-style InfoSec questions, reverse-engineering code, solving cryptographic puzzles, and simulated penetration testing (βpen testingβ), which means attempting to hack into a network, application, or system set up by the CTFβs organizers.
The pen testing challenges began with a mysterious link: a βVULNERABLE VM DOWNLOAD: CIS-WEBSRV01β. We navigated through a series of challenges that led us through configuring the VM, setting it up, and discovering some of the software and systems already installed on the VM. True to its name, the VM was running multiple web servers, FTP instances, a MySQL instance, and various other kinds of software.
The previous challenges had left us the trail of breadcrumbs we needed for βHack Not Rootβ and βHack Root.β We got access to an unprivileged account over ssh (creatively named βsshβ). We had also found a mysql server on the system running on the default port 3306, and had managed to log into the mysql application with the usernameΒ rootΒ and no password. For these challenges, we needed to gain access to the βtcβ and βrootβ system accounts respectively (which are separate from theΒ mysqlΒ accounts of the same name), and needed to be able to execute commands as these users.
First thingβs first: Reconnaissance. We needed to know what was on the system to know how to hack it. Using our ssh access to the ssh account, we ran the ps aux command to list the processes running as theΒ tcΒ user:
ssh@CIS-WEBSRV01:~$ ps aux | grep β tc β
1534 tc {mysqld_safe} /bin/sh /usr/Local/mysql/bin/mysqld_safe --datadir=/home/tc/mysql/data --socket=/tmp/mysql.sock --pid-file=/tmp/mysql.pid
1707 tc /usr/Local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir= /home/tc/mysql/data --plugin-dir=/usr/Local/mysql/lib/plugin --log-error=/home/tc/mysql/data/CIS-WEBSRV01.err --pid-file=/tmp/mysql.pid --socket=/tmp/mysql.sock
1841 ssh grep tc
Note: A wget process, triggered every 5 minutes by a cron job, was also running asΒ tc. It was relevant to a different problem in the CTF,Β but we didnβt see an obvious way to exploit wget to hackΒ tc.
It was clear thatΒ mysqlΒ presented our primary attack surface. SinceΒ mysqlΒ was running as tc, we could escalate our own privileges to tc by hacking into mysql and executing commands on its behalf β as tc.
To attack MySQL, we first turned to its infamousΒ SELECT ... INTO OUTFILEΒ command that has made InfoSec history as an easily-exploited vulnerability.Β
In the 2000s and 2010s, a popular technology for hosting websites was the so-called LAMP stack β aΒ Linux operating system, anΒ Apache HTTP server, aΒ MySQL database, andΒ PHP for server-side scripting. A common exploit strategy at the time was to look for text fields in the website that were vulnerable to SQL injection: if the PHP application didnβt sanitize user input to remove SQL queries or code (using something likeΒ mysqli_real_escape_string), or used raw query strings instead of a prepared statement-based API, a skilled intruder essentially had full access to the databaseβs permissions and contents.Β
These SQL injection vulnerabilities were most exploitable when accompanied by overly generous permissions for the default MySQL user. If the administrator had not removed FILE permissions from this user, and the web directory was writable, the intruder could use theΒ INTO OUTFILEΒ SQL clause to create a .php file with the contents of their choosing. Visiting that newly created PHP fileβs page on the web would then execute the intruderβs php code on the server, allowing them to take full control of the machine. This attack could turn benign text fields into full-access backdoors.
We launched a similar attack, and asked MySQL to output the results of a SELECT query to a PHP file. We carefully chose the directory we asked MySQL to write the file to. We needed to break into a directory writable byΒ tc, and we also needed the directory to be configured to execute PHP files.Β
The two apache web-root directories weβd found while working on other challenges were good candidates βΒ we knew from previous challenges that php scripting had been enabled in apache. We were hoping that apache (and by extension php) was running as root. Using our unprivileged ssh access to runΒ ls -lah, we discovered that one of these web accessible directories was owned by tc. Cha-ching!Β We injected code into a SELECT command, and instructed mysql to output the results as a PHP file to
/usr/local/apache2/htdocs/hack-the-command/cmd.php
Alas, no dice.Β We discovered that apache was instead running as the userΒ nobody, and notΒ tcΒ orΒ rootΒ βΒ and so our PHP file ran without the escalated privileges we were hoping for.Β
We might have been able to escalate privileges by creating another file of some kind, but we couldnβt think of anything obvious.
We next thought to check the version of mysql running on the webserver β crossing our fingers and hoping for one with an easily-exploitable vulnerability.
We searched for this version of MariaDB,Β 10.4.11, in the βCommon Vulnerabilities and Exposuresβ (CVE) database βΒ a key resource for any InfoSec professional βΒ and found the criticalΒ CVE-2021-27928Β vulnerability. This particular MariaDB version allows users with SUPER mysql privileges to make runtime changes to the global mysql variableΒ wsrep_providerΒ β which points to a shared object that mysql attempts to load with dlopen(). IfΒ wsrep_providerΒ is changed during runtime, MariaDB re-loads the .so file!Β
While MariaDB complains if the library doesnβt expose the APIs it expects, it canβt abort the execution before running all the functions marked as constructors βΒ which dlopen() runs by default. The upshot? A user with SUPER privileges can essentially execute arbitrary code as the user mysql runs as.Β Β
We got to work on building our wsrep_provider impersonator. On our own machine (not on the VM), we created a shared library file (the equivalent of a .dll for our Windows-loving readers) that would spawn a βreverse shellβ immediately after it was instantiated β a shell session established over a connection initiated from the VM (rather than the remote user, as is the case with SSH). We hardcoded the reverse shell to connect to our machineβs IP and an arbitrarily chosen port. Whichever user executed this shared library function on the VM would essentially give us access to an interactive shell with that userβs permissions. Voila!Β
We compiled our βwsrep providerβ withΒ gcc: gcc exploit.c -fPIC -sharedΒ -o exploit.soΒ (We were compiling on x86-64 linux, the same as our target; if you were cross compiling you would need additional arguments.) TheΒ -fPICΒ flag made the libraryΒ relocatable, so that it could be used as a dynamically linked object.Β
We used our ssh access to the ssh user to transfer our .so shared library file to the VM. As simple as scp!Β
To prepare for the exploit, we launched a netcat instance on our machine to listen for the connection request from our VMβs reverse shell.
Note: You would need to add the -p flag if you were using GNU netcat instead of BSD netcat.
We then reconnected to the VMβs mysql instance, and launched the exploit. We loaded our compiledΒ .soΒ file as the implementation of our wsrep provider. MariaDBΒ loaded the shared library object and executed the constructor function:
MariaDB complained about how poorly implemented our wsrep provider was, but not before running the constructor and spawning a reverse shell for the user mysql was running as β the fallen tc. They put up a good fight.
Back in the shell on our own machine, we watched: the nc process connected to an interactive remote shell. A quick run of ls and id confirmed that our plan had worked, and we now had full access to theΒ tcΒ user!
From there, getting access toΒ rootΒ was a cakewalk. Since tc was allowed to use sudo, we ranΒ sudo /bin/su. The id command again confirmed our escalated privileges. We then decided to use our newfound privileges to remotely write βI AM ROOT!β on the VMβs login screen.
And thus we solved the problem!
This was a fun experience and we ended up coming inΒ third place. Most of our team hadnβt participated in a CTF before, and the mix of skills on the team created a valuable learning and bonding opportunity for us all. It was also exciting and refreshing to use our security skills in a slightly different way, and get on the βother sideβ for a moment βΒ disarming rather than securing a system. Thank you to Central InfoSec for putting the contest together!
Last of all, weβre hiring! If solving challenges like this one sounds fun and you want to learn more about the impact the Security team has at Asana, check out ourΒ open positions.
This article was written by Brian Wolff & Harshita Gupta. They share their special thanks to Central InfoSec for hosting the contest.