Nakerah CTF 0x04 Write-up

Nakerah CTF 0x04 Write-up

=====================================================
CTF 0x04 Write-up
=====================================================


في هذا المقال سنقوم بحل CTF 0x04 ,و هو عباره عن Code برنامج تشفير نصوص. في بداية التحدي يتم أمدادنا بنص مشفر باستخدام هذا الـ Code والمطلوب عمل Decrypt للنص، اى فك تشفيره بالاضافة الى القدرة على فك تشفير اي نص اخر تم تشفيره بواسطة هذا ال Code


Code:
\x31\xc0\x83\xc4\x08\x68\x65\x66\x67\x68\x68\x61\x62\x63\x64\x54\x5e\x89\xf7\xfc\xb1
\x08\xac\x50\x52\x0f\x31\x35\xff\xff\x00\x00\x88\xc2\x21\xd0\x89\xc3\x5a\x58\x30\xd8\xaa\x88
\x5c\x0c\x08\xe2\xe5\x54\x5e\x68\x63\x64\x65\x66\x68\x38\x39\x61\x62\x68\x34\x35\x36\x37
\x68\x30\x31\x32\x33\x54\x5b\xb1\x11\x31\xd2\x50\xac\x88\xc4\xc0\xe8\x04\x80\xe4\x0f\xd7
\x86\xe0\xd7\x88\xa2\x00\x91\x04\x08\x42\x88\x82\x00\x91\x04\x08\x42\x58\xe2\xe1\x31
\xdb\xb9\x00\x91\x04\x08\xb2\x22\xb3\x01\xb0\x04\xcd\x80\xb0\x01\xcd\x80


اذا نظرنا الى Code سوف نعرف انه Shellcode "كما هو متعارف عليه" أو Machine Code ممثل فى Hexadecimal.

و ال Machine code هى اللغة التى يتعامل بها و يفهمها ال CPU ويمكن ترجمتها لمجموعه من أوامر"instructions" للغة Assembly وهذه Assembly instructions تسمى mnemonics .و لكي نستطيع فهم هذا ال Machine code سوف تقوم بعمل Disassemble اى تحويل ال machine code الى mnemonics يسهل قرائتها.

بداية يجب أن نعرف أن "x\" هنا هى escape sequence توضح ان القيمة التى تليها ممثلة فى Hexadecimal وهي ليست جزء من الـ Code نفسه. لذلك سوف نقوم اولا بالتخلص منها عن طريق استبدلها ب space لان بعض ال Disassemblers اذا قمنا باعطائها ال machine code بهذه الصورة سوف تصدر خطأ اثناء عملية ال Disassembly.

توجد عدة طرق للقيام بذلك ولكن سنتعرض لطريقة واحدة فقط. سوف نقوم بنسخ ال shellcode فى ملف باستخدام vim وهو محرر نصوص يعمل على Linux و مماثل لمحرر النصوص vi وهو يتيح لنا كتابة اوامر تنفذ على النص منها عمل بحث واستبدال لنص معين داخل الملف.

سوف نقوم اولا بانشاء ملف عن طريق الامر vim shellcode.txt وعمل paste للـ shellcode فيه ثم بعد ذلك نقوم بالضغط على Esc لكى نخرج من insert mode الذي يسمح لنا بالتعديل فى النص ثم نكتب ":" لكى ندخل الى Command mode الخاص ب vim ثم نكتب الامر التالى لكى يستبدل كل " x\" بـ "space" و يكون syntax الامر كالتالى :


:[address]s/old_text/new_text/
Code:
:%s/\\x/ /g

بعد تنفيذ الأمر سوف نحصل على تلك النتيجة:


Code:
31 c0 83 c4 08 68 65 66 67 68 68 61 62 63 64 54 5e 89 f7 fc b1
08 ac 50 52 0f 31 35 ff ff 00 00 88 c2 21 d0 89 c3 5a 58 30 d8 aa 88
5c 0c 08 e2 e5 54 5e 68 63 64 65 66 68 38 39 61 62 68 34 35 36 37
68 30 31 32 33 54 5b b1 11 31 d2 50 ac 88 c4 c0 e8 04 80 e4 0f d7
86 e0 d7 88 a2 00 91 04 08 42 88 82 00 91 04 08 42 58 e2 e1 31
db b9 00 91 04 08 b2 22 b3 01 b0 04 cd 80 b0 01 cd 80


بعد ذلك نقوم بنسخ النتيجة عن طريق عمل select لها ثم الضغط على "y" لعمل copy او yank.
و لحفظ الملف نقوم بكتابة الامر:


Code:
:wq

الخطوه التاليه هى تشغيل الـ shellcode او عمل disassembly له عن طريق عمل Analysis لل code لفهم كيف تتم عمليه ال encryption فى البرنامج لكى نستطيع عمل decryption للنصوص المشفره.

و لتنفيذ هذه الخطوة توجد عدة طرق منها:

الطريقة الأولى :استخدام udis86 و هى library لعمل disassembly بتنفيذ الامر :


Code:
udcli -x -32 -intel shellcode.txt

CTF_04_udcli_01.png


الطريقة الثانية : باستخدام Debugger مثل Immunity Debugger هو برنامج يستخدم فى الهندسه العكسيه Reverse Engineering و Malware Analysis و فى كتابه ال Exploits.

سوف نستخدم هنا immunity debugger و سوف نقوم بتشغيل الكود عن طريق عمل binary paste للـ shellcode داخل immunity debugger بعد فتح اى برنامج exe فى ال immunity debugger سوف نستخدم هنا "internet explorer" ثم عمل select لمجموعة من ال instructions لم تنفذ بعد (يمكنك مراجعة EIP لمعرفة ما هي الـ Instruction القادمة التي سيتم تنفيذها). يجب عمل select لعدد كبير من الـ instructions لضمان وجود مكان كافي لاستيعاب الـ shellcode الخاص بنا. يمكننا التأكد من ذلك عن طريق التحقق من أخر Instruction تم عمل paste لها وأنها بالفعل آخر Instruction في الـ Shellcode الخاص بنا.


immunity_001_01.png


سوف يكون البرنامج فى حال الـ Pause ,سوف نقوم بالضغط على f9 لتشغيله ولكننا سوف نحصل على Access Violation لان احد ال instructions تريد الوصول الى Protected memory Address اى انه لا يجوز لهذا البرنامج الوصول لهذا الـ Memory location ,و هذا حدث لان ECX register يتواجد به قيمة ما (والمفترض أن يتم عمل Initialization له ليصبح 0) و بالتالى لن تنفذ الـ Loop بشكل صحيح , و للتغلب على هذه النقطه سوف نقوم بتعديل ال shellcode لكى نقوم بمسح محتويات ال ECX قبل البدء فى تنفيذ ال shellcode

فبالتالى الـ assembly instruction التى يجب ان نقوم باضافتها هى :


Code:
xor ecx,ecx


و ذلك يمكن ان يتم بواسطة عدة طرق منها:

الطريقة الأولى: باستخدام nasm.rb ويتم ذلك عن طريق تشغيل ال tool ثم كتابه ال Assembly instruction لكى نحصل على ال Machine code المكافئ لها


CTF_04_8_nasm_01.png

الطريقة الثانية: عن طريق استخدام ال Immunity Debugger يمكن لنا ان نقوم بكتابه ال instructions بشكل مباشر دون الحاجه للتحويل الى Machine code وذلك عن طريق اختيار instruction فى البرنامج ثم الضغط على space أو "right click -> assemble" ثم نكتب الأمر كالاتى:


CTF_04_9_immunity_01.png


والان لنعود الى الـ shellcode…..بعد ان حصلنا على ال machine code ل XOR ECX,ECX سوف نقوم باضافتها فى shellcode قبل اول استخدام للECX register سنكتبه هنا بعد ال CLD instruction و قبل mov cl,8 فيصبح shellcode كالتالى


Code:
31 c0 83 c4 08 68 65 66 67 68 68 61 62 63 64 54 5e 89 f7 fc 31 c9 b1
08 ac 50 52 0f 31 35 ff ff 00 00 88 c2 21 d0 89 c3 5a 58 30 d8 aa 88
5c 0c 08 e2 e5 54 5e 68 63 64 65 66 68 38 39 61 62 68 34 35 36 37
68 30 31 32 33 54 5b b1 11 31 d2 50 ac 88 c4 c0 e8 04 80 e4 0f d7
86 e0 d7 88 a2 00 91 04 08 42 88 82 00 91 04 08 42 58 e2 e1 31
db b9 00 91 04 08 b2 22 b3 01 b0 04 cd 80 b0 01 cd 80
CTF_04_14_immunity_02.png

نجد الآن Access violation ولكن خاصه ب instruction اخرى ,واذا نظرنا الى ال memory address سوف نجد انه immediate addressing أى انه قيمة ثابتة مكتوبه فى shellcode. هذا ال Memory Address هو الذي يقوم الكود بعمل write للنص المشفر فيه.

و لتخطى هذه ال access violation سوف نضع memory address يستطيع البرنامج الوصول اليه وسوف نختار memory address فى نطاق ال Stack ,و حيث ان ال ESP يحتوى على memory location هو "13ffd4" فيمكن مثلا ان نستبدل 08049100 ب 132000 و نقوم باعاده كتابه ال instructions التى كانت تحتوى عليه لتصبح:


Code:
Mov Byte PTR DS:[EDX+0x132000],AH
Mov Byte PTR DS:[EDX+0x132000],AL
Mov ECX,0x132000


نقوم بكتابه كتابه كل instruction فى مكانه ليصبح ال shellcode بعد التعديل :


Code:
31 c0 83 c4 08 68 65 66 67 68 68 61 62 63 64 54 5e 89 f7 fc 31 c9 b1
08 ac 50 52 0f 31 35 ff ff 00 00 88 c2 21 d0 89 c3 5a 58 30 d8 aa 88
5c 0c 08 e2 e5 54 5e 68 63 64 65 66 68 38 39 61 62 68 34 35 36 37
68 30 31 32 33 54 5b b1 11 31 d2 50 ac 88 c4 c0 e8 04 80 e4 0f d7
86 e0 d7 88 A2 00 20 13 00 42 88 82 00 20 13 00 42 58 e2 e1 31
db B9 00 20 13 00 b2 22 b3 01 b0 04 cd 80 b0 01 cd 80


بعد ذلك تعديل و اعادة التشغيل واضافة الـ shellcode سوف نبدأ عمل Analysis ل shellcode و سوف نقسم العمليه الى جزئين :

الجزء الاول :


CTF_04_19_immunity_01.png


هنا يتم عمل Push للنص المراد تشفيره فى ال stack ثم يتم اخذ كل حرف على حده ليخضع لعملية xor مع قيمة ناتجة عن عدة أوامر أولها RDTSC ,ثم بعد عمليه ال xor يتم تخزين النتيجة بالإضافة إلى القيمة التى تم عمل xor لها مع الحرف .و تلك العمليه هى اساس ال encryption حيث ان اذا كان هناك اثنان operands و قمنا بعمل xor لهم ,فيمكن لنا ان نقوم بعمل xor للنتيجه مع احد تلك ال operands حتى نحصل على ال operand الاخر.


Code:
a “ascii” ----> 61 hexadecimal
61 xor DD = BC
BC xor DD = 61
CTF_04_21_immunity_01.png

الجزء الثانى :

هنا يتم عمل push ل string وهو 0123456789abcdef وهى ال hexadecimal characters حيث أن هذا ال string سوف يتم استخدامه كجدول مع xlat instruction فى LOOP لعمل Translation لكل hexadecimal character من ال string المشفر الناتج عن الجزء الاول ثم الاحتفاظ به بدايتا من الMemory address الذى قمنا بتحديده مسبقا و هو 0x132000 لانه سوف يحتوى على الناتج النهائى الخاص بال decrypted string و تكون ال index لهذا الجدول هى ال value الخاصة ب AL .


CTF_04_24_immunity_01.png


الجزء الثالث :

هنا يستخدم الكود () system call write و exit فى ال Linux للقيام بعملية طباعة النص المشفر على الشاشة ثم عمل exit


CTF_04_25_immunity_01.png


الDecryptor :

سوف نقوم بكتابة Assembly instructions لعمل Decryption للنص :

بعد أن قمنا بعمل Analysis لل assembly instruction و عرفنا كيف يتم تشفير اى نص نستطيع عمل Reverse Engineering أو هندسه عكسيه للكود لفك تشفير أى نص تم تشفيره بواسطة هذا الكود.


Code:
0967b4941d0e6fe2f15757c300f72f6797cf073f6fa7df2767


سنحتاج أولا لمعرفة عدد ال characters بالنص و تحويلها الى hexadecimal ,يمكن لنا عن طريق كتابة الأمر التالي :



Code:
echo -n "0967b4941d0e6fe2f15757c300f72f6797cf073f6fa7df2767" | wc -c
Printf ‘%x \n’ 50
CTF_04_27_terminal_01.png


كود فك التشفير :

توجد طريقتين :

1- اما ان نقوم باعطاء الكود الencrypted string عن طريق عمل push لها ثم عمل loop لحفظه ب memory location

0x132000 ,سيكون ال machine code كالتالى



Code:
68 36 37 00 00 68 64 66 32 37 68 36 66 61 37 68 30 37 33 66 68 39 37 63 66 68 32 66 36 37 68 3030 66 37 68 35 37 63 33 68 66 31 35 37 68 36 66 65 32 68 31 64 30 65 68 62 34 39 34 68 30 39 3637 B9 32 00 00 00 31 D2 54 5E BF 00 20 13 00 AC AA 42 E2 FB 68 63 64 65 66 68 38 39 61 62 68 3435 36 37 68 30 31 32 33 B9 00 20 13 00 54 5F 89 FB 51 5E 31 C9 57 89 D0 B9 02 00 00 00 F6 F1 89C2 42 31 C9 B9 00 21 13 00 01 D1 51 31 C9 B1 11 53 5F AC F2 AE FE C9 80 F1 0F 88 CC 90 B1 11 535F AC F2 AE FE C9 80 F1 0F 88 C8 C0 E4 04 08 E0 88 82 00 21 13 00 4A 89 D1 E2 D3 BE 02 21 13 005A 89 D0 29 F0 B9 02 00 00 00 F6 F1 89 C1 BF 00 22 13 00 31 C0 AC 8A 22 4A 30 E0 AA E2 F5 B9 0022 13 00 83 C3 14
CTF_04_28_immunity_01.png


2- ان نقوم بتحويل النص من Ascii الى hexadecimal ثم نقوم فى ال immunity debugger بعمل inject encrypted string بشكل مباشر فى ال memory location 0x132000 "طريقة عملية اكثر و اسهل في التنفيذ" باختيار ال memory dump ثم الضغط على ctrl+g و كتابة ال memory location المراد الذهاب اليه و عمل binary paste لل hexdecimal value للنص كالتالى:

استخدمنا xxd -p لتحويل النص الى plaintext hexdump style


Code:
printf ‘0967b4941d0e6fe2f15757c300f72f6797cf073f6fa7df2767’ | xdd -p


:النتيجه


Code:
3039363762343934316430653666653266313537353763333030663732663637393763663037336636666137646632373637


نذهب الى memory location 0x132000 ثم نقوم بعمل ال binary paste ل hex به و نقوم بعمل binary paste ل "كود التشفير" Machine code فتكون النتيجه كالتالى:
كود التشفير :


Code:
BA 32 00 00 00 68 63 64 65 66 68 38 39 61 62 68 34 35 36 37 68 30 31 32 33 B9 00 20 13 00 54 5F 89 FB 51 5E 31 C9 57 89 D0 B9 02 00 00 00 F6 F1 89 C2 42 31 C9 B9 00 21 13 00 01 D1 51 31 C9 B1 11 53 5F AC F2 AE FE C9 80 F1 0F 88 CC 90 B1 11 53 5F AC F2 AE FE C9 80 F1 0F 88 C8 C0 E4 04 08 E0 88 82 00 21 13 00 4A 89 D1 E2 D3 BE 02 21 13 00 5A 89 D0 29 F0 B9 02 00 00 00 F6 F1 89 C1 BF 00 22 13 00 31 C0 AC 8A 22 4A 30 E0 AA E2 F5 B9 00 22 13 00 BB 00 20 13 00

CTF_04_31_terminal_01.png


سوف نتبع تلك الطريقة

نظرة عامة عن الكود :

سوف نقسم الكود الى جزأين

الجزء الأول :
وهى reversing الجزء الثانى من عملية التشفير حيث أن الكود يحتوى على طول النص و نقوم هنا بعمل push ل hexadecimal table كالذى تم استخدامه فى عملية التشفير فى الجزء الثانى ثم بعد ذلك نقوم بعمل nested loop و عمل قسمه لطول النص على 2 لاننا كل count فى ال loop الرئيسية سوف نقوم بعمل translation ل 2bytes من ال address 0x132000 عن طريق اخذ كل byte و عمل مقارنه لها بمحتويات الجدول وعندما يتم العثور عليه يتم اخذ ال index الموجوده به القيمه للعمليتين "تكرر مره لكل byte" و نقله الى memory address هو EDX+0x132100 أى انه سوف يكتب معكوس من الاخر الى 0x132100 "بمعنى آخر كتابه الASCII داخل ال memory"

مثال 30 39 فى ال memory سوف تحول الى 09 ويتم تسجيلها فى EDX+0x132100



CTF_04_32_table_01.png


CTF_04_33_immunity_01.png
CTF_04_35_immunity_01.png

وبعد الانتهاء من ال LOOP ستكون الmemory بالشكل التالى :



CTF_04_36_immunity_01.png

الجزء الثانى :
وهو reverse للجزء الاول فى كود التشفير وذلك عن طريق عمل xor لاول byte مع اخر byte ثم ال byte الثانية من الأول مع الثانية من النهاية ... ثم حفظ الناتج فى memory location 0x132200 وهو ال plaintext ممثل فى hexadecimal



CTF_04_37_immunity_01.png

و بعد تنفيذ الكود نحصل على ال Flag و هو n@k3r1h-f0x4


CTF_04_38_immunity_01.png

الحل ب High level language Decryptor :
بعد فهم كيفية عمل كود الـ encryption نستطيع إنشاء tool باى لغه كال python لتقوم بفك التشفير كهذه ال tool تقوم باخذ النص المشفر و عمل xor بنفس الطريقه لتحويله الى Plaintext


Code:
#!/usr/bin/python
import sys

if len(sys.argv) !=2:
   print("")
   print ("[*] Usage: nakerah_ctf_04_decryptor PASTE_YOUR_HASH_HERE ")
   print("")
else:
   def xor(s1,s2):  # xor function
       result=hex(int(s1,16) ^ int(s2,16))
       return result[2:]
 
   my_hash=sys.argv[1] #"ff409d3a27406d8674ee0a26425efe229e"
   hash1=my_hash[0:int(len(my_hash)/2-1)]
   hash2=my_hash[int(len(my_hash)/2+1):]
   hash2_reversed=""
   hash2_tmp=hash2
   i=len(hash2)/2
 
   while i>=0:
       hash2_reversed=hash2_reversed + hash2_tmp[-2:]
       hash2_tmp=hash2_tmp[0:-2]
       i=i-1
   i=0
   hash2_lengh=len(hash2_reversed)
   plaintext_hex=""

   while i<hash2_lengh:

       tmp1=hash1[i:i+2]
       tmp2=hash2_reversed[i:i+2]
       plaintext_hex=plaintext_hex+xor(tmp1,tmp2)
       i=i+2

   plaintext_ascii=(bytearray.fromhex(plaintext_hex).decode())
   print("")
   print("Plaintext is :"+plaintext_ascii)
   print("")
Author
Younes.Hassanin
Views
1,946
First release
Last update
Rating
5.00 star(s) 7 ratings

Latest reviews

♡♡
مقال رائع اتمنى منك اضافة تحديات اخرى و ربنا يجعله في ميزان حسناتك
Great
Top