← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2025-0203 · CWE-74 · Disclosed 2025-01-04

A vulnerability was found in code-projects Student Management System 1

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a sharp knife left in a locked classroom, not a grenade in the lobby

CVE-2025-0203 is a SQL injection flaw in code-projects Student Management System 1.0, specifically the showSubject1 function in /config/DbFunction.php where the sid parameter is mishandled. The authoritative records disagree on preconditions: the CNA/VulDB vector says PR:L while NVD later enriched it to PR:N; the product page describes a simple PHP app with only an admin login, which makes the authenticated interpretation more believable in real deployments.

Vendor MEDIUM 6.3 is closer to reality than NVD's later 9.8 enrichment. The biggest reason is friction: this looks like a low-end school/demo PHP application with narrow enterprise presence, no KEV listing, very low EPSS, and only public PoC evidence; even if exploitation is straightforward on a live target, most 10,000-host estates either do not run it at all or run it in a limited web-app corner rather than as a core platform.

"Remote SQLi with a public PoC, but the likely auth gate and tiny deployment base keep this out of the front of the line."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Reach a live instance and the vulnerable route

An attacker first has to find a deployed Student Management System 1.0 instance and reach functionality that calls showSubject1 in /config/DbFunction.php. In practice this is usually done with manual browsing, Burp Suite, or a simple crawler against the admin workflow rather than mass internet exploitation tooling.
Conditions required:
  • A real deployment of code-projects Student Management System 1.0 exists
  • The web app is reachable from the attacker's position
  • If the CNA vector is correct, the attacker also needs a valid low-privilege session or admin credentials
Where this breaks in practice:
  • This is a niche PHP project, not a mainstream enterprise platform
  • Many organizations will have zero sanctioned instances
  • The stock app appears admin-centric, which makes authenticated reachability plausible
Detection/coverage: Unauthenticated network scanners often miss this entirely; authenticated DAST or manual testing is much more reliable.
STEP 02

Exploit sid with SQLi tooling

Using Burp Repeater or sqlmap, the attacker manipulates the sid parameter passed into showSubject1 until database errors, boolean differences, or time-based behavior confirm injection. NVD and VulDB both reference a public exploit/PoC, so the exploit-development burden is low.
Conditions required:
  • The vulnerable endpoint is callable
  • The sid parameter reaches a SQL query without proper parameterization
  • The application/database stack returns enough signal for exploitation
Where this breaks in practice:
  • Custom routing or session checks may block direct access
  • WAF rules and generic PHP hardening can disrupt noisy tools like sqlmap
  • Database error suppression can force slower blind techniques
Detection/coverage: Most SAST/DAST coverage is decent here if the app is actually in scope; WAF, HTTP logs, and DB slow-query logs can also expose probing.
STEP 03

Read or alter application data

Once injection is working, the likely impact is extraction or tampering of student, subject, session, or registration data in the application's schema. That is serious for the app owner, but the blast radius typically stops at the web app's database privileges rather than becoming host-level compromise by default.
Conditions required:
  • The DB account used by the app has meaningful read/write rights
  • Useful tables exist and are reachable from the vulnerable query path
Where this breaks in practice:
  • Shared-hosting style DB accounts are often scoped only to the app schema
  • No evidence here points to built-in RCE or OS command execution
  • Operational impact is usually local to one app/tenant, not domain-wide
Detection/coverage: DB audit logs, anomalous query volume, and application logs are the best post-exploitation signals; endpoint controls on the web server may show nothing if this stays in SQL.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo confirmed active exploitation found. CISA KEV does not list this CVE, and OpenCVE's CISA ADP enrichment marks exploitation as poc, not known in-the-wild campaign use.
Public exploit / PoCYes. NVD and OpenCVE both reference a public GitHub Gist PoC by th4s1s.
EPSS0.00096 from the user intel block, which is roughly 0.096% 30-day exploitation probability; third-party enrichment pages place it around the low percentile range (~P21).
KEV statusNot KEV-listed. No CISA Known Exploited Vulnerabilities catalog entry was found for CVE-2025-0203.
CVSS disagreementCNA/VulDB: 6.3 MEDIUM, PR:L. NVD enrichment: 9.8 CRITICAL, PR:N. That precondition disagreement is the whole case here.
Affected versionscode-projects Student Management System 1.0 is the only affected version explicitly listed in CNA/NVD data.
Fixed versionNo vendor fixed version published. I found no authoritative patch advisory or newer safe release mapping.
Exposure realityLikely narrow. This is a free PHP source-code project rather than a broadly deployed enterprise product. VulDB notes Google-dork discoverability, but I found no reliable Shodan/Censys/FOFA population data worth treating as hard exposure telemetry.
Disclosure timelineDisclosed January 4, 2025. OpenCVE shows advisory activity on 2025-01-03, with NVD publication on 2025-01-04.
Reporterlio346 (VulDB User) is credited in the CNA/OpenCVE record.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to MEDIUM (5.1/10)

The decisive factor is the likely authenticated reachability requirement combined with a tiny real deployment population. This is a real remote SQL injection, but it does not behave like a front-of-queue enterprise exposure unless you actually run this niche PHP app and expose it to untrusted users.

MEDIUM Overall severity reassessment
MEDIUM `PR:L` is the more realistic attacker precondition than NVD's later `PR:N` enrichment
HIGH Low threat prevalence: no KEV, no campaign evidence, very low EPSS

Why this verdict

  • Authenticated friction likely applies: the CNA vector is PR:L, and the product's own page describes a simple admin-login workflow; that sharply undercuts NVD's later unauthenticated 9.8 interpretation.
  • Exposure population is tiny: this is a free code-projects PHP application, not Exchange, Citrix, or SharePoint. In a 10,000-host estate, the most common outcome is *not present at all*.
  • Threat telemetry is cold: no KEV listing, no observed campaign reporting, and EPSS is extremely low. Public PoC exists, but that is a weak amplifier by itself.

Why not higher?

If this were clearly unauthenticated and broadly internet-exposed, the score would move up fast because SQLi is easy to weaponize and the PoC is public. I am not giving it that bump because the most credible precondition data says PR:L, and the product itself looks narrow, low-maturity, and rarely deployed in enterprise fleets.

Why not lower?

It is still a remote SQL injection against a live web app with a public exploit reference, so dismissing it as pure noise would be sloppy. If your org actually runs this application, compromise of app data is plausible and the vulnerability merits real remediation rather than documentation-only closure.

05 · Compensating Control

What to do — in priority order.

  1. Remove internet exposure or IP-restrict the app — If this app exists, the best stopgap is to stop treating it like a public service. Put it behind VPN, campus IP allowlists, or a reverse proxy ACL; for a MEDIUM verdict there is no formal mitigation SLA, so do this at the next practical change window while you decide whether to retire the app.
  2. Add an authenticated DAST test for sid — Most generic scanning will miss auth-gated routes. Build an authenticated check that exercises the showSubject1 path and the sid parameter so you can prove presence or absence across all copies of the app; for MEDIUM, there is no mitigation SLA — go straight to the 365-day remediation window and use this to scope exposure now.
  3. Monitor web and DB logs for SQLi probing — Watch for sid values containing quotes, boolean payloads, time-delay functions, or UNION patterns, and correlate with application sessions. This is useful immediately because public PoC means opportunistic testing is possible even if large-scale exploitation interest is low.
  4. Retire unsupported copies — No authoritative patched version was found, which makes this more of a software hygiene problem than a patch-cadence problem. If the app is still present, replace or decommission it inside the remediation window instead of betting on a future vendor fix.
What doesn't work
  • MFA alone does not fix SQL injection; it only makes the likely PR:L prerequisite harder to obtain.
  • Unauthenticated perimeter vulnerability scans are not enough if the vulnerable route sits behind login.
  • Endpoint AV/EDR on the web server may see nothing if the attack stays purely in SQL and only manipulates application data.
06 · Verification

Crowdsourced verification payload.

Run this on the target web host or against a checked-out copy of the application source. Invoke it with a single argument pointing at the app root, for example python3 verify_cve_2025_0203.py /var/www/html/student-management-system or py verify_cve_2025_0203.py C:\xampp\htdocs\student-management-system; it only needs read access to the files.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# verify_cve_2025_0203.py
# Heuristic verifier for code-projects Student Management System 1.0 SQLi in /config/DbFunction.php showSubject1 sid
# Exit codes:
#   0 = PATCHED
#   1 = VULNERABLE
#   2 = UNKNOWN

import os
import re
import sys
from pathlib import Path

VULN_FILE = os.path.join('config', 'DbFunction.php')

RAW_SID_PATTERNS = [
    re.compile(r"\$_(GET|POST|REQUEST)\s*\[\s*['\"]sid['\"]\s*\]", re.I),
    re.compile(r"\$sid\b", re.I),
]

SQL_CONCAT_PATTERNS = [
    re.compile(r"select.+where.+sid.+\.(?:\s*)\$sid", re.I | re.S),
    re.compile(r"select.+where.+sid\s*=\s*['\"]?\s*\$sid", re.I | re.S),
    re.compile(r"query\s*\(.*\$sid", re.I | re.S),
    re.compile(r"mysqli_query\s*\(.*\$sid", re.I | re.S),
]

PREPARED_PATTERNS = [
    re.compile(r"->prepare\s*\(", re.I),
    re.compile(r"bind_param\s*\(", re.I),
    re.compile(r"bindValue\s*\(", re.I),
    re.compile(r"bindParam\s*\(", re.I),
    re.compile(r"execute\s*\(", re.I),
]

FUNC_PATTERN = re.compile(r"function\s+showSubject1\s*\(", re.I)


def print_result(state: str, reason: str, code: int) -> None:
    print(f"{state}: {reason}")
    sys.exit(code)


def find_candidate(root: Path):
    direct = root / VULN_FILE
    if direct.is_file():
        return direct

    for path in root.rglob('DbFunction.php'):
        try:
            rel = path.relative_to(root).as_posix().lower()
        except Exception:
            rel = str(path).replace('\\', '/').lower()
        if rel.endswith('config/dbfunction.php'):
            return path
    return None


def main():
    if len(sys.argv) != 2:
        print("Usage: verify_cve_2025_0203.py <application_root>")
        sys.exit(2)

    root = Path(sys.argv[1]).resolve()
    if not root.exists() or not root.is_dir():
        print_result("UNKNOWN", f"Path not found or not a directory: {root}", 2)

    candidate = find_candidate(root)
    if not candidate:
        print_result("UNKNOWN", "Could not find config/DbFunction.php under the supplied path", 2)

    try:
        data = candidate.read_text(encoding='utf-8', errors='ignore')
    except Exception as e:
        print_result("UNKNOWN", f"Could not read {candidate}: {e}", 2)

    has_func = bool(FUNC_PATTERN.search(data))
    has_sid = any(p.search(data) for p in RAW_SID_PATTERNS)
    has_sql_concat = any(p.search(data) for p in SQL_CONCAT_PATTERNS)
    has_prepare = any(p.search(data) for p in PREPARED_PATTERNS)

    if has_func and has_sid and has_sql_concat and not has_prepare:
        print_result("VULNERABLE", f"Found likely unsafe showSubject1/sid SQL construction in {candidate}", 1)

    if has_func and has_prepare and not has_sql_concat:
        print_result("PATCHED", f"showSubject1 appears to use prepared statements or no obvious raw sid concatenation in {candidate}", 0)

    if has_func:
        print_result("UNKNOWN", f"showSubject1 exists in {candidate}, but the code pattern was inconclusive", 2)

    print_result("UNKNOWN", f"{candidate} exists, but showSubject1 was not found; version/layout may differ", 2)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, first confirm whether this app exists anywhere in your estate; for most enterprises this will be a fast not-applicable closeout. If you do run it, there is no mitigation SLA — go straight to the 365-day remediation window under the noisgate mitigation SLA and noisgate remediation SLA; because I found no authoritative patched version, use that window to retire, replace, or isolate any internet-reachable instance, and treat authenticated scanning plus log monitoring as the interim control.

Sources

  1. NVD CVE-2025-0203
  2. OpenCVE record for CVE-2025-0203
  3. VulDB entry VDB-290140
  4. OSV entry for CVE-2025-0203
  5. Product page: Student Management System Using PHP With Source Code
  6. CISA Known Exploited Vulnerabilities Catalog
  7. FIRST EPSS API documentation
  8. Third-party enrichment showing EPSS percentile context
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.