In this walkthrough the attacker machine will be a Kali Linux system that is a virtual machine.
The attacker system has an IP address of 172.16.20.111 and the victim system "Sokar" will be configured to have a network interface in the same segment as the attacker.
Via DHCP, the Sokar 1 machine will obtain an IP address from within the subnet of 172.16.20.0/24.
Obtaining network information
After having installed the virtual machine, the IP address of the victim machine needs to be found out:
Now that we know the address of the machine, we look for open ports:
Doing a port scan for all TCP ports and for the UDP ports as well take forever. There seems to be some type of network restriction in place.
Now that we know there is a web application listening on port 591, we can dive into it!
Exploiting the first vector - the webserver
Continuing by checking the webserver listening on port 591 with a browser:
Looks like a web page that is made up of output from different command line tools from a Linux shell (netstat, uname, df, etc.).
Also checking the HTML source of the page:
A CGI script delivers the HTML output and is included in the page via iframe.
CGI .... CGI ... cgi ... cgi ... shell tools ... shell ... shell ... SHELLSHOCK COMES TO MIND!
Trying it out:
No result ... Hmmmm ...
Trying it again with with the full path to the binaries, coming up with this:
Looking around the system further
Doing some reconnaissance and checking filesystem folders, the interesting ones in this case being /home/ and /var/mail/:
Facts so far:
Two regular users "apophis" and "bynarr" exist
Home folder for user bynarr is world-readable
Mail folder for user bynarr is readable for "others"
Establishing shell access
Trying to get a reverse shell to smoothen working with the box:
Setup a listener in another terminal session on attacker machine (172.16.20.111 being the IP of the attacker machine):
Try to spawn a reverse shell on the victim via netcat with option "-e" (a.k.a. GAPING_SECURITY_HOLE):
nope (curl instantly returns)
Try to spawn a reverse shell on the victim via bash and /dev/tcp:
nope (curl instantly returns)
Does it even do an outgoing ping?!?!?!?!
nope (curl exits after some longer timeout)
netcat might not be available for using it with a reverse shell (fast timeout when executing the command)
Something is fishy about the outgoing network connectivity. Restrictions might be in place
We will look into that. Let's check the other vectors.
Mail data of user "bynarr" is readable by "other" so let's check /var/mail/bynarr:
Veeeeeeery nice! :-)
Conclusion so far:
Outbound network connections are restricted
User "bynarr" might be able to initiate outbound TCP connections on port 51242
User "bynarr" might have the password "fruity"
Quotation hell and tty oddities
So, for a reverse shell we need to switch user and use the port 51242 for the outgoing connection.
This should be as easy as something like this, would it not? :-)
Not really! While in fact the commands above illustrate what needs to be done, they do not work that way.
Let's analyze it one at a time, using some other Linux machine:
Piping the password does not work due to tty "issues".
Spawning a pty and executing the "su" command in it is necessary to compensate for the "must be run from a terminal" problem:
Now it seems like there is some timing issue - the password is printed before the "Password:" prompt
Let' fix the timing by adding a "sleep 1" to the "echo user_password2" and put both in parentheses, creating a subshell for detaching it from the spawned pty.
Now let's add the challenge-proven method of using the /dev/tcp trick to open a reverse shell and also add the full path to the used binaries:
I will be honest here: it took quite some time to test through the variations of the commands and tricks necessary to achieve the su-and-reverse-shell in one push.
Due to nested quotes that would have been required to use the command with "curl" I decided to use metasploit to deliver the command.
Luckily there is an exploitation module available for shellshock: apache_mod_cgi_bash_env_exec
First let's use msfconsole to open a listener:
Now let's go for the actual exploitation (please note that the quotes need to be escaped in CMD):
We're in :-) Let's interact:
Digging up stuff from RAM
Looking through the user bynarr's home folder, we find some interesting stuff:
The file "lime.ko" is only accessible by root but the file "lime" can be read and executed. Let's see if that helps:
Let's look at the shell script
The heading of the file says "Memory Extractor" so we can assume that some type of memory dump can be created by the kernel module, presumably as file "/tmp/ram".
As "insmod" and "lime.ko" are not accessible by the user bynarr directly, it should be worth giving "sudo" a shot, running the script with the option "add":
Has anything happened? Let's take a look in the folder "/tmp":
There is a file called "ram", allright.
After quite some time extracting the strings from "ram" and analyzing the output, the following important data can be retrieved:
This is cool! We have found the password hashes for the users "apophis" and "root".
Let's create a pseudo-shadow file that John the Ripper can work with on the attacker machine to crack the passwords:
Knowing that sqlmap has a pretty decent wordlist for cracking passwords we go for it:
The root password could not be bruteforced but we now have the password for the user "apophis"!
Another user, another file to exploit
Let's switch the user and continue looking for hints:
Let's look through the user's folder and see if we can find something interesting:
We have a suid-root binary in the folder. Let's analyze it:
An executable with symbol information included. Good.
Any interesting strings?
Looks like some input/output related to user interaction.
To see what information the symbols provide I dumped the function names and looked for familiar or special entries, dealing with input and output functions or user interaction in general:
The presence of function calls with a "chk" prepended to them indicates that the binary has been created with a compiler option to "FORTIFY" i.e. protect the programm flow from buffer overflows (see https://isisblogs.poly.edu/2011/04/11/fortifysource-semantics/).
It seems like we will have no luck in owning the binary via gets and printf.
The function "encryptDecrypt" looks like a non-system function and will be examined later.
The next function "strcmp" is to be considered insecure as described at https://security.web.cern.ch/security/recommendations/en/codetools/c.shtml:
The strcpy built-in function does not check buffer lengths and may very well overwrite memory zone contiguous to the intended destination.
In fact, the whole family of functions is similarly vulnerable: strcpy, strcat and strcmp.
The next function "system" also introduces weaknesses to a software, as described at https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=2130132:Use of the system() function can result in exploitable vulnerabilities, in the worst case allowing execution of arbitrary system commands. Situations in which calls to system() have high risk include the following:- When passing an unsanitized or improperly sanitized command string originating from a tainted source- If a command is specified without a path name and the command processor path name resolution mechanism is accessible to an attacker- If a relative path to an executable is specified and control over the current working directory is accessible to an attacker
*- If the specified executable program can be spoofed by an attacker
Let's run the software with different options for further analysis:
Observations while running "build":
The software expects an input parameter of either "Y" or "N".
The parameter entry is case sensitive (capital "Y" for "yes" and everything else is considered "no")
The software tries to clone something into "/mnt/secret-project"
SSH is being used
The hostname "sokar-dev" is relevant for some network activity
Doing a strings did not show any SSH related commands embedded in the binary, which is fishy - the function call "encryptDecrypt" comes to mind.
Let's see if we can shed some light what it does by visualizing the programm flow (I used a trial version of the Hopper disassembler for this):
Interpreting the disassembly on a rather abstract level:
Some things happen
A relatively big amount of data is put on the stack
There is interaction with the user (print something, get some answer, compare the answer to something as in "enter yes or no")
In case the user choses "Y", do some more stuff
Call the function "encryptDecrypt" and do more things
To avoid reverse engineering the functionality of encryptDecrpyt I used a rather lazy but effective method:
Load "build" into the GNU debugger:
Set a breakpoint at main and run:
Put another breakpoint at the end of the encryptDecrypt function (offset +65) and continue to run the program:
Let's take a look at the register values, focusing on the value in rbx:
Let's see what we can find at that particular memory location:
There we go: this is what the decrypted string looks like.
The tool "build" is trying to clone a git repository via ssh to a local path of /mnt/secret-project.
As the path to "git" is absolute, there is no way to mess around with the PATH environment variable and fake a "git" command.
After doing some research on what other environment variables exist that git uses, I came up with idea of using GIT_SSH to execute arbitrary commands under my control.
Firstly however, let's create a binary to spawn a shell by transferring the source code and compiling it:
(please note the enter key had to be pressed additionaly once after the final closing curly brace due to terminal oddities)
Let's compile it:
Create a script that does the "chown and chmod" job to create a suid root binary:
Make the script executable, put it into the GIT_SSH environment variable and run build:
Did it work?
Looks good, let's go for it :-)
Really appreciating the moment, let's stroll over to the root user's directory and get the flag