Post

IronCTF2024 web/MovieReviewApp

My solution for IronCTF2024 web/MovieReviewApp challenge

Challenge overview

MovieReviewApp

The MovieReviewApp challenge is a web application that allow users to check reviews for specific movies.

Application structure

Static website
The challenge presents a seemingly simple web page with movie reviews, lacking any interactive elements like input fields or forms.

Analysis

Available .git directory
The movie review website has a .git directory accessible, which provides a way to download and analyze the application’s source code. Once the .git directory is retrieved, the repository can be reconstructed locally, providing access to the full source code and commit history.

Reviewing the commit logs with git log -p reveals sensitive information, including:

  • the route for the admin panel (/servermonitor/admin_panel)
  • hardcoced admin credentials:
    ADMIN_USERNAME = 'superadmin'
    ADMIN_PASSWORD = 'Sup3rS3cR3TAdminP@ssw0rd$!'

Identifying the vulnerabilities

The admin panel has a feature to ping an IP address, with the relevant code found in the source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def ping_ip(ip, count):
    if re.match(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$', ip):
        return subprocess.check_output(f"ping -c {count} {ip}", shell=True).decode()
    else:
        return "Invalid ip address and count!"

@app.route('/admin_panel', methods=['GET', 'POST'])
def admin_panel():
    ping_result = None
    if request.method == 'POST':
        ip = request.form.get('ip')
        count = request.form.get('count', 1)
        try:
            ping_result = ping_ip(ip, count)
        except ValueError:
            flash("Count must be a valid integer")
        except Exception as e:
            flash(f"An error occurred: {e}")

    memory_info = psutil.virtual_memory()
    memory_usage = memory_info.percent
    total_memory = memory_info.total / (1024 ** 2)
    available_memory = memory_info.available / (1024 ** 2)

    return render_template('admin.html', ping_result=ping_result,
                           memory_usage=memory_usage, total_memory=total_memory,
                           available_memory=available_memory)

The count parameter, which is intended to specify the number of ICMP requests, is not properly sanitized, leading to a command injection vulnerability. The ping_ip() function uses ip and count to form a system command, making it possible to inject arbitrary commands using the count parameter.

Crafting the exploit

Command injection
The goal is to leverage the command injection vulnerability to read sensitive files on the server. By providing a crafted payload in the count parameter, command injection is achieved:
ip=1.1.1.1&count=;cd /;cat /flag.txt;

The payload terminates the intended command and adds additional commands to navigate to the root directory and read the flag.txt file.

Result

Flag:ironCTF{4lways_b3_c4ar3ful_w1th_G1t!}

Conclusion

This challenge highlights the importance of securing sensitive files, like the .git directory, which can leak crucial information about the application. Additionally, improper input validation allows for command injection, which could be mitigated by sanitizing user input and using safer command execution methods.

Key takeaways

  • Don’t expose sensitive directories/files: Always ensure that sensitive directories like .git are not accessible publicly.
  • Proper validation: Properly validate and sanitize all user inputs to avoid injection vulnerabilities.
  • Avoid hardcoding credentials: Avoid hardcoding sensitive information such as credentials in the source code, especially in publicly accessible environments.
This post is licensed under CC BY 4.0 by the author.