Vending Machine

Challenge Overview

Upon accessing the challenge, we’re greeted by a straightforward page featuring an image of a vending machine and a text input field.

My first instinct was to examine the page source, where I discovered a JavaScript file named script.js.

// script.js
async function handleSubmit(event) {
    event.preventDefault(); // Prevent the default form submission

    const input = document.getElementById('product-input').value;
    const output = document.getElementById('output');
    const item = document.getElementById('item');

    // Simple product check and image mapping
    const products = {
        chips: "assets/chips.png",
        soda: "assets/soda.png",
        candy: "assets/candy.png",
        juice: "assets/juice.png"
    };
 setTimeout(async () => {
            // Wait for PHP response
            const response = await sendProduct(input);
            output.innerHTML = response; // Show PHP response
            item.style.transform = "translateY(0)"; // Reset position for next drop
            setTimeout(() => item.style.display = "none", 1000); // Hide item after a second
        }, 2000); // Time it takes to drop the item
    
	
	if (products[input.toLowerCase()]) {
        output.innerHTML = `Dropping ${input}... 🥳`;
        
        // Show item and animate drop
        item.style.display = "block"; // Show the item
        item.innerHTML = `<img src="${products[input.toLowerCase()]}" alt="${input}">`; // Set image source
        
        // Move item up to simulate dropping down
        item.style.transform = "translateY(-60px)"; // Move up to simulate dropping down
        
       
    } 

    // Clear input field
    document.getElementById('product-input').value = '';
}

// Function to send product to PHP and return response
async function sendProduct(product) {
    const response = await fetch('drop-item.php', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: `product=${encodeURIComponent(product)}` // Send product name
    });

    if (response.ok) {
        const responseData = await response.text(); // Get the response text
        return responseData; // Return response to be displayed
    } else {
        return "Error communicating with the server."; // Handle errors
    }
}

The function sendProduct particularly stood out, as it sends a request to drop-item.php with the user input as a parameter. After testing various inputs, I noticed it only accepted specific products (chips, soda, candy, juice) and filtered out most special characters and spaces. However,

Finding a Way In

When I attempted certain shell commands, such as ls, the application returned a message indicating it was “not allowed.”

I tried different commands that list directory contents. When I tested the dir command, it unexpectedly worked, revealing the directory contents. Among the files listed was one called entrypoint.sh

Upon inspecting entrypoint.sh, I noticed it reads the flag from an environment variable named FLAG and stores it in a file located at /home/apache/flag with permissions set to allow reading.

To retrieve the value, I used printenv to list all environment variables. Sure enough, this revealed the hidden flag at the end.

FLAG=CYCTF{_vJVo_yhwh76u-3yZ1Pp_Ex4SDGFacx0J7zhGPpIFd1cYeSj7s-h1doBOVPfH4Uq5h_bhtKmDnu98b4IqVZTbo8cdg9cSprylxscgesLcUrN3g}

Last updated

Was this helpful?