GCVE-1988-2026-0469

Vulnerability from gna-1988 – Published: 2026-11-02 07:30 – Updated: 2026-11-02 07:30
VLAI
Title
[0day-rubbish] Maian Cart 3.8 addBanners unrestricted banner upload to PHP webshell and administrator command execution (7.2 primary, PR:H)
Summary
0day Rubbish Research Team is publicly disclosing a vulnerability in Maian Cart 3.8, the self-hosted PHP shopping-cart system from Maian Media (Maian Script World), verified end to end against a real installation of that version. Type: unrestricted upload of a file with a dangerous type (CWE-434), realized as OS command execution (CWE-78) through an attacker-supplied PHP webshell, with CWE-269 bearing on the execution privilege context. The Store Banners page of the administration backend (route /admin/index.php?p=settings&s=9) dispatches multipart uploads to addBanners() in admin/control/classes/class.system.php:376-413, which reads the raw client filename at line 386, derives the stored extension from it at line 392 with strrchr on the lower-cased name, composes the stored name at line 393 as the banner prefix plus a counter from the banners table plus that extension, and writes the file with move_uploaded_file at line 401, a second call site being recorded at line 410. There is no extension allow-list, no MIME or finfo validation and no getimagesize() content check anywhere on the path; mc_safeImport at line 377 is an SQL-escaping pass over $_POST and never touches $_FILES, and is_uploaded_file only confirms the file arrived over HTTP. With the shipped defaults RENAME_BANNERS=1 and BANNER_PREFIX='img_', an upload named shell.php is stored as img_1.php: the rename regenerates the base name and preserves the attacker's extension. The destination, content/_theme_default/images/banners/, is inside the document root and carries no deny rule, in explicit contrast to admin/import/.htaccess, admin/attachments/.htaccess and content/_theme_default/cache/.htaccess, all of which ship Deny from all, so a plain GET for the stored img_<id>.php is handed to the PHP interpreter and a one-line shell_exec webshell yields command execution in the web server process context. move_uploaded_file runs before the INSERT INTO banners statement, so the shell survives even a failing INSERT. The product's own image allow-list ($imgAllow at class.products.php:9, applied at :1213 and :1907 in addAdditionalProductPictures) is the one-line control this handler omits. Scoring. Four readings are published with their vectors, labelled, rather than one number: - PRIMARY, and the only classification this advisory claims: 7.2 High, CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H. The sink sits behind the webmaster gate at admin/control/system-load.php:79 (mc_isWebmasterLoggedIn, whose underlying test at functions.php:324-336 requires a fully populated webmaster session array). - CONDITIONAL, 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, for a deployment that retains an unchanged, known or guessable administrator credential. This reading is this advisory's own construction, not a figure produced by the research record, which scores the finding only under the 7.2 vector and records that the unauthenticated objective was not reached. It describes deployment state rather than product state: the product ships no fixed factory credential, the install wizard writes the operator-chosen USERNAME and PASSWORD into access.php, and no installation whose credentials were guessable was verified. Its sole basis is the companion observation that the installer-provisioned credential is never forced to rotate (a CWE-798-class note about persistent provisioned credentials without a rotation gate). It does not change the primary classification. - CONSIDERED AND NOT ADOPTED: 8.8 High, CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, which differs from the primary vector only in Privileges Required and was not adopted because no role below webmaster reaches the settings module in the recorded gate model; and 9.1 High, CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H, which would require Scope Changed and does not fit, the vulnerable component and the impacted component being the same security authority. Authentication: administrator session. The login handler (admin/control/modules/system/portal.php:26-47) requires process=1, a cs_rf CSRF token matching the hidden field served on the login page, a user value equal to the USERNAME constant in access.php and a password verified through mc_PassHash; the trigger is isset($_POST['process_banners']) at settings.php:84-87. The unauthenticated objective was pursued and exhaustively ruled out: ajax.php exposes no file-write or command primitive an unauthenticated caller can steer; forging the persistent administrator cookie is infeasible because mc_encrypt(SECRET_KEY . DB_NAME) requires the per-installation database name, which is not remotely discoverable; the only gadget found was PHPMailer's __destruct, not exploitable into a dangerous sink in this codebase, so no object-population chain exists; the login path is not injectable; and every move_uploaded_file call site identified sits under the gated /admin/ backend. No unauthenticated route to the sink is claimed. Impact: arbitrary OS command execution as the web server process, uid=0(root) in the laboratory capture because the test web tier ran as root, typically www-data or apache in production. Full read and write access to store source code, application configuration including the database credentials the application itself reads, uploaded order attachments and the surrounding file system; database access with the application's own privileges, meaning the store's orders, customer records and settings; persistence, since the stored img_<id>.php outlives the administrator session and nothing in the product scans for or removes it; and a pivot into whatever segments the store host can reach. For an insider or credential-holder the upload is audit-invisible: it appears in the interface as an ordinary banner addition. Verification boundary, stated plainly. Verified end to end against a real Maian Cart 3.8 installation: the product's own install wizard run to completion on a Linux laboratory host, creating 62 database tables and populating the settings rows, with MySQL 8.0.46 on a dedicated laboratory schema and account, and the web tier being the PHP built-in server bound to loopback for laboratory safety. That process ran as root for the session in question, which is why uid=0(root) was observed and why the stored 39-byte shell, exactly the length of the one-line payload, was owned by root. Three independent runs reached command execution, the third being a from-scratch re-analysis pass by an independent reviewer who rebuilt the audit and shipped a second, distinctly named shell through the same handler, stored as img_3.php. An adversarial refutation review searched for a global upload sanitizer, a deny rule for the banners directory, FilesMatch restrictions on .php, getimagesize usage on this path, web-server configuration hardening and install-time hardening, found none, and left the finding standing. No vendor-hosted or third-party installation was touched, and no post-exploitation was performed beyond identity and file-system probes. What was not exercised: the production Apache and mod_php stack was not run, so execution under Apache rests on static evidence plus the research record's own assertion that Apache with mod_php is the default production deployment, an assertion not substantiated from a vendor document; a non-root process identity was not demonstrated, so the claim is command execution at whatever identity the web server holds; the updateBanners edit path, the TRADE_THEME_FOLDER branch and the dead-code uploadWebLogo variant (class.system.php:956, same pattern, no call site, excluded from the finding) were not exercised; only 3.8 was tested. One precondition is unresolved and stated rather than smoothed over: the banners directory must already exist on disk. It was absent in the first laboratory iteration, move_uploaded_file failed with a no-such-file-or-directory error, and the directory was created manually before a later iteration succeeded; move_uploaded_file does not create directories and the handler's only filesystem guard tests the destination file, not the directory. No artifact establishes which product component creates it, so no first-upload directory creation is claimed. Related product, scoped out. The research record notes that the sibling Maian Support product exhibits the same CWE-434-class pattern, a content tree without .htaccess protection combined with Apache AllowOverride All. That product is out of scope for this advisory: no exploitation attempt was made there and no identifier is claimed for it. Fix direction, in short: enforce an extension allow-list at the sink reusing the control already in class.products.php; validate uploaded content with getimagesize() or finfo; discard the client-supplied extension and name stored files server-side; make the banner storage non-executable by moving it outside the document root or shipping a deny rule plus documented nginx-equivalent guidance; route every move_uploaded_file call site through one shared validator; force first-login rotation of the installer-provisioned administrator credential; and remove or gate the dead uploadWebLogo code. Full technical analysis and a reproducible proof-of-concept: https://0day-rubbish.com/blog/maian-cart-addbanners-upload-extension-webshell-rce Project archive (ongoing disclosure series): https://github.com/Exploit-Garbage/0day-Rubbish The vendor has been notified through the support mailbox it publishes for its products. No vulnerability identifier has been assigned to this finding yet. -- 0day Rubbish Research Team disclosure () 0day-rubbish com https://0day-rubbish.com _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/
Severity
No CVSS data available.
Assigner
VULNARCHIVE GNA GNA-1988
GNA scorecard E 38/100 over 552 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
Maianscriptworld Maian Cart Affected: unknown
guessed Create a notification for this product.

{
  "containers": {
    "cna": {
      "affected": [
        {
          "product": "Maian Cart",
          "vendor": "Maianscriptworld",
          "versions": [
            {
              "status": "affected",
              "version": "unknown"
            }
          ]
        }
      ],
      "credits": [
        {
          "lang": "en",
          "type": "finder",
          "value": "disclosure via Fulldisclosure"
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "0day Rubbish Research Team is publicly disclosing a vulnerability in Maian\nCart 3.8, the self-hosted PHP shopping-cart system from Maian Media (Maian\nScript World), verified end to end against a real installation of that\nversion.\n\nType: unrestricted upload of a file with a dangerous type (CWE-434), realized\nas OS command execution (CWE-78) through an attacker-supplied PHP webshell,\nwith CWE-269 bearing on the execution privilege context. The Store Banners\npage of the administration backend (route /admin/index.php?p=settings\u0026s=9)\ndispatches multipart uploads to addBanners() in\nadmin/control/classes/class.system.php:376-413, which reads the raw client\nfilename at line 386, derives the stored extension from it at line 392 with\nstrrchr on the lower-cased name, composes the stored name at line 393 as the\nbanner prefix plus a counter from the banners table plus that extension, and\nwrites the file with move_uploaded_file at line 401, a second call site being\nrecorded at line 410. There is no extension allow-list, no MIME or finfo\nvalidation and no getimagesize() content check anywhere on the path;\nmc_safeImport at line 377 is an SQL-escaping pass over $_POST and never\ntouches $_FILES, and is_uploaded_file only confirms the file arrived over\nHTTP. With the shipped defaults RENAME_BANNERS=1 and BANNER_PREFIX=\u0027img_\u0027,\nan upload named shell.php is stored as img_1.php: the rename regenerates the\nbase name and preserves the attacker\u0027s extension. The destination,\ncontent/_theme_default/images/banners/, is inside the document root and\ncarries no deny rule, in explicit contrast to admin/import/.htaccess,\nadmin/attachments/.htaccess and content/_theme_default/cache/.htaccess, all\nof which ship Deny from all, so a plain GET for the stored img_\u003cid\u003e.php is\nhanded to the PHP interpreter and a one-line shell_exec webshell yields\ncommand execution in the web server process context. move_uploaded_file runs\nbefore the INSERT INTO banners statement, so the shell survives even a failing\nINSERT. The product\u0027s own image allow-list ($imgAllow at class.products.php:9,\napplied at :1213 and :1907 in addAdditionalProductPictures) is the one-line\ncontrol this handler omits.\n\nScoring. Four readings are published with their vectors, labelled, rather than\none number:\n- PRIMARY, and the only classification this advisory claims: 7.2 High,\n  CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H. The sink sits behind the\n  webmaster gate at admin/control/system-load.php:79\n  (mc_isWebmasterLoggedIn, whose underlying test at functions.php:324-336\n  requires a fully populated webmaster session array).\n- CONDITIONAL, 9.8 Critical, CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H,\n  for a deployment that retains an unchanged, known or guessable\n  administrator credential. This reading is this advisory\u0027s own construction,\n  not a figure produced by the research record, which scores the finding only\n  under the 7.2 vector and records that the unauthenticated objective was not\n  reached. It describes deployment state rather than product state: the\n  product ships no fixed factory credential, the install wizard writes the\n  operator-chosen USERNAME and PASSWORD into access.php, and no installation\n  whose credentials were guessable was verified. Its sole basis is the\n  companion observation that the installer-provisioned credential is never\n  forced to rotate (a CWE-798-class note about persistent provisioned\n  credentials without a rotation gate). It does not change the primary\n  classification.\n- CONSIDERED AND NOT ADOPTED: 8.8 High,\n  CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, which differs from the\n  primary vector only in Privileges Required and was not adopted because no\n  role below webmaster reaches the settings module in the recorded gate\n  model; and 9.1 High,\n  CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H, which would require Scope\n  Changed and does not fit, the vulnerable component and the impacted\n  component being the same security authority.\n\nAuthentication: administrator session. The login handler\n(admin/control/modules/system/portal.php:26-47) requires process=1, a cs_rf\nCSRF token matching the hidden field served on the login page, a user value\nequal to the USERNAME constant in access.php and a password verified through\nmc_PassHash; the trigger is isset($_POST[\u0027process_banners\u0027]) at\nsettings.php:84-87. The unauthenticated objective was pursued and exhaustively\nruled out: ajax.php exposes no file-write or command primitive an\nunauthenticated caller can steer; forging the persistent administrator cookie\nis infeasible because mc_encrypt(SECRET_KEY . DB_NAME) requires the\nper-installation database name, which is not remotely discoverable; the only\ngadget found was PHPMailer\u0027s __destruct, not exploitable into a dangerous sink\nin this codebase, so no object-population chain exists; the login path is not\ninjectable; and every move_uploaded_file call site identified sits under the\ngated /admin/ backend. No unauthenticated route to the sink is claimed.\n\nImpact: arbitrary OS command execution as the web server process, uid=0(root)\nin the laboratory capture because the test web tier ran as root, typically\nwww-data or apache in production. Full read and write access to store source\ncode, application configuration including the database credentials the\napplication itself reads, uploaded order attachments and the surrounding file\nsystem; database access with the application\u0027s own privileges, meaning the\nstore\u0027s orders, customer records and settings; persistence, since the stored\nimg_\u003cid\u003e.php outlives the administrator session and nothing in the product\nscans for or removes it; and a pivot into whatever segments the store host can\nreach. For an insider or credential-holder the upload is audit-invisible: it\nappears in the interface as an ordinary banner addition.\n\nVerification boundary, stated plainly. Verified end to end against a real Maian\nCart 3.8 installation: the product\u0027s own install wizard run to completion on a\nLinux laboratory host, creating 62 database tables and populating the settings\nrows, with MySQL 8.0.46 on a dedicated laboratory schema and account, and the\nweb tier being the PHP built-in server bound to loopback for laboratory\nsafety. That process ran as root for the session in question, which is why\nuid=0(root) was observed and why the stored 39-byte shell, exactly the length\nof the one-line payload, was owned by root. Three independent runs reached\ncommand execution, the third being a from-scratch re-analysis pass by an\nindependent reviewer who rebuilt the audit and shipped a second, distinctly\nnamed shell through the same handler, stored as img_3.php. An adversarial\nrefutation review searched for a global upload sanitizer, a deny rule for the\nbanners directory, FilesMatch restrictions on .php, getimagesize usage on this\npath, web-server configuration hardening and install-time hardening, found\nnone, and left the finding standing. No vendor-hosted or third-party\ninstallation was touched, and no post-exploitation was performed beyond\nidentity and file-system probes.\n\nWhat was not exercised: the production Apache and mod_php stack was not run,\nso execution under Apache rests on static evidence plus the research record\u0027s\nown assertion that Apache with mod_php is the default production deployment,\nan assertion not substantiated from a vendor document; a non-root process\nidentity was not demonstrated, so the claim is command execution at whatever\nidentity the web server holds; the updateBanners edit path, the\nTRADE_THEME_FOLDER branch and the dead-code uploadWebLogo variant\n(class.system.php:956, same pattern, no call site, excluded from the finding)\nwere not exercised; only 3.8 was tested. One precondition is unresolved and\nstated rather than smoothed over: the banners directory must already exist on\ndisk. It was absent in the first laboratory iteration, move_uploaded_file\nfailed with a no-such-file-or-directory error, and the directory was created\nmanually before a later iteration succeeded; move_uploaded_file does not\ncreate directories and the handler\u0027s only filesystem guard tests the\ndestination file, not the directory. No artifact establishes which product\ncomponent creates it, so no first-upload directory creation is claimed.\n\nRelated product, scoped out. The research record notes that the sibling Maian\nSupport product exhibits the same CWE-434-class pattern, a content tree\nwithout .htaccess protection combined with Apache AllowOverride All. That\nproduct is out of scope for this advisory: no exploitation attempt was made\nthere and no identifier is claimed for it.\n\nFix direction, in short: enforce an extension allow-list at the sink reusing\nthe control already in class.products.php; validate uploaded content with\ngetimagesize() or finfo; discard the client-supplied extension and name stored\nfiles server-side; make the banner storage non-executable by moving it outside\nthe document root or shipping a deny rule plus documented nginx-equivalent\nguidance; route every move_uploaded_file call site through one shared\nvalidator; force first-login rotation of the installer-provisioned\nadministrator credential; and remove or gate the dead uploadWebLogo code.\n\nFull technical analysis and a reproducible proof-of-concept:\n  https://0day-rubbish.com/blog/maian-cart-addbanners-upload-extension-webshell-rce\n\nProject archive (ongoing disclosure series):\n  https://github.com/Exploit-Garbage/0day-Rubbish\n\nThe vendor has been notified through the support mailbox it publishes for its\nproducts. No vulnerability identifier has been assigned to this finding yet.\n\n--\n0day Rubbish Research Team\ndisclosure () 0day-rubbish com\nhttps://0day-rubbish.com\n_______________________________________________\nSent through the Full Disclosure mailing list\nhttps://nmap.org/mailman/listinfo/fulldisclosure\nWeb Archives \u0026 RSS: https://seclists.org/fulldisclosure/"
        }
      ],
      "problemTypes": [
        {
          "descriptions": [
            {
              "cweId": "CWE-269",
              "description": "CWE-269",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-434",
              "description": "CWE-434",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-78",
              "description": "CWE-78",
              "lang": "en",
              "type": "CWE"
            },
            {
              "cweId": "CWE-798",
              "description": "CWE-798",
              "lang": "en",
              "type": "CWE"
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-11-02T07:30:01Z",
        "orgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
        "shortName": "VULNARCHIVE"
      },
      "references": [
        {
          "tags": [
            "technical-description",
            "exploit"
          ],
          "url": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/6"
        },
        {
          "tags": [
            "technical-description"
          ],
          "url": "https://seclists.org/fulldisclosure/2026/Oct/6"
        },
        {
          "url": "https://0day-rubbish.com"
        },
        {
          "url": "https://0day-rubbish.com/blog/maian-cart-addbanners-upload-extension-webshell-rce"
        },
        {
          "url": "https://github.com/Exploit-Garbage/0day-Rubbish"
        },
        {
          "url": "https://nmap.org/mailman/listinfo/fulldisclosure"
        },
        {
          "url": "https://seclists.org/fulldisclosure/"
        }
      ],
      "source": {
        "defect": [
          "https://seclists.org/fulldisclosure/2026/Oct/6"
        ],
        "discovery": "EXTERNAL"
      },
      "title": "[0day-rubbish] Maian Cart 3.8 addBanners unrestricted banner upload to PHP webshell and administrator command execution (7.2 primary, PR:H)",
      "x_gcve": [
        {
          "recordType": "advisory",
          "relationships": [],
          "vulnId": "GCVE-1988-2026-0469",
          "x_vulnarchive": {
            "archiveUrl": "https://vuln.freearchive.org/archive/full-disclosure/2026/Oct/6",
            "automated": true,
            "contentSha256": "996730e626ea94faa931788cc5994301981a5d0a11716f9aa25f9688cf48c3e0",
            "evidenceScore": 11,
            "messageId": "",
            "originalUrl": "https://seclists.org/fulldisclosure/2026/Oct/6",
            "policy": "vulnarchive-1",
            "sourceFormat": "text/html",
            "sourcePublishedAt": "2026-10-05T17:53:29Z"
          }
        }
      ]
    }
  },
  "cveMetadata": {
    "assignerOrgId": "4e2abfbf-4a2a-4b76-a4e0-d77c18ba156c",
    "assignerShortName": "VULNARCHIVE",
    "datePublished": "2026-11-02T07:30:01Z",
    "dateUpdated": "2026-11-02T07:30:01Z",
    "state": "PUBLISHED",
    "vulnId": "GCVE-1988-2026-0469"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.