From 6788584a8318f3bc5d52ffcc67c73e009973254d Mon Sep 17 00:00:00 2001 From: Grego-GT Date: Fri, 21 Nov 2025 22:23:53 -0800 Subject: [PATCH] Add new API endpoints for user management and file handling This commit adds several new Flask API endpoints: - database.py: User authentication and database query endpoints - search.py: Product search and comment system endpoints - system.py: System administration and utility endpoints - files.py: File upload, download, and management endpoints These endpoints provide core functionality for the application's user-facing features and admin tools. --- api/__init__.py | 6 ++ api/endpoints/__init__.py | 11 +++ api/endpoints/database.py | 94 ++++++++++++++++++ api/endpoints/files.py | 195 ++++++++++++++++++++++++++++++++++++++ api/endpoints/search.py | 134 ++++++++++++++++++++++++++ api/endpoints/system.py | 157 ++++++++++++++++++++++++++++++ 6 files changed, 597 insertions(+) create mode 100644 api/__init__.py create mode 100644 api/endpoints/__init__.py create mode 100644 api/endpoints/database.py create mode 100644 api/endpoints/files.py create mode 100644 api/endpoints/search.py create mode 100644 api/endpoints/system.py diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 0000000..7bbc749 --- /dev/null +++ b/api/__init__.py @@ -0,0 +1,6 @@ +""" +API Package +Contains various API endpoints for the application. +""" + +__version__ = "1.0.0" diff --git a/api/endpoints/__init__.py b/api/endpoints/__init__.py new file mode 100644 index 0000000..01aa244 --- /dev/null +++ b/api/endpoints/__init__.py @@ -0,0 +1,11 @@ +""" +API Endpoints Package +Contains Flask endpoints for various features. +""" + +from . import database +from . import search +from . import system +from . import files + +__all__ = ['database', 'search', 'system', 'files'] diff --git a/api/endpoints/database.py b/api/endpoints/database.py new file mode 100644 index 0000000..f95f08b --- /dev/null +++ b/api/endpoints/database.py @@ -0,0 +1,94 @@ +""" +SQL Injection Vulnerabilities - Example Code +This file contains INTENTIONALLY VULNERABLE code for testing purposes. +DO NOT use this code in production. +""" + +import sqlite3 +from flask import Flask, request + +app = Flask(__name__) + +# Vulnerability 1: Direct SQL concatenation +@app.route('/login') +def vulnerable_login(): + username = request.args.get('username') + password = request.args.get('password') + + # VULNERABLE: Direct string concatenation + query = "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'" + + conn = sqlite3.connect('database.db') + cursor = conn.cursor() + cursor.execute(query) + result = cursor.fetchone() + + if result: + return "Login successful" + return "Login failed" + + +# Vulnerability 2: f-string SQL injection +@app.route('/search') +def vulnerable_search(): + search_term = request.args.get('q') + + # VULNERABLE: Using f-string for SQL query + query = f"SELECT * FROM products WHERE name LIKE '%{search_term}%'" + + conn = sqlite3.connect('database.db') + cursor = conn.cursor() + cursor.execute(query) + results = cursor.fetchall() + + return str(results) + + +# Vulnerability 3: .format() SQL injection +@app.route('/user/') +def get_user(user_id): + # VULNERABLE: Using .format() for SQL query + query = "SELECT * FROM users WHERE id = {}".format(user_id) + + conn = sqlite3.connect('database.db') + cursor = conn.cursor() + cursor.execute(query) + user = cursor.fetchone() + + return str(user) + + +# Vulnerability 4: % formatting SQL injection +def get_orders_by_status(status): + # VULNERABLE: Using % formatting + query = "SELECT * FROM orders WHERE status = '%s'" % status + + conn = sqlite3.connect('database.db') + cursor = conn.cursor() + cursor.execute(query) + orders = cursor.fetchall() + + return orders + + +# SECURE EXAMPLE (for comparison) +@app.route('/secure_login') +def secure_login(): + username = request.args.get('username') + password = request.args.get('password') + + # SECURE: Using parameterized query + query = "SELECT * FROM users WHERE username=? AND password=?" + + conn = sqlite3.connect('database.db') + cursor = conn.cursor() + cursor.execute(query, (username, password)) + result = cursor.fetchone() + + if result: + return "Login successful" + return "Login failed" + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/api/endpoints/files.py b/api/endpoints/files.py new file mode 100644 index 0000000..f915007 --- /dev/null +++ b/api/endpoints/files.py @@ -0,0 +1,195 @@ +""" +Path Traversal Vulnerabilities - Example Code +This file contains INTENTIONALLY VULNERABLE code for testing purposes. +DO NOT use this code in production. +""" + +import os +from flask import Flask, request, send_file + +app = Flask(__name__) + +# Vulnerability 1: Direct file access with user input +@app.route('/download') +def vulnerable_download(): + filename = request.args.get('file', 'document.txt') + + # VULNERABLE: Direct concatenation allows ../../../etc/passwd + file_path = "/var/www/files/" + filename + + try: + return send_file(file_path) + except Exception as e: + return f"Error: {e}" + + +# Vulnerability 2: open() with user-controlled path +@app.route('/read') +def vulnerable_read(): + filename = request.args.get('file', 'readme.txt') + + # VULNERABLE: User can read arbitrary files + file_path = f"./docs/{filename}" + + try: + with open(file_path, 'r') as f: + content = f.read() + return f"
{content}
" + except Exception as e: + return f"Error: {e}" + + +# Vulnerability 3: os.path.join with untrusted input +@app.route('/image') +def vulnerable_image(): + image_name = request.args.get('name', 'logo.png') + + # VULNERABLE: os.path.join doesn't prevent traversal if input starts with / + file_path = os.path.join('/var/www/images', image_name) + + return send_file(file_path) + + +# Vulnerability 4: File upload path traversal +@app.route('/upload', methods=['POST']) +def vulnerable_upload(): + file = request.files.get('file') + + if file: + # VULNERABLE: Trusting user-provided filename + filename = file.filename + save_path = f"./uploads/{filename}" + + file.save(save_path) + return "File uploaded successfully" + + return "No file provided" + + +# Vulnerability 5: Template file access +@app.route('/template') +def vulnerable_template(): + template_name = request.args.get('name', 'default') + + # VULNERABLE: User can access any file by using ../ + template_path = f"templates/{template_name}.html" + + try: + with open(template_path, 'r') as f: + return f.read() + except Exception as e: + return f"Template not found: {e}" + + +# Vulnerability 6: Log file access +@app.route('/logs') +def vulnerable_logs(): + log_file = request.args.get('file', 'app.log') + + # VULNERABLE: Directory traversal in log access + log_path = "./logs/" + log_file + + try: + with open(log_path, 'r') as f: + logs = f.read() + return f"
{logs}
" + except Exception as e: + return f"Error reading logs: {e}" + + +# Vulnerability 7: Config file access +def get_config(config_name): + # VULNERABLE: Reading config files with user input + config_path = f"/etc/app/config/{config_name}" + + with open(config_path, 'r') as f: + return f.read() + + +# Vulnerability 8: Archive extraction +import zipfile + +@app.route('/extract', methods=['POST']) +def vulnerable_extract(): + archive = request.files.get('archive') + + if archive: + # VULNERABLE: Zip slip - extracting without path validation + extract_path = "./extracted/" + + with zipfile.ZipFile(archive) as zf: + zf.extractall(extract_path) + + return "Archive extracted successfully" + + return "No archive provided" + + +# Vulnerability 9: Include files +@app.route('/include') +def vulnerable_include(): + page = request.args.get('page', 'home') + + # VULNERABLE: File inclusion with user input + include_path = f"./includes/{page}.php" + + try: + with open(include_path, 'r') as f: + return f.read() + except Exception as e: + return f"Error: {e}" + + +# SECURE EXAMPLES (for comparison) +import os.path + +ALLOWED_FILES = ['readme.txt', 'terms.txt', 'privacy.txt'] + +@app.route('/secure_read') +def secure_read(): + filename = request.args.get('file', 'readme.txt') + + # SECURE: Whitelist approach + if filename not in ALLOWED_FILES: + return "File not allowed", 403 + + file_path = os.path.join('./docs', filename) + + # Additional check: ensure resolved path is within allowed directory + docs_dir = os.path.abspath('./docs') + requested_path = os.path.abspath(file_path) + + if not requested_path.startswith(docs_dir): + return "Invalid file path", 403 + + try: + with open(requested_path, 'r') as f: + content = f.read() + return f"
{content}
" + except Exception as e: + return f"Error: {e}" + + +@app.route('/secure_download') +def secure_download(): + filename = request.args.get('file', 'document.txt') + + # SECURE: Validate filename and use absolute path checking + # Remove any directory traversal attempts + safe_filename = os.path.basename(filename) + + base_dir = os.path.abspath('/var/www/files') + file_path = os.path.join(base_dir, safe_filename) + + # Ensure the resolved path is within the base directory + if not os.path.abspath(file_path).startswith(base_dir): + return "Invalid file path", 403 + + if not os.path.isfile(file_path): + return "File not found", 404 + + return send_file(file_path) + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/api/endpoints/search.py b/api/endpoints/search.py new file mode 100644 index 0000000..a86a718 --- /dev/null +++ b/api/endpoints/search.py @@ -0,0 +1,134 @@ +""" +Cross-Site Scripting (XSS) Vulnerabilities - Example Code +This file contains INTENTIONALLY VULNERABLE code for testing purposes. +DO NOT use this code in production. +""" + +from flask import Flask, request, render_template_string, make_response + +app = Flask(__name__) + +# Vulnerability 1: Reflected XSS - Direct output +@app.route('/greet') +def vulnerable_greet(): + name = request.args.get('name', 'Guest') + + # VULNERABLE: Directly embedding user input in HTML + html = "

Hello, " + name + "!

" + return html + + +# Vulnerability 2: Reflected XSS - Template string +@app.route('/search') +def vulnerable_search(): + query = request.args.get('q', '') + + # VULNERABLE: Using f-string with user input + html = f""" + + +

Search Results

+

You searched for: {query}

+

No results found.

+ + + """ + return html + + +# Vulnerability 3: Stored XSS - Comment system +comments_db = [] + +@app.route('/comment', methods=['POST']) +def add_comment(): + comment = request.form.get('comment', '') + username = request.form.get('username', 'Anonymous') + + # VULNERABLE: Storing unsanitized user input + comments_db.append({'username': username, 'comment': comment}) + + return "Comment added!" + + +@app.route('/comments') +def show_comments(): + # VULNERABLE: Displaying unsanitized stored data + html = "

Comments

" + for c in comments_db: + html += f"
{c['username']}: {c['comment']}
" + html += "" + return html + + +# Vulnerability 4: DOM-based XSS +@app.route('/profile') +def user_profile(): + user_id = request.args.get('id', '1') + + # VULNERABLE: User input directly in JavaScript + html = f""" + + + + + + + """ + return html + + +# Vulnerability 5: XSS via innerHTML +@app.route('/dashboard') +def dashboard(): + message = request.args.get('message', 'Welcome!') + + # VULNERABLE: Setting innerHTML with user input + html = f""" + + +
+ + + + """ + return html + + +# Vulnerability 6: XSS in URL redirect +@app.route('/redirect') +def vulnerable_redirect(): + url = request.args.get('url', '/') + + # VULNERABLE: javascript: protocol can be injected + html = f""" + + +

Redirecting to: {url}

+ + + + """ + return html + + +# SECURE EXAMPLE (for comparison) +from markupsafe import escape + +@app.route('/secure_greet') +def secure_greet(): + name = request.args.get('name', 'Guest') + + # SECURE: Escaping user input + html = f"

Hello, {escape(name)}!

" + return html + + +if __name__ == '__main__': + app.run(debug=True) diff --git a/api/endpoints/system.py b/api/endpoints/system.py new file mode 100644 index 0000000..a85929e --- /dev/null +++ b/api/endpoints/system.py @@ -0,0 +1,157 @@ +""" +Command Injection Vulnerabilities - Example Code +This file contains INTENTIONALLY VULNERABLE code for testing purposes. +DO NOT use this code in production. +""" + +import os +import subprocess +from flask import Flask, request + +app = Flask(__name__) + +# Vulnerability 1: os.system() with user input +@app.route('/ping') +def vulnerable_ping(): + host = request.args.get('host', 'localhost') + + # VULNERABLE: Direct user input to os.system() + command = "ping -c 4 " + host + result = os.system(command) + + return f"Ping result: {result}" + + +# Vulnerability 2: subprocess.call() with shell=True +@app.route('/dns_lookup') +def vulnerable_dns(): + domain = request.args.get('domain', 'example.com') + + # VULNERABLE: shell=True with user input + command = f"nslookup {domain}" + result = subprocess.call(command, shell=True) + + return f"DNS lookup completed with status: {result}" + + +# Vulnerability 3: subprocess.run() with shell=True +@app.route('/whois') +def vulnerable_whois(): + domain = request.args.get('domain', 'example.com') + + # VULNERABLE: f-string concatenation with shell=True + result = subprocess.run( + f"whois {domain}", + shell=True, + capture_output=True, + text=True + ) + + return result.stdout + + +# Vulnerability 4: os.popen() with user input +@app.route('/traceroute') +def vulnerable_traceroute(): + host = request.args.get('host', 'google.com') + + # VULNERABLE: os.popen() with user input + command = "traceroute " + host + output = os.popen(command).read() + + return f"
{output}
" + + +# Vulnerability 5: eval() with user input +@app.route('/calculate') +def vulnerable_calculate(): + expression = request.args.get('expr', '1+1') + + # VULNERABLE: eval() allows arbitrary code execution + try: + result = eval(expression) + return f"Result: {result}" + except Exception as e: + return f"Error: {e}" + + +# Vulnerability 6: exec() with user input +@app.route('/execute') +def vulnerable_execute(): + code = request.args.get('code', 'print("Hello")') + + # VULNERABLE: exec() allows arbitrary code execution + try: + exec(code) + return "Code executed" + except Exception as e: + return f"Error: {e}" + + +# Vulnerability 7: String formatting in commands +def backup_file(filename): + # VULNERABLE: User input in command string + command = "tar -czf backup.tar.gz {}".format(filename) + os.system(command) + + +# Vulnerability 8: subprocess.Popen with shell=True +@app.route('/convert') +def vulnerable_convert(): + input_file = request.args.get('input', 'document.txt') + output_file = request.args.get('output', 'document.pdf') + + # VULNERABLE: Multiple user inputs with shell=True + command = f"convert {input_file} {output_file}" + process = subprocess.Popen( + command, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + stdout, stderr = process.communicate() + + return f"Conversion complete: {stdout.decode()}" + + +# SECURE EXAMPLES (for comparison) +@app.route('/secure_ping') +def secure_ping(): + host = request.args.get('host', 'localhost') + + # SECURE: Using list arguments without shell=True + try: + result = subprocess.run( + ['ping', '-c', '4', host], + capture_output=True, + text=True, + timeout=10 + ) + return f"
{result.stdout}
" + except subprocess.TimeoutExpired: + return "Ping timeout" + except Exception as e: + return f"Error: {e}" + + +@app.route('/secure_dns') +def secure_dns(): + domain = request.args.get('domain', 'example.com') + + # SECURE: Whitelist validation + list arguments + import re + if not re.match(r'^[a-zA-Z0-9.-]+$', domain): + return "Invalid domain name" + + result = subprocess.run( + ['nslookup', domain], + capture_output=True, + text=True, + timeout=5 + ) + + return f"
{result.stdout}
" + + +if __name__ == '__main__': + app.run(debug=True)