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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-66753-HTTP-Header-Injection-via-Unvalidated-CR-and-LF-in-Header-Values-tiny_http- — نشرة أمنية: حقن ترويسات HTTP عبر CR وLF غير مُتحقَّق منها في قيم الترويسات (tiny_http) | Kitploit
أدوات/GitHubGitHub/theopaid/cve-2026-66753-http-header-injection-via-unvalidated-cr-and-lf-in-header-values-tiny_http-
تحليل الثغرات الأمنيةتحليل الكودأمن الويبالتعلم والتعليمموارد منسقة
GitHubtheopaid/cve-2026-66753-http-header-injection-via-unvalidated-cr-and-lf-in-header-values-tiny_http-

CVE-2026-66753-HTTP-Header-Injection-via-Unvalidated-CR-and-LF-in-Header-Values-tiny_http-

نشرة أمنية: حقن ترويسات HTTP عبر CR وLF غير مُتحقَّق منها في قيم الترويسات (tiny_http)

عرض المستودع

الأكثر شعبية

عرض الكل →

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

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

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

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

نشرة أمنية: حقن في ترويسات HTTP عبر CR و LF غير مُتحقق منهما في قيم الترويسات (tiny_http)

معرّف CVE المُسند: CVE-2026-66753

الملخص

لا يرفض tiny_http حرف إرجاع العربة (carriage return) أو تغذية السطر (line feed) داخل قيم ترويسات HTTP، في أيٍّ من الاتجاهين.

في جانب الطلب، لا يُنهي read_next_line سطر الترويسة إلا عند وجود CRLF، لذا يبقى LF منفرد داخل القيمة المُحلَّلة ويصل إلى التطبيق. وفي جانب الاستجابة، لا يتحقق Header::from_bytes إلا من أن البايتات هي ASCII، ويكتب كاتب الاستجابة القيم كما هي دون تغيير، لذا فإن القيمة التي تحتوي CRLF تقسّم الاستجابة.

التطبيقات التي تعكس قيمة ترويسة طلب في ترويسة استجابة، أو التي تعيد تسلسل ترويسات الطلب إلى اتصال آخر، ترث بالتالي أولية حقن (injection primitive) دون أي مؤشر على وجود خطأ.

الإصدارات المتأثرة

رابط المستودع: https://github.com/tiny-http/tiny-http

المتأثرجميع الإصدارات المنشورة حتى 0.12.0 (2022-10-06) ضمناً، وهو الإصدار الحالي
تم التحقق منه0.6.2, 0.6.3, 0.8.0, 0.9.0, 0.10.0, 0.11.0, 0.12.0
تم الإصلاح فيلا يوجد إصدار مُصلَح وقت كتابة هذا التقرير

يختلف هذا عن RUSTSEC-2020-0031 / CVE-2020-35884، الذي غطّى تحليل Transfer-Encoding وتم إصلاحه في 0.6.3 و 0.8.0. السلوك الموصوف هنا موجود قبل وبعد ذلك الإصلاح.

الخطورة

CWE-113 (تحييد غير سليم لتسلسلات CRLF في ترويسات HTTP)، وهي حالة خاصة من CWE-93 (حقن CRLF).

درجة CVSS 4.0 الأساسية 6.3 (متوسطة) CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:L/SI:L/SA:N

نموذج التهديد

عميل بعيد غير مُصادَق يرسل HTTP خام إلى أي خادم tiny_http. لا توجد بيانات اعتماد أو تفاعل من المستخدم.

شكلان من أشكال الاستهلاك يحوّلان هذا إلى ثغرة:

التطبيقات التي تنسخ قيمة ترويسة طلب إلى ترويسة استجابة. هذا هو نمط الانعكاس الكامن وراء صدى أصل CORS (CORS origin echo)، وترويسات Location المبنية من بيانات الطلب، ومعالجة ملفات تعريف الارتباط (cookies). يصل LF منفرد في قيمة الطلب إلى الاستجابة، وإذا كان التطبيق يبني قيمة الاستجابة بنفسه فيمكن أن تحمل CRLF كاملة.

التطبيقات التي تعيد تسلسل ترويسات الطلب إلى اتصال آخر، مثل وكيل عكسي (reverse proxy). يُكتب LF المنفرد في الطلب المُوجَّه إلى المنبع (upstream)، والخوادم الخلفية التي تتعامل مع LF المجرّد كفاصل لسطر الترويسة تقرأ طلباً واحداً على أنه طلبان. تسمح RFC 9112، القسم 2.2، للمستقبِلات بذلك، لذا فإن تلك الخوادم الخلفية ضمن المواصفة. تم قياس كل من Go net/http و Python http.server وتبيّن أن كليهما يقبله.

السبب الجذري

جانب الطلب

tiny_http-0.12.0/src/client.rs، الأسطر من 80 إلى 102. لا يُرجَع من الحلقة إلا عندما يسبق حرف CR حرف LF. أي بايت آخر، بما في ذلك LF منفرد أو CR منفرد، يُدفع إلى مخزن السطر المؤقت (line buffer) في السطر 100:

root@kitploit:~
 84          loop {
 85              let byte = self.next_header_source.by_ref().bytes().next();
...
 92              if byte == b'\n' && prev_byte_was_cr {
 93                  buf.pop(); // removing the '\r'
 94                  return AsciiString::from_ascii(buf)
 95                      .map_err(|_| IoError::new(ErrorKind::InvalidInput, "Header is not in ASCII"));
 96              }
 97  
 98              prev_byte_was_cr = byte == b'\r';
 99  
100              buf.push(byte);
101          }

LF هو 0x0A و CR هو 0x0D، وكلاهما ASCII صالح، لذا فإن AsciiString::from_ascii في السطر 94 يقبلهما.

في tiny_http-0.12.0/src/common.rs، الأسطر من 184 إلى 191، يقتصر الأمر بعد ذلك على قصّ (trim) القيمة. يزيل trim المسافات البيضاء من البداية والنهاية لكنه يترك البايتات الداخلية كما هي:

root@kitploit:~
184      fn from_str(input: &str) -> Result<Header, ()> {
185          let mut elems = input.splitn(2, ':');
186  
187          let field = elems.next().and_then(|f| f.parse().ok()).ok_or(())?;
188          let value = elems
189              .next()
190              .and_then(|v| AsciiString::from_ascii(v.trim()).ok())
191              .ok_or(())?;

لا يمكن لزوج CRLF أن يبقى، لأنه ينهي السطر، لكن يمكن لـ LF منفرد أو CR منفرد أو متواليات مثل \n\r أن تبقى جميعها.

جانب الاستجابة

في tiny_http-0.12.0/src/common.rs، الأسطر من 166 إلى 172، لا يتحقق إلا من ASCII:

root@kitploit:~
166      pub fn from_bytes<B1, B2>(header: B1, value: B2) -> Result<Header, ()>
...
171          let header = HeaderField::from_bytes(header).or(Err(()))?;
172          let value = AsciiString::from_ascii(value).or(Err(()))?;

في tiny_http-0.12.0/src/response.rs، الأسطر من 99 إلى 104، يكتب القيمة دون أي تهريب (escaping):

root@kitploit:~
 99      for header in headers.iter() {
100          writer.write_all(header.field.as_str().as_ref())?;
101          write!(&mut writer, ": ")?;
102          writer.write_all(header.value.as_str().as_ref())?;
103          write!(&mut writer, "\r\n")?;
104      }

لاحظ أن HeaderField::from_str في السطر 226 يرفض بالفعل المسافات البيضاء في اسم الحقل، لكن HeaderField::from_bytes في السطر 171 لا يفعل ذلك، لذا فإن أسماء ترويسات الاستجابة غير مُتحقق منها أيضاً.

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

الخطوة 1. شغّل خادماً يطبع قيمة ترويسة طلب مُحلَّلة ويعيد صدى قيمة تحتوي CRLF في ترويسة استجابة.

root@kitploit:~
use tiny_http::{Header, Response, Server};

fn main() {
    let server = Server::http("127.0.0.1:8004").unwrap();
    for request in server.incoming_requests() {
        for h in request.headers() {
            if h.field.equiv("X-Test") {
                println!("parsed X-Test value = {:?}", h.value.as_str());
            }
        }
        let evil = "a\r\nX-Injected: yes";
        let mut resp = Response::from_string("body");
        resp.add_header(Header::from_bytes(&b"X-Echo"[..], evil.as_bytes()).unwrap());
        let _ = request.respond(resp);
    }
}

الخطوة 2. أرسل طلباً تحتوي قيمة X-Test فيه على LF مجرّد. في الأمر أدناه، \n هو تغذية سطر واحدة و \r\n هو CRLF. هذا التمييز هو جوهر الاختبار، فلا تدع محرر نصوص يطبّعه.

root@kitploit:~
printf 'GET / HTTP/1.1\r\nHost: x\r\nX-Test: aaa\nbbb\r\nConnection: close\r\n\r\n' | nc 127.0.0.1 8004

النتيجة على stdout. لا يزال LF داخل القيمة المُحلَّلة:

root@kitploit:~
parsed X-Test value = "aaa\nbbb"

النتيجة على الشبكة. انقسمت ترويسة الاستجابة إلى اثنتين:

root@kitploit:~
HTTP/1.1 200 OK
Server: tiny-http (Rust)
Content-Type: text/plain; charset=UTF-8
X-Echo: a
X-Injected: yes
Content-Length: 4

body

التأثير

بحد ذاته، لا يعيد tiny_http إصدار ترويسات الطلب، لذا فإن سلوك جانب الطلب هو أولية كامنة (latent primitive) وليس اختراقاً مباشراً. يصبح قابلاً للاستغلال في أي مستهلك يعيد توجيه قيم الترويسات أو يعكسها، حيث ينتج عنه تهريب طلبات (request smuggling) ضد الخوادم الخلفية المتسامحة مع LF، أو حقن ترويسات في الاستجابة.

سلوك جانب الاستجابة قابل للاستغلال مباشرة في أي تطبيق يضع نصاً متأثراً بالمهاجم في قيمة ترويسة: حقن نصوص برمجية (script injection) في سياق الأصل (origin)، تسميم ذاكرة التخزين المؤقت (cache poisoning)، تثبيت الجلسة (session fixation) عبر Set-Cookie مُحقَنة، وتجاوز ترويسات الأمان.

للمقارنة، يرفض crate http الأحرف CR و LF في HeaderValue::from_str، ولهذا السبب فإن الحزم المبنية عليه لا تُظهر أيّاً من السلوكين.

المعالجة

ارفض أحرف التحكم عند كلا الحدّين.

في read_next_line (src/client.rs السطر 80)، تعامل مع CR المجرّد أو LF المجرّد في سطر الترويسة كخطأ بروتوكولي وأرجِع 400، بدلاً من ضمّه إلى القيمة. أو بدلاً من ذلك، ارفضها في Header::from_str (src/common.rs السطر 184) بعد عملية التقسيم.

في Header::from_bytes (src/common.rs السطر 166)، ارفض القيم التي تحتوي على 0x0D أو 0x0A أو 0x00، وارفض أسماء الحقول التي تحتوي على أي شيء خارج مجموعة token الخاصة بـ RFC 9110. إرجاع Err هناك مُعالَج بالفعل من قِبل المتصلين، لأن التوقيع قابل للفشل (fallible).

تنزيل الأداة