Skip to content
KitploitKITPLOIT
أدواتعمليات الاستغلالالمدونة
Log in
إرسال
أدواتعمليات الاستغلالالمدونة
إرسال

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/y4er/weblogic-shiro-shell
تحليل الثغرات الأمنيةالاستغلالاستغلال تطبيقات الويباختبار الاختراقالتعلم والتعليمتطوير الحمولاتاستغلال الملفات الثنائية
GitHuby4er/weblogic-shiro-shell

WebLogic-Shiro-shell

WebLogic يستخدم CVE-2020-2883 لاستغلال ثغرة إلغاء التسلسل Shiro rememberMe، وتسجيل filter لـ AntSword كـ shell في الذاكرة بنقرة واحدة.

عرض المستودع
5316012منذ 6 سنواتتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

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

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

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

عرض جميع الأدوات →
مشاركة

مشاركة تقنية حول إلغاء تسلسل Java

تتضمن هذه المشاركة النقاط التالية:

  1. أساسيات تسلسل وإلغاء تسلسل Java
  2. لماذا تحدث الثغرات الأمنية أثناء إلغاء التسلسل؟
  3. الانعكاس في Java
  4. ysoserial CommonsCollections2 و CommonsCollections5
  5. عدة طرق لتحميل الفئات باستخدام ClassLoader في Java
  6. WebLogic CVE-2020-2555 و CVE-2020-2883 RCE
  7. Shiro-550 rememberMe الترميز الثابت الذي يؤدي إلى RCE عن طريق إلغاء التسلسل
  8. WebLogic + Shiro إلغاء تسلسل لتسجيل filter في الذاكرة بضغطة واحدة

أساسيات تسلسل وإلغاء تسلسل Java

يشير تسلسل Java إلى عملية تحويل كائنات Java إلى سلسلة من البايتات لتسهيل حفظها في الذاكرة أو الملفات أو قواعد البيانات. يمكن استخدام طريقة writeObject() من فئة ObjectOutputStream لتحقيق التسلسل، حيث تحول كائن Java إلى سلسلة بايت.

يشير إلغاء تسلسل Java إلى عملية استعادة الكائنات Java من سلسلة البايتات. تستخدم طريقة readObject() من فئة ObjectInputStream لإلغاء التسلسل.

لنأخذ مثالاً بسيطاً، انظر إلى الكود SerializeAndDeserialize ملاحظة: هنا نركز على تحويل النوع القسري في الكود```java package org.chabug.demo;

import org.chabug.entity.Dog; import org.chabug.entity.Person; import org.chabug.util.Serializables;

/* 这个例子是为了证明只要实现了Serializable接口的类都可以被序列化 并且Java内置的几大数据类型也可被序列化,因为他们都继承了Object类 */

public class SerializeAndDeserialize {

public static void main(String[] args) throws Exception {
    byte[] bytes;
    String s1 = "I'm a String Object....";
    bytes = Serializables.serializeToBytes(s1);
    Object o1 = Serializables.deserializeFromBytes(bytes);
    System.out.println(o1);

    String[] s2 = new String[]{"tom", "bob", "jack"};
    bytes = Serializables.serializeToBytes(s2);
    String[] o2 = (String[])Serializables.deserializeFromBytes(bytes);
    System.out.println(o2);

    int i = 123;
    bytes = Serializables.serializeToBytes(i);
    int o3 = (Integer) Serializables.deserializeFromBytes(bytes);
    System.out.println(o3);

    // 一只名叫woody的狗
    Dog dog = new Dog();
    dog.setName("woody");

    // tom
    Person tom = new Person();
    tom.setAge(14);
    tom.setName("tom");
    tom.setSex("男");
    tom.setDog(dog);

    bytes = Serializables.serializeToBytes(tom);
    Person o = (Person) Serializables.deserializeFromBytes(bytes);
    System.out.println(o);

}

}

يمكن لأنواع البيانات المضمنة في Java مثل String وInteger وArray وObject أن تقوم بالتسلسل (Serialization)، والطبقات التي نكتبها بأنفسنا مثل Person وDog يمكنها القيام بالتسلسل وإلغاء التسلسل طالما أنها تطبق واجهة Serializable.

## لماذا تحدث الثغرات أثناء إلغاء التسلسل؟

لننظر إلى مقطع كود، الآن هناك فئة كيان خبيثة EvilClass```java
package org.chabug.entity;

import java.io.ObjectInputStream;
import java.io.Serializable;

public class EvilClass implements Serializable {
    String name;

    public EvilClass() {
        System.out.println(this.getClass() + "的EvilClass()构造方法被调用!!!!!!");
    }

    public EvilClass(String name) {
        System.out.println(this.getClass() + "的EvilClass(String name)构造方法被调用!!!!!!");
        this.name = name;
    }

    public String getName() {
        System.out.println(this.getClass() + "的getName被调用!!!!!!");
        return name;
    }

    public void setName(String name) {
        System.out.println(this.getClass() + "的setName被调用!!!!!!");
        this.name = name;
    }

    @Override
    public String toString() {
        System.out.println(this.getClass() + "的toString()被调用!!!!!!");
        return "EvilClass{" +
                "name='" + getName() + '\'' +
                '}';
    }

    private void readObject(ObjectInputStream in) throws Exception {
        //执行默认的readObject()方法
        in.defaultReadObject();
        System.out.println(this.getClass() + "readObject()被调用!!!!!!");
        Runtime.getRuntime().exec(new String[]{"cmd", "/c", name});
    }
}

يحتوي readObject الخاص به على كود لتنفيذ الأوامر Runtime.getRuntime().exec(new String[]{"cmd", "/c", name})، حيث وسيط name هو الأمر المراد تنفيذه. لذا يمكننا بناء كائن خبيث، وتعيين خاصية name الخاصة به إلى الأمر المراد تنفيذه، وعند إلغاء التسلسل (deserialization) يؤدي تشغيل readObject إلى RCE. كما يلي```java package org.chabug.demo;

import org.chabug.entity.EvilClass; import org.chabug.util.Serializables;

public class EvilSerialize { public static void main(String[] args) throws Exception { EvilClass evilObj = new EvilClass(); evilObj.setName("calc"); byte[] bytes = Serializables.serializeToBytes(evilObj); EvilClass o = (EvilClass) Serializables.deserializeFromBytes(bytes); System.out.println(o); } }

![image-20200822105256120](https://assets.kitploit.com/production/public/readmes/21799/7f07c0c8196e56e1d554bce64f73f069bdd3e589a3302936c831903e5f7e5539.png)

الآن نحن نعرف كيف يتم تنفيذ RCE عبر إلغاء التسلسل، لكن من غير الممكن كتابة الكود بهذه الطريقة مباشرة في التطوير، لذا يتعلق الأمر بالبحث عن سلسلة الاستغلال. يتطلب ثغرة إلغاء التسلسل ثلاثة أشياء:

1. مدخل إلغاء التسلسل (source)
2. طريقة الهدف (sink)
3. سلسلة الاستغلال (gadget chain)

إذا نظرنا بعناية إلى نتائج الإخراج في الصورة أعلاه، نجد أنها لم تؤدِ فقط إلى تشغيل طريقة readObject، بل أيضًا إلى تشغيل toString()، والبناء بدون وسائط، وset، وget. لذا في عملية البحث الفعلية عن سلسلة الاستغلال، لا نحتاج فقط إلى التركيز على طريقة readObject().

والآن نحتاج إلى فهم **الانعكاس** (Reflection). لقد ذكرنا سابقًا مشكلة **تحويل النوع الإجباري**. في التطوير العملي، يتم معالجة المنطق في readObject، وعندما لا نعرف نوع البيانات المحدد للكائن المدخل، يتم استخدام الانعكاس لتحديد الاستدعاء. والانعكاس هو وسيلتنا المهمة للوصول إلى RCE.

## انعكاس Java

ما هو الانعكاس؟ كلمة "الانعكاس" تحتوي على مقطع "عكس"، لذا لشرح الانعكاس يجب أن نبدأ من "الانعكاس الإيجابي"، انظر إلى الكود. هذه هي فئة الكيان الخاصة بي.```java
package org.chabug.entity;

import java.io.IOException;

public class ReflectionClass {
    String name;

    public ReflectionClass(String name) {
        this.name = name;
    }

    public ReflectionClass() {
    }

    public String say() {
        return this.name;
    }

    private void evil(String cmd) {
        try {
            Runtime.getRuntime().exec(new String[]{"cmd","/c",cmd});
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return "ReflectionClass{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

الكتابة العادية```java package org.chabug.demo;

import org.chabug.entity.ReflectionClass;

public class ReflectionDemo { public static void main(String[] args) { ReflectionClass demo = new ReflectionClass(); demo.setName("hello"); System.out.println(demo.say()); // demo.evil("calc"); // 不能够调用private方法 } }

ببساطة، يتم إنشاء مثيل من `ReflectionClass` باستخدام `new`، ثم استدعاء أساليبه عبر هذا المثيل، وهذا ما يُسمى "الإسقاط المباشر". ولكن ماذا لو كنت لا تعرف اسم الفئة عند استخدام `new`؟ كيف تستدعي الأساليب المحمية بـ `private`؟ هنا يظهر دور الانعكاس (Reflection). انظر إلى مقطع الكود التالي```java
package org.chabug.demo;

import org.chabug.entity.ReflectionClass;

import java.lang.reflect.Method;

public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        // new
        Class<?> aClass = Class.forName("org.chabug.entity.ReflectionClass");
        Object o = aClass.newInstance();

        // setName("jack")
        Method setName = aClass.getDeclaredMethod("setName",String.class);
        setName.invoke(o, "jack");

        // say()
        Method say = aClass.getDeclaredMethod("say",null);
        Object o1 = say.invoke(o, null);
        System.out.println(o1);
تنزيل الأداة