تحليل نتائج Hayabusa باستخدام jq¶
المؤلف¶
Zach Mathis (@yamatosecurity) - 2023/03/22
حول¶
تُعد القدرة على تحديد واستخراج وإنشاء مقاييس مقابل الحقول المهمة في السجلات مهارة أساسية لمحللي DFIR وصيد التهديدات.
عادةً ما تُحفظ نتائج Hayabusa في ملفات .csv من أجل استيرادها إلى برامج مثل Excel أو Timeline Explorer لتحليل الجداول الزمنية.
ومع ذلك، عندما يكون هناك مئات أو أكثر من نفس الحدث، يصبح من غير العملي أو من المستحيل التحقق منها يدويًا.
في هذه الحالات، عادةً ما يقوم المحللون بفرز وعدّ الأنواع المتشابهة من البيانات بحثًا عن القيم الشاذة.
يُعرف هذا أيضًا بتحليل الذيل الطويل، وترتيب المكدس، وتحليل التكرار، إلخ...
يمكن تحقيق ذلك باستخدام Hayabusa عن طريق إخراج النتائج إلى ملفات .json أو .jsonl ثم التحليل باستخدام jq.
على سبيل المثال، يمكن للمحلل مقارنة الخدمات المثبتة على جميع محطات العمل في المؤسسة. وفي حين أنه من الممكن أن تُثبَّت قطعة معينة من البرامج الضارة على كل محطة عمل، فمن المرجح أكثر أنها لن توجد إلا على عدد قليل من الأنظمة. في هذه الحالة، من المرجح أن تكون الخدمات المثبتة على جميع الأنظمة حميدة، بينما تميل الخدمات النادرة إلى أن تكون أكثر إثارة للريبة وينبغي التحقق منها دوريًا.
حالة استخدام أخرى هي المساعدة في تحديد مدى الريبة في شيء ما.
على سبيل المثال، يمكن للمحلل تحليل سجلات تسجيل الدخول الفاشلة 4625 لتحديد عدد المرات التي فشل فيها عنوان IP معين في تسجيل الدخول.
إذا كان هناك عدد قليل فقط من عمليات تسجيل الدخول الفاشلة، فمن المرجح أن المسؤول قد أخطأ في كتابة كلمة المرور فحسب.
ومع ذلك، إذا كان هناك مئات أو أكثر من عمليات تسجيل الدخول الفاشلة في فترة زمنية قصيرة من عنوان IP معين، فمن المرجح أن عنوان IP هذا خبيث.
سيساعدك تعلم كيفية استخدام jq على إتقان ليس فقط تحليل سجلات أحداث Windows، بل جميع السجلات المنسقة بصيغة JSON.
الآن وقد أصبحت JSON صيغة سجلات شائعة جدًا وتستخدمها معظم مزودات الخدمات السحابية لسجلاتها، أصبحت القدرة على تحليلها باستخدام jq مهارة أساسية للمحلل الأمني الحديث.
في هذا الدليل، سأشرح أولًا كيفية استخدام jq لأولئك الذين لم يستخدموه من قبل، ثم أشرح استخداماته الأكثر تعقيدًا مع أمثلة من العالم الواقعي.
أوصي باستخدام linux أو macOS أو linux على Windows لتتمكن من دمج jq مع أوامر مفيدة أخرى مثل sort وuniq وgrep وsed إلخ...
تثبيت jq¶
يرجى الرجوع إلى https://stedolan.github.io/jq/ وتثبيت أمر jq.
حول صيغة JSON¶
سجلات JSON هي قائمة من الكائنات محتواة بين أقواس معقوفة { }.
داخل هذه الكائنات توجد أزواج مفتاح-قيمة مفصولة بنقطتين.
يجب أن تكون المفاتيح سلاسل نصية، لكن القيم قد تكون واحدة مما يلي:
* سلسلة نصية (مثال: "string")
* رقم (مثال: 10)
* كائن آخر (مثال: { xxxx })
* مصفوفة (مثال: ["string", 10])
* قيمة منطقية (مثال: true، false)
* null
يمكنك تداخل أي عدد تريده من الكائنات داخل الكائنات.
في هذا المثال، Details هو كائن متداخل داخل كائن جذري:
{
"Timestamp": "2016-08-19 08:06:57.658 +09:00",
"Computer": "IE10Win7",
"Channel": "Sec",
"EventID": 4688,
"Level": "info",
"RecordID": 6845,
"RuleTitle": "Proc Exec",
"Details": {
"CmdLine": "C:\\Windows\\system32\\ipconfig /release",
"Path": "C:\\Windows\\System32\\ipconfig.exe",
"PID": "0xcf4",
"User": "IE10WIN7$",
"LID": "0x3e7"
}
}
حول صيغتي JSON وJSONL مع Hayabusa¶
في الإصدارات السابقة، كان Hayabusa يستخدم صيغة JSON التقليدية المتمثلة في وضع جميع كائنات السجل { xxx } في مصفوفة عملاقة واحدة.
مثال:
[
{
"Timestamp": "2016-08-19 08:06:57.658 +09:00",
"Computer": "IE10Win7",
"Channel": "Sec",
"EventID": 4688,
"Level": "info",
"RecordID": 6845,
"RuleTitle": "Proc Exec",
"Details": {
"CmdLine": "C:\\Windows\\system32\\ipconfig /release",
"Path": "C:\\Windows\\System32\\ipconfig.exe",
"PID": "0xcf4",
"User": "IE10WIN7$",
"LID": "0x3e7"
}
},
{
"Timestamp": "2016-08-19 11:07:47.489 +09:00",
"Computer": "IE10Win7",
"Channel": "Sec",
"EventID": 4688,
"Level": "info",
"RecordID": 6847,
"RuleTitle": "Proc Exec",
"Details": {
"CmdLine": "taskhost.exe $(Arg0)",
"Path": "C:\\Windows\\System32\\taskhost.exe",
"PID": "0x228",
"User": "IE10WIN7$",
"LID": "0x3e7"
}
}
]
هناك مشكلتان في هذا.
المشكلة الأولى هي أن استعلامات jq ستصبح أكثر تعقيدًا حيث يجب أن يبدأ كل شيء بـ .[] إضافية لإخباره بالنظر داخل تلك المصفوفة.
المشكلة الأكبر بكثير هي أنه لكي يحلل أي شيء مثل هذه السجلات، من الضروري أولًا تحميل جميع البيانات في المصفوفة.
يصبح هذا مشكلة إذا كانت لديك ملفات JSON كبيرة جدًا وليس لديك وفرة في الذاكرة.
من أجل تقليل استخدام وحدة المعالجة المركزية والذاكرة المطلوب، أصبحت صيغة JSONL (أسطر JSON)، التي لا تضع كل شيء في مصفوفة عملاقة، أكثر شيوعًا.
يُخرج Hayabusa بصيغتي JSON وJSONL، إلا أن صيغة JSON لم تعد محفوظة داخل مصفوفة.
الفرق الوحيد هو أن صيغة JSON أسهل في القراءة في محرر نصوص أو على وحدة التحكم، بينما تخزن صيغة JSONL كل كائن JSON في سطر واحد.
ستكون صيغة JSONL أسرع قليلًا وأصغر حجمًا، لذا فهي مثالية إذا كنت ستستورد السجلات فقط إلى SIEM، إلخ... دون النظر إليها.
صيغة JSON مثالية إذا كنت ستقوم أيضًا ببعض التحقق اليدوي.
إنشاء ملفات نتائج JSON¶
في الإصدار الحالي 2.x من Hayabusa، يمكنك حفظ النتائج بصيغة JSON باستخدام hayabusa json-timeline -d <directory> -o results.json أو hayabusa json-timeline -d <directory> -J -o results.jsonl لصيغة JSONL.
سيستخدم Hayabusa ملف التعريف الافتراضي standard ويحفظ فقط الحد الأدنى من البيانات للتحليل في كائن Details.
إذا كنت تريد حفظ جميع معلومات الحقول الأصلية في سجلات .evtx، يمكنك استخدام ملف التعريف all-field-info مع الخيار --profile all-field-info.
سيحفظ هذا جميع معلومات الحقول إلى كائن AllFieldInfo.
إذا كنت تريد حفظ كل من كائني Details وAllFieldInfo تحسبًا، يمكنك استخدام ملف التعريف super-verbose.
فوائد استخدام Details بدلًا من AllFieldInfo¶
الفائدة الأولى لاستخدام Details بدلًا من AllFieldInfo هي أنه يتم حفظ الحقول المهمة فقط، وتم اختصار أسماء الحقول لتوفير مساحة الملف.
الجانب السلبي هو أن هناك احتمالًا لفقدان بيانات كنت تهتم بها فعلًا لكنها فُقدت.
الفائدة الثانية هي أن Hayabusa سيحفظ الحقول بطريقة أكثر توحيدًا عن طريق تطبيع أسماء الحقول.
على سبيل المثال، في سجلات Windows الأصلية، يكون اسم المستخدم عادةً في حقل SubjectUserName أو TargetUserName.
ومع ذلك، أحيانًا يكون اسم المستخدم في حقل AccountName، وأحيانًا يكون المستخدم المستهدف في الواقع في حقل SubjectUserName، إلخ...
لسوء الحظ، هناك العديد من أسماء الحقول غير المتسقة في سجلات أحداث Windows.
يحاول Hayabusa تطبيع هذه الحقول، بحيث يكون على المحلل فقط تحليل اسم شائع بدلًا من الاضطرار إلى فهم العدد اللانهائي من الخصوصيات والتناقضات بين معرّفات الأحداث في Windows.
إليك مثالًا على حقل المستخدم.
سيقوم Hayabusa بتطبيع SubjectUserName وTargetUserName وAccountName إلخ... بالطريقة التالية:
* SrcUser (المستخدم المصدر): عندما يحدث إجراء من مستخدم. (عادةً مستخدم بعيد.)
* TgtUser (المستخدم المستهدف): عندما يحدث إجراء على مستخدم. (على سبيل المثال، تسجيل دخول إلى مستخدم.)
* User: عندما يحدث إجراء بواسطة مستخدم مسجّل الدخول حاليًا. (لا يوجد اتجاه معين في الإجراء.)
مثال آخر هو العمليات.
في سجلات أحداث Windows الأصلية، يُشار إلى حقل العملية باصطلاحات تسمية متعددة: ProcessName وImage وprocessPath وApplication وWindowsDefenderProcessName إلخ...
بدون تطبيع الحقول، سيكون على المحلل أولًا أن يكون على دراية بجميع أسماء الحقول المختلفة، ثم استخراج جميع السجلات بأسماء الحقول هذه، ثم دمجها معًا.
يمكن للمحلل توفير الكثير من الوقت والعناء باستخدام حقل Proc المفرد المطبّع الذي يوفره Hayabusa في كائن Details.
دروس/وصفات jq¶
سأذكر الآن العديد من الدروس/الوصفات من الأمثلة العملية التي قد تساعدك في عملك.
1. التحقق اليدوي باستخدام jq وLess بالألوان¶
هذا أحد أول الأشياء التي يجب القيام بها لفهم الحقول الموجودة في السجلات.
يمكنك ببساطة تنفيذ less results.json لكن الطريقة الأفضل هي التالية:
cat results.json | jq -C | less -R
عن طريق التمرير إلى jq، سيقوم بتنسيق جميع الحقول بشكل أنيق لك إذا لم تكن منسقة بشكل أنيق في الأصل.
باستخدام الخيار -C (اللون) مع jq والخيار -R (الإخراج الخام) مع less، يمكنك التمرير لأعلى وأسفل بالألوان.
2. المقاييس¶
يمتلك Hayabusa بالفعل وظيفة لطباعة عدد ونسبة الأحداث بناءً على معرّفات الأحداث، ومع ذلك، من الجيد أيضًا معرفة كيفية القيام بذلك باستخدام jq.
سيتيح لك هذا تخصيص البيانات التي تريد إنشاء مقاييس لها.
لنستخرج أولًا قائمة بمعرّفات الأحداث باستخدام الأمر التالي:
cat results.json | jq '.EventID'
سيستخرج هذا فقط رقم معرّف الحدث من كل سجل.
بعد jq، بين علامتي اقتباس مفردتين، اكتب فقط . واسم الحقل الذي تريد استخراجه.
يجب أن ترى قائمة طويلة مثل هذه:
الآن، مرّر النتائج إلى أمري sort وuniq -c لعدّ عدد المرات التي حدثت فيها معرّفات الأحداث:
cat results.json | jq '.EventID' | sort | uniq -c
سيقوم الخيار -c لـ uniq بعدّ عدد المرات التي حدث فيها معرّف حدث فريد.
يجب أن ترى شيئًا مثل هذا:
على اليسار العدد، وعلى اليمين معرّف الحدث. كما ترى فهي ليست مفروزة، لذا من الصعب معرفة أي معرّفات الأحداث حدثت أكثر.
يمكنك إضافة sort -n في النهاية لإصلاح هذا:
cat results.json | jq '.EventID' | sort | uniq -c | sort -n
يخبر الخيار -n الأمر sort بالفرز حسب الرقم.
يجب أن ترى شيئًا مثل هذا:
يمكننا أن نرى أن أحداث 4688 (إنشاء العملية) سُجّلت أكثر من غيرها.
ثاني أكثر حدث تم تسجيله كان 4625 (تسجيل الدخول الفاشل).
إذا كنت تريد طباعة الأحداث الأكثر تسجيلًا في الأعلى، فيمكنك عكس الفرز باستخدام sort -n -r أو sort -nr.
يمكنك أيضًا طباعة أعلى 10 أحداث مسجلة فقط عن طريق تمرير النتائج إلى head -n 10.
cat results.json | jq '.EventID' | sort | uniq -c | sort -nr | head -n 10
سيعطيك هذا:
من المهم مراعاة أن معرّفات الأحداث (EIDs) ليست فريدة، لذا قد يكون لديك أحداث مختلفة تمامًا بنفس معرّف الحدث.
لذلك، من المهم أيضًا التحقق من Channel.
يمكننا إضافة معلومات هذا الحقل بهذه الطريقة:
cat results.json | jq -j ' .Channel , " " , .EventID , "\n" ' | sort | uniq -c | sort -nr | head -n 10
نضيف الخيار -j (الدمج) إلى jq لدمج جميع الحقول معًا مفصولة بفواصل ومنتهية بحرف سطر جديد \n.
سيعطينا هذا:
12277 Sec 4688
7135 Sec 4625
2584 Sec 5145
2321 Sysmon 1
1382 Sys 7045
1131 PwSh 4104
682 PwSh 4103
433 Sec 5140
400 Sec 4624
391 Sysmon 8
ملاحظة: يُختصر Security إلى Sec، وSystem إلى Sys، وPowerShell إلى PwSh.
يمكننا إضافة عنوان القاعدة على النحو التالي:
cat results.json | jq -j ' .Channel , " " , .EventID , " " , .RuleTitle , "\n" ' | sort | uniq -c | sort -nr | head -n 10
سيعطينا هذا:
9714 Sec 4688 Proc Exec
3564 Sec 4625 Logon Failure (Wrong Password)
3561 Sec 4625 Metasploit SMB Authentication
2564 Sec 5145 NetShare File Access
1459 Sysmon 1 Proc Exec
1418 Sec 4688 Susp CmdLine (Possible LOLBIN)
789 PwSh 4104 PwSh Scriptblock
680 PwSh 4103 PwSh Pipeline Exec
433 Sec 5140 NetShare Access
342 Sec 4648 Explicit Logon
يمكنك الآن استخراج أي بيانات بحرية من السجلات وعدّ التكرارات.
3. التصفية على بيانات معينة¶
في كثير من الأحيان ستحتاج إلى التصفية على معرّفات أحداث أو مستخدمين أو عمليات أو معرّفات تسجيل دخول (LIDs) معينة، إلخ...
يمكنك القيام بذلك باستخدام select داخل استعلام jq.
على سبيل المثال، لنستخرج جميع أحداث تسجيل الدخول الناجح 4624:
cat results.json | jq 'select ( .EventID == 4624 ) '
سيعيد هذا جميع كائنات JSON لمعرّف الحدث 4624:
{
"Timestamp": "2021-12-12 16:16:04.237 +09:00",
"Computer": "fs03vuln.offsec.lan",
"Channel": "Sec",
"Provider": "Microsoft-Windows-Security-Auditing",
"EventID": 4624,
"Level": "info",
"RecordID": 1160369,
"RuleTitle": "Logon (Network)",
"RuleAuthor": "Zach Mathis",
"RuleCreationDate": "2020/11/08",
"RuleModifiedDate": "2022/12/16",
"Status": "stable",
"Details": {
"Type": 3,
"TgtUser": "admmig",
"SrcComp": "",
"SrcIP": "10.23.123.11",
"LID": "0x87249a8"
},
"RuleFile": "Sec_4624_Info_Logon-Type-3-Network.yml",
"EvtxFile": "../hayabusa-sample-evtx/EVTX-to-MITRE-Attack/TA0007-Discovery/T1046-Network Service Scanning/ID4624-Anonymous login with domain specified (DonPapi).evtx",
"AllFieldInfo": {
"AuthenticationPackageName": "NTLM",
"ImpersonationLevel": "%%1833",
"IpAddress": "10.23.123.11",
"IpPort": 60174,
"KeyLength": 0,
"LmPackageName": "NTLM V2",
"LogonGuid": "00000000-0000-0000-0000-000000000000",
"LogonProcessName": "NtLmSsp",
"LogonType": 3,
"ProcessId": "0x0",
"ProcessName": "-",
"SubjectDomainName": "-",
"SubjectLogonId": "0x0",
"SubjectUserName": "-",
"SubjectUserSid": "S-1-0-0",
"TargetDomainName": "OFFSEC",
"TargetLogonId": "0x87249a8",
"TargetUserName": "admmig",
"TargetUserSid": "S-1-5-21-4230534742-2542757381-3142984815-1111",
"TransmittedServices": "-",
"WorkstationName": ""
}
إذا كنت تريد التصفية على شروط متعددة، يمكنك استخدام كلمات مفتاحية مثل and وor وnot.
على سبيل المثال، لنبحث عن أحداث 4624 حيث يكون النوع 3 (تسجيل دخول شبكي).
cat results.json | jq 'select ( ( .EventID == 4624 ) and ( .Details.Type == 3 ) ) '
سيعيد هذا جميع الكائنات حيث يكون EventID هو 4624 ويكون الحقل المتداخل "Details": { "Type" } هو 3.
لكن هناك مشكلة.
قد تلاحظ أخطاءً تقول jq: error (at <stdin>:10636): Cannot index string with string "Type".
في أي وقت ترى فيه الخطأ Cannot index string with string، فهذا يعني أنك تطلب من jq إخراج حقل غير موجود أو من النوع الخاطئ.
يمكنك التخلص من هذه الأخطاء بإضافة ? إلى نهاية الحقل.
هذا يخبر jq بتجاهل الأخطاء.
مثال: cat results.json | jq 'select ( ( .EventID == 4624 ) and ( .Details.Type? == 3 ) ) '
الآن، بعد التصفية على معايير معينة، يمكننا استخدام | داخل استعلام jq لتحديد حقول معينة محل اهتمام.
على سبيل المثال، لنستخرج اسم المستخدم المستهدف TgtUser وعنوان IP المصدر SrcIP:
cat results.json | jq -j 'select ( ( .EventID == 4624 ) and ( .Details.Type? == 3 ) ) | .Details.TgtUser , " " , .Details.SrcIP , "\n" '
مرة أخرى، نضيف الخيار -j (الدمج) إلى jq لتحديد حقول متعددة للإخراج.
يمكنك بعد ذلك تشغيل sort وuniq -c إلخ... كما في الأمثلة السابقة لمعرفة عدد المرات التي سجّل فيها عنوان IP معين الدخول إلى مستخدم عبر تسجيل دخول شبكي من النوع 3.
4. حفظ الإخراج بصيغة CSV¶
لسوء الحظ، ستختلف الحقول في سجلات أحداث Windows اختلافًا تامًا وفقًا لنوع الحدث، لذا ليس من الممكن بسهولة إنشاء جداول زمنية مفصولة بفواصل حسب الحقول دون وجود مئات الأعمدة.
ومع ذلك، من الممكن إنشاء جداول زمنية مفصولة بالحقول لأنواع مفردة من الأحداث.
مثالان شائعان هما Security 4624 (عمليات تسجيل الدخول الناجحة) و4625 (عمليات تسجيل الدخول الفاشلة) للتحقق من الحركة الجانبية وتخمين/رش كلمات المرور.
في هذا المثال، نستخرج سجلات Security 4624 فقط ونُخرج الطابع الزمني واسم الكمبيوتر وجميع معلومات Details.
نحفظها إلى ملف CSV باستخدام | @csv، ومع ذلك، نحتاج إلى تمرير البيانات كمصفوفة.
يمكننا القيام بذلك عن طريق تحديد الحقول التي نريد إخراجها كما فعلنا سابقًا وإحاطتها بأقواس مربعة [ ] لتحويلها إلى مصفوفة.
مثال: cat results.json | jq 'select ( (.Channel == "Sec" ) and ( .EventID == 4624 ) ) | [ .Timestamp , .Computer , .Details[]? ] | @csv ' -r
ملاحظات:
* لتحديد جميع الحقول في كائن Details نضيف [].
* هناك حالات يكون فيها Details سلسلة نصية وليس مصفوفة وستعطي أخطاء Cannot iterate over string لذا تحتاج إلى إضافة ?.
* نضيف الخيار -r (الإخراج الخام) إلى jq لعدم استخدام الشرطة المائلة العكسية لتهريب علامات الاقتباس المزدوجة.
النتائج:
"2019-03-19 08:23:52.491 +09:00","WIN-77LTAPHIQ1R.example.corp",3,"user01","","10.0.2.17","0x15e1a7"
"2019-03-19 08:23:57.397 +09:00","WIN-77LTAPHIQ1R.example.corp",3,"WIN-77LTAPHIQ1R$","","fe80::79bf:8ee2:433c:2567","0x15e25f"
"2019-03-19 09:02:04.179 +09:00","WIN-77LTAPHIQ1R.example.corp",3,"ANONYMOUS LOGON","NULL","10.0.2.17","0x17e29a"
"2019-03-19 09:02:04.210 +09:00","WIN-77LTAPHIQ1R.example.corp",3,"Administrator","","10.0.2.17","0x17e2aa"
"2019-03-19 09:02:04.226 +09:00","WIN-77LTAPHIQ1R.example.corp",3,"Administrator","","10.0.2.17","0x17e2c0"
"2019-03-19 09:02:21.929 +09:00","WIN-77LTAPHIQ1R.example.corp",3,"WIN-77LTAPHIQ1R$","","fe80::79bf:8ee2:433c:2567","0x18423d"
"2019-05-12 02:10:10.889 +09:00","IEWIN7",9,"IEUser","","::1","0x1bbdce"
إذا كنا نتحقق فقط ممن قام بعمليات تسجيل دخول ناجحة، فقد لا نحتاج إلى حقل LID (معرّف تسجيل الدخول) الأخير.
يمكنك حذف أي عمود غير مطلوب باستخدام دالة del.
مثال: cat results.json | jq 'select ( ( .Channel == "Sec" ) and ( .EventID == 4624 ) ) | [ .Timestamp , .Computer , .Details[]? ] | del( .[6] ) | @csv ' -r
تبدأ المصفوفة العد من 0 لذا لإزالة الحقل السابع، نستخدم 6.
يمكنك الآن حفظ ملف CSV بإضافة > 4624-logs.csv ثم استيراده إلى Excel أو Timeline Explorer لمزيد من التحليل.
لاحظ أنك ستحتاج إلى إضافة رأس للقيام بالتصفية.
وفي حين أنه من الممكن إضافة عنوان داخل استعلام jq، إلا أنه عادةً ما يكون من الأسهل إضافة صف علوي يدويًا بعد حفظ الملف.
5. العثور على التواريخ ذات أكثر التنبيهات¶
سيخبرك Hayabusa افتراضيًا بالتواريخ التي كان بها أكثر التنبيهات وفقًا لمستويات الخطورة. ومع ذلك، قد تريد العثور على ثاني وثالث، إلخ... أكثر التواريخ بالتنبيهات أيضًا. يمكننا القيام بذلك عن طريق تقطيع السلسلة النصية للطابع الزمني للتجميع حسب السنة أو الشهر أو التاريخ حسب احتياجاتك.
مثال: cat results.json | jq ' .Timestamp | .[:10] ' -r | sort | uniq -c | sort
يخبر .[:10] الأمر jq باستخراج أول 10 بايتات فقط من Timestamp.
سيعطينا هذا التواريخ ذات أكثر الأحداث:
1066 2021-12-12
1093 2016-09-02
1571 2021-04-22
1750 2016-09-03
2271 2016-08-19
2932 2021-11-03
8095 2016-09-20
إذا كنت تريد معرفة الشهر ذي أكثر الأحداث، يمكنك ببساطة تغيير .[:10] إلى .[:7] لاستخراج أول 7 بايتات.
إذا كنت تريد إدراج التواريخ ذات أكثر تنبيهات high، يمكنك القيام بهذا:
cat results.json | jq 'select ( .Level == "high" ) | .Timestamp | .[:10] ' -r | sort | uniq -c | sort
يمكنك الاستمرار في إضافة شروط التصفية إلى دالة select وفقًا لاسم الكمبيوتر ومعرّف الحدث إلخ... حسب احتياجاتك.
6. إعادة بناء سجلات PowerShell¶
من الأمور المؤسفة بشأن سجلات PowerShell أن السجلات غالبًا ما تُقسَّم إلى سجلات متعددة مما يجعلها صعبة القراءة. يمكننا جعل السجلات أسهل بكثير في القراءة عن طريق استخراج الأوامر التي شغّلها المهاجم فقط.
على سبيل المثال، إذا كانت لديك سجلات ScriptBlock بمعرّف الحدث 4104، يمكنك استخراج ذلك الحقل فقط لإنشاء جدول زمني سهل القراءة.
cat results.json | jq 'select ( .EventID == 4104) | .Timestamp[:16] , " " , .Details.ScriptBlock , "\n" ' -jr
سينتج عن هذا جدول زمني كما يلي:
2022-12-24 10:56 ipconfig
2022-12-24 10:56 prompt
2022-12-24 10:56 pwd
2022-12-24 10:56 prompt
2022-12-24 10:56 whoami
2022-12-24 10:56 prompt
2022-12-24 10:57 cd..
2022-12-24 10:57 prompt
2022-12-24 10:57 ls
7. العثور على اتصالات الشبكة المريبة¶
يمكنك أولًا الحصول على قائمة بجميع عناوين IP المستهدفة باستخدام الأمر التالي:
cat results.json | jq 'select ( .Details.TgtIP? ) | .Details.TgtIP ' -r | sort | uniq
إذا كانت لديك معلومات استخباراتية عن التهديدات، يمكنك التحقق مما إذا كان أي من عناوين IP معروفًا بأنه خبيث.
يمكنك عدّ المرات التي تم فيها الاتصال بعنوان IP مستهدف معين باستخدام ما يلي:
cat results.json | jq 'select ( .Details.TgtIP? ) | .Details.TgtIP ' -r | sort | uniq -c | sort -n
بتغيير TgtIP إلى SrcIP، يمكنك إجراء نفس التحقق من المعلومات الاستخباراتية عن التهديدات لعناوين IP الخبيثة بناءً على عناوين IP المصدر.
لنفترض أنك وجدت أن عنوان IP الخبيث 93.184.220.29 يتم الاتصال به من بيئتك.
يمكنك الحصول على تفاصيل حول تلك الأحداث باستخدام الاستعلام التالي:
cat results.json | jq 'select ( .Details.TgtIP? == "93.184.220.29" ) '
سيعطيك هذا نتائج JSON مثل هذه:
{
"Timestamp": "2019-07-30 06:33:20.711 +09:00",
"Computer": "MSEDGEWIN10",
"Channel": "Sysmon",
"EventID": 3,
"Level": "med",
"RecordID": 4908,
"RuleTitle": "Net Conn (Sysmon Alert)",
"Details": {
"Proto": "tcp",
"SrcIP": "10.0.2.15",
"SrcPort": 49827,
"SrcHost": "MSEDGEWIN10.home",
"TgtIP": "93.184.220.29",
"TgtPort": 80,
"TgtHost": "",
"User": "MSEDGEWIN10\\IEUser",
"Proc": "C:\\Windows\\System32\\mshta.exe",
"PID": 3164,
"PGUID": "747F3D96-661E-5D3F-0000-00107F248700"
}
}
إذا كنت تريد إدراج النطاقات التي تم الاتصال بها، يمكنك استخدام الأمر التالي:
cat results.json | jq 'select ( .Details.TgtHost ) ? | .Details.TgtHost ' -r | sort | uniq | grep "\."
ملاحظة: أضفت مرشّح grep لـ
.لإزالة أسماء مضيفي NETBIOS.
8. استخراج تجزئات الملفات الثنائية القابلة للتنفيذ¶
في سجلات إنشاء العملية Sysmon بمعرّف الحدث 1، يمكن تكوين sysmon لحساب تجزئات الملف الثنائي.
يمكن لمحللي الأمن مقارنة هذه التجزئات بالتجزئات الخبيثة المعروفة باستخدام المعلومات الاستخباراتية عن التهديدات.
يمكنك استخراج حقل Hashes باستخدام ما يلي:
cat results.json | jq 'select ( .Details.Hashes? ) | .Details.Hashes ' -r
سيعطيك هذا قائمة بالتجزئات مثل هذه:
MD5=E112A827FAB9F8378C76040187A6F336,SHA256=ED369187681A62247E38D930320F1CD771756D0B7B67072D8EC655EF99E14AEB,IMPHASH=8EEAA9499666119D13B3F44ECD77A729
MD5=E112A827FAB9F8378C76040187A6F336,SHA256=ED369187681A62247E38D930320F1CD771756D0B7B67072D8EC655EF99E14AEB,IMPHASH=8EEAA9499666119D13B3F44ECD77A729
MD5=E112A827FAB9F8378C76040187A6F336,SHA256=ED369187681A62247E38D930320F1CD771756D0B7B67072D8EC655EF99E14AEB,IMPHASH=8EEAA9499666119D13B3F44ECD77A729
MD5=E112A827FAB9F8378C76040187A6F336,SHA256=ED369187681A62247E38D930320F1CD771756D0B7B67072D8EC655EF99E14AEB,IMPHASH=8EEAA9499666119D13B3F44ECD77A729
سيقوم Sysmon عادةً بحساب تجزئات متعددة مثل MD5 وSHA1 وIMPHASH.
يمكنك استخراج هذه التجزئات باستخدام التعبيرات النمطية في jq أو ببساطة استخدام تقطيع السلسلة النصية لأداء أفضل.
على سبيل المثال، يمكنك استخراج تجزئات MD5 وإزالة التكرارات باستخدام ما يلي:
cat results.json | jq 'select ( .Details.Hashes? ) | .Details.Hashes | .[4:36] ' -r | sort | uniq
9. استخراج سجلات PowerShell¶
عادةً ما تُقسَّم سجلات Scriptblock في PowerShell (معرّف الحدث: 4104) إلى سجلات كثيرة، وعند الإخراج بصيغة CSV، سيحذف Hayabusa علامات الجدولة وأحرف الإرجاع لجعل الإخراج أكثر إيجازًا.
ومع ذلك، من الأسهل تحليل سجلات powershell بتنسيق علامات الجدولة وأحرف الإرجاع الأصلية ودمج السجلات معًا.
إليك مثالًا على استخراج سجلات PowerShell بمعرّف الحدث 4104 من COMPUTER-A وحفظها إلى ملف .ps1 من أجل فتحها وتحليلها في VSCode، إلخ...
بعد استخراج حقل ScriptBlock، نستخدم awk لاستبدال \r\n و\n بأحرف الإرجاع و\t بعلامات الجدولة.
cat results.json | jq 'select ( .EventID == 4104 and .Details.ScriptBlock? != "n/a" and .Computer == "COMPUTER-A.domain.local" ) | .Details.ScriptBlock , "\r\n"' -j | awk '{ gsub(/\\r\\n/,"\r\n"); print; }' | awk '{ gsub(/\\t/, "\t"); print; }' | awk '{ gsub(/\\n/, "\r\n"); print; }' > 4104-PowerShell-Logs.ps1
بعد أن يحلل المحلل السجلات بحثًا عن أوامر PowerShell الخبيثة، سيحتاج عادةً بعد ذلك إلى البحث عن وقت تشغيل تلك الأوامر. إليك مثالًا على إخراج الطابع الزمني وسجلات PowerShell إلى ملف CSV من أجل البحث عن وقت تشغيل أمر ما:
cat results.json | jq ' select (.EventID == 4104 and .Details.ScriptBlock? != "n/a" and .Computer == "COMPUTER-A.domain.local") | .Timestamp, ",¦", .Details.ScriptBlock?, "¦\r\n" ' -j | awk '{ gsub(/\\r\\n/,"\r\n"); print; }' | awk '{ gsub(/\\t/,"\t"); print; }' | awk '{ gsub(/\\n/,"\r\n"); print; }' > 4104-PowerShell-Logs.csv
ملاحظة: محدد السلسلة النصية المستخدم هو ¦ لأن علامات الاقتباس المفردة والمزدوجة توجد غالبًا في سجلات PowerShell وستفسد إخراج CSV.
عند استيراد ملف CSV، تحتاج إلى تحديد محدد السلسلة النصية ¦ للتطبيق.