[SECURITY] Time-based blind SQL Injection in Relyt do_create_kb allows arbitrary data extraction (CWE-89, CVSS 8.0)

#5513 · open · 0 comments

View on GitHub ↗

Jiecub3

# Langchain-Chatchat Relyt do_create_kb Time-Based Blind SQL Injection ## Summary `RelytKBService.do_create_kb()` uses f-string to concatenate `kb_name` into `index_name`, executed via `text(f"SELECT 1 FROM pg_indexes WHERE indexname='{index_name}'")`, constituting SQL injection. Since the `create_kb` handler has no try/except error echo (FastAPI returns 500 with no body) and always returns 200, only time-based blind injection is possible: `UNION SELECT (SELECT CASE WHEN ascii(substring(...))>X THEN pg_sleep(N) ELSE 0 END)` binary search reads characters one by one. Verified reading out complete secret `S005_KEY_7f3a` (13 characters) + `current_user=postgres` (DB superuser). ## Affected Version & Commit - Repository: https://github.com/chatchat-space/Langchain-Chatchat - Branch: master - Commit: 49165d6af4438aa7e8a1f71ce276db55f4405151 ## Vulnerability Description `RelytKBService.do_create_kb()` uses f-string to directly concatenate the `kb_name` parameter into the `index_name` variable, executed as raw SQL via `text(f"SELECT 1 FROM pg_indexes WHERE indexname='{index_name}'")`. Since the `create_kb` handler has no try/except to echo exceptions (FastAPI returns 500 with no body) and always returns 200, data can only be extracted through time-based blind injection. An attacker uses `UNION SELECT (SELECT CASE WHEN ascii(substring(...))>X THEN pg_sleep(N) ELSE 0 END)` to perform binary search character-by-character. Verified reading out complete secret `S005_KEY_7f3a` (13 characters, ~91 requests), and confirmed `current_user=postgres` (DB superuser, can read any table). ## Affected Endpoints - `POST /knowledge_base/create_knowledge_base` (port 7861) ## Exploitation Conditions - Exploitable with default configuration, no authentication required - Requires `vs_type=relyt` (Relyt knowledge base backend) - Time-based blind injection is slower (~7 requests per character via binary search) ## Proof of Concept ```bash # Step 1: POST create_knowledge_base, kb_name=UNION payload, pg_sleep condition triggers curl -s -X POST http://127.0.0.1:7861/knowledge_base/create_knowledge_base \ -H "Content-Type: application/json" \ -d '{"knowledge_base_name":"x\x27 UNION SELECT (SELECT CASE WHEN ascii(substring((SELECT secret FROM victim_table_s005),1,1))>64 THEN (SELECT 1 FROM pg_sleep(1)) ELSE 0 END)-- ","vector_store_type":"relyt","kb_info":"b","embed_model":"bge-large-zh-v1.5"}' # Expected: response delay ≥1s (pg_sleep triggers) ← ascii>64 holds, binary search locates first character # Step 2: Adjust substring offset + threshold, repeat binary search to read secret character by character # (script auto-loops, 13 characters ~91 requests) # Expected: read out complete secret S005_KEY_7f3a ``` Tested: binary search reads out complete secret `S005_KEY_7f3a` (13 characters, ~91 requests), and confirmed `current_user=postgres` (DB superuser, can read any table). ## Impact An unauthenticated attacker can read any data in the database character-by-character via time-based blind injection, including secrets, API keys, and other sensitive credentials, as well as verify the current database user identity (postgres superuser). ## Severity CVSS v3.1: 8.0 (High) Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N CWE: CWE-89 (SQL Injection) ## Credit - Jiecub3 (GitHub ID: 87791178) - Aur0ra-m (GitHub ID: 103031059) - lz2y (GitHub ID: 55266300)

Comments