Target 🎯

Technical Vulnerability Background 🤓

Main() Function Signature

C Main Possible Signatures

main

int main int main(int argc, char *argv[]) int main(int argc, char *argv[], char *envp[])

argc

argv

argv

cat a.txt b.txt

argv

["cat", "a.txt", "b.txt", NULL]

envp

Exec*() Family Functions

Exec* family function signatures

main()

argv

Vulnerability Hunting Methodology 🔍

Unsafe string functions - These functions don't accept a length parameter and therefore require manual bounds checking on the length of the parameters passed. This bounds check can be easily forgotten by a programmer. Examples of unsafe string functions:

strcpy



strcat



sprintf (especially when used with %s)

(especially when used with %s)

scanf (especially when used with %s)

(especially when used with %s) Command execution functions - If these functions are passed strings that can even be partially controlled by a malicious user, then that's a recipe for disaster.

system



popen



exec* family functions

system

IDA shows 4 references to system

The Vulnerability 🙊

system()

system()

filename_of_exectuable

Call to system highlighted (Line 13) [view from IDA Pro decompiler]

chmod u+s <some filename>

<some filename>

we can control argv[0] with one of the exec* functions (discussed earlier) and achieve code execution

run as root

Call to the discovered vulnerable function highlighted in line 74 [view from IDA Pro decompiler]



Exploitation 🦹‍♀️

Format string our text is injected into is highlighted (Line 12) [view from IDA Pro decompiler]

filename_of_executable

chmod u+s "%s"

%s

Original string passed to system() without vulnerability:

chmod u+s "

/usr/local/Serv-U/Serv-U

"

red text

green text

red text

green text

red text

red text

/bin/sh

Malicious string passed to system() executing /bin/sh:

chmod u+s "

";

/bin/sh ;" "

red text

green text

Tl;dr: I found a privilege escalation 0day CVE-2019-12181 ) in the Serv-U FTP Server through command injection.POC code available here I searched for a program that isn't too niche and market specific that it hasn't had time to develop its security. Yet, I didn't want to commit long months of research to find a vulnerability in an extremely popular program that has already been reviewed by many security researchers. I came across Serv-U FTP Server from shodan and decided to pursue this target after seeing the respectable number of over 168,000 instances running worldwide exposed to the Internet.As its name suggests, Serv-U FTP Server is an FTP server; but it also has a web interface for easy file management and a web admin interface.Serv-U is available both for Linux and Windows. On Linux, the ftp server is a SUID executable and runs as root. Therefore, even an attack that can only be executed locally is still a threat as it will give the attacker root privileges. This is called a privilege escalation attack.Some technical background on two specific C functions: main() and execve() is needed to understand and exploit this vulnerability. If you are already familiar with these functions you can skip ahead. According to the gnu libc manual , there are 3 ways to declare thefunction.When there is anparameter, it holds the amount of parameters in theparameter passed.When there is anparameter, it points to an array of C strings. Each string is a command line parameter passed to the program. The last element of the string array is NULL. For example,will result inholdingWhen there is anparameter, it points to an array of C strings as well. Each string is an environment variable. The environment variables are described with a string in the template "key=value" where "key" is the name of the environment variable with the value "value". The last element of the array is NULL.Experiment with this code to see parameters passed to main.The functions in the exec* family allow you to execute a file; optionally, with custom parameters that are passed to the executed program'sfunction. In fact, with these functions you can even set the first argument ofthat is passed to the new process' main (which you can't do from the command line). These functions also have the ability to invoke SUID binaries. Those last two facts will come in handy later 😉.When I start searching for vulnerabilities in a new program, the first thing I do is look for low hanging fruits. I look for calls to specific functions that developers tend to misuse - functions that require programmers to manually check the parameters they pass because these functions won't do safety checks themselves.Some dangerous functions I look for:Since my research target (Serv-U) is closed source, in order to look for calls to the above mentioned dangerous functions, I opened up my favorite reverse engineering platform, IDA Pro , and got to work.While scanning for the use of vulnerable functions, the fact that the executable callsfour different times(!) caught my eye and led me to focus on that. For comparison, secure programs will usually only use this function once, if at all.Going over thecalls in the code, I reached a call tothat looked like through control of theparameter we could inject our own string into the parameter going to system! See picture below:After reversing, debugging, and taking educated guesses, I came to the conclusion that the command passed to system is "" whereis set to argv[0]! This is dangerous since if we manage to reach this vulnerable flow,! Furthermore, since the executable is SUID, even when we run it from exec* functions it will, giving any attacking user root privileges.After setting a breakpoint on the vulnerable function and normally starting the FTP server, I was disappointed to discover that the breakpoint wasn't hit: Meaning this function isn't called by default. I needed to reverse some more to learn how we can trigger the discovered vulnerable program flow.I looked at who was calling our vulnerable function:Looking at the decompiled code we can assume that when some condition on line 53 (highlighted) is met, our wanted function on line 74 (highlighted) will be called. The condition on line 53 looks like a string comparison, and one of the strings being compared looks like a command line flag. Starting the FTP Server with the "-prepareinstallation" command line flag resulted in the program calling the vulnerable function! 😊Since this is a shell injection vulnerability, exploitation is trivial: all we need to do is escape the current command and append a command of our own to be executed.As seen on line 12 in the decompiled code, the variablethat we control is inserted into the string. Since our string is inserted instead of the, which is in the middle of a different string, we need to isolate our command with separators at the beginning and end.system('')Key:is junk around our string we can't control that is passed into the system() functionis the string we controlWe are going to escape the string that we are inserted into (the) by only changing our controllable variable (the). We begin by closing the opened quotes in thewith a '"' and then inserting a command separator, which is ';' on Linux. To end our command and close the quote at the very end in the, we will end our inserted string with a ';' and '"'.Such that to execute, we will set our controlled string to be: "; /bin/sh/ ;". The string passed to system() will be as shown below.system('')Key:is junk around our string we can't control that is passed into the system() functionis the string we controlNotice in the display above that all quotes that have been opened are closed, and our command is elegantly separated and thus independently executed because of the ';'. For working exploit code click here. Link to Serv-U release notes with fix here , and link to vulnerability summary and resolution here. Leave a comment or DM me with any questions you have 😊And thank you to the good folks at psirt@solarwinds.com for the quick and professional handling of my vulnerability disclosure.Follow my twitter @va_start for my latest vulnerability research