[0day-rubbish] Maian Cart 3.8 addBanners unrestricted banner upload to PHP webshell and administrator command execution (7.2 primary, PR:H)
Full Disclosuremailing list archivesFrom: disclosure via Fulldisclosure <fulldis 2026-10-6 17:44:49 Author: seclists.org(查看原文) 阅读量:3 收藏

fulldisclosure logo

Full Disclosure mailing list archives


From: disclosure via Fulldisclosure <fulldisclosure () seclists org>
Date: Mon, 5 Oct 2026 17:53:29 +0000

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/


Current thread:

  • [0day-rubbish] Maian Cart 3.8 addBanners unrestricted banner upload to PHP webshell and administrator command execution (7.2 primary, PR:H) disclosure via Fulldisclosure (Oct 06)

文章来源: https://seclists.org/fulldisclosure/2026/Oct/6
如有侵权请联系:admin#unsafe.sh