Дырочка в модах с использованием ObjectInputStream

Дырочка в модах с использованием ObjectInputStream

1,111
47
420
Он есть. но пока что предоставить я его не могу.
И раз есть фиксы - могу поделиться наблюдением: в пейлоаде(бинарном, есс-но) замешана scala, какие-то импорты функций, которые я не понимаю, увы.
а
скала
прикольно
но на самом деле все еще интересно было б знать через какой класс это делается.
 

tox1cozZ

aka Agravaine
8,455
598
2,892
вот на этом этапе было б интересно знать как это вообще происходит, что челы умудряются запустить целый жарник. Если есть пейлоад в бинарном виде, мне было б очень интересно на него посмотреть честно говоря.
Ты отсылаешь с клиента свой класс, в котором определён метод readObject (если он существует, то ObjectInputStream вызывает его для чтения объекта).
А в этом методе ты уже волен делать вообще всё что хочешь, например, скачать откуда-то джарник и запустить процесс, который выкачает весь сервер или вообще запустит всякие трояны.
И не надо говорить про контейнеры, в майне их юзают единицы. Даже если они и есть, выдать нужным лицам опку и устроить армагеддон - уже огромная бяка.
1680965604716.png
 
1,111
47
420
отсылаешь с клиента свой класс
мне кажется ты не прав
ты не отсылаешь свой класс
ты отсылаешь только поля объекта
исходя из спеки OIS не загружает новый класс, а только ищет по имени

Раскидывая по фактам, вот что делает OOS исходя из спеки
Код:
The writeObject method is used to serialize an object to the stream. An object is serialized as follows:

     1.    If a subclass is overriding the implementation, call the writeObjectOverride method and return. Overriding the implementation is described at the end of this section.
     2.    If there is data in the block-data buffer, the data is written to the stream and the buffer is reset.
     3.    If the object is null, null is put in the stream and writeObject returns.
     4.    If the object has been previously replaced, as described in Step 8, write the handle of the replacement to the stream and writeObject returns.
     5.    If the object has already been written to the stream, its handle is written to the stream and writeObject returns.
     6.    If the object is a Class, the corresponding ObjectStreamClass is written to the stream, a handle is assigned for the class, and writeObject returns.
     7.    If the object is an ObjectStreamClass, a handle is assigned to the object, after which it is written to the stream using one of the class descriptor formats described in section 4.3. In versions 1.3 and later of the Java 2 SDK, Standard Edition, the writeClassDescriptor method is called to output the ObjectStreamClass if it represents a class that is not a dynamic proxy class, as determined by passing the associated Class object to the isProxyClass method of java.lang.reflect.Proxy. Afterwards, an annotation for the represented class is written: if the class is a dynamic proxy class, then the annotateProxyClass method is called; otherwise, the annotateClass method is called. The writeObject method then returns.
     8.    Process potential substitutions by the class of the object and/or by a subclass of ObjectInputStream.
     a.    If the class of an object is not an enum type and defines the appropriate writeReplace method, the method is called. Optionally, it can return a substitute object to be serialized.
     b.    Then, if enabled by calling the enableReplaceObject method, the replaceObject method is called to allow subclasses of ObjectOutputStream to substitute for the object being serialized. If the original object was replaced in the previous step, the replaceObject method is called with the replacement object.
         If the original object was replaced by either one or both steps above, the mapping from the original object to the replacement is recorded for later use in Step 4. Then, Steps 3 through 7 are repeated on the new object.
         If the replacement object is not one of the types covered by Steps 3 through 7, processing resumes using the replacement object at Step 10.
     9.    If the object is a java.lang.String, the string is written as length information followed by the contents of the string encoded in modified UTF-8. For details, refer to Section 6.2, "Stream Elements". A handle is assigned to the string, and writeObject returns.
     10.    If the object is an array, writeObject is called recursively to write the ObjectStreamClass of the array. The handle for the array is assigned. It is followed by the length of the array. Each element of the array is then written to the stream, after which writeObject returns.
     11.    If the object is an enum constant, the ObjectStreamClass for the enum type of the constant is written by recursively calling writeObject. It will appear in the stream only the first time it is referenced. A handle is assigned for the enum constant. Next, the value returned by the name method of the enum constant is written as a String object, as described in step 9. Note that if the same name string has appeared previously in the stream, a back reference to it will be written. The writeObject method then returns.
     12.    For regular objects, the ObjectStreamClass for the class of the object is written by recursively calling writeObject. It will appear in the stream only the first time it is referenced. A handle is assigned for the object.
     13.    The contents of the object are written to the stream.
     a.    If the object is serializable, the highest serializable class is located. For that class, and each derived class, that class's fields are written. If the class does not have a writeObject method, the defaultWriteObject method is called to write the serializable fields to the stream. If the class does have a writeObject method, it is called. It may call defaultWriteObject or putFields and writeFields to save the state of the object, and then it can write other information to the stream.
     b.    If the object is externalizable, the writeExternal method of the object is called.
     c.    If the object is neither serializable or externalizable, the NotSerializableException is thrown.

Здесь интересно читать только про ObjectStreamClass. Мало ли там как-то указывается URL откуда загружать класс.
Смотрим:
Код:
public class ObjectStreamClass
{
    public static ObjectStreamClass lookup(Class cl);

        public static ObjectStreamClass lookupAny(Class cl);

    public String getName();

    public Class forClass();

    public ObjectStreamField[] getFields();

    public long getSerialVersionUID();

    public String toString();
}

Здесь в целом интересен только Class forClass. На поверку оказывается, что туда класс может попасть только двумя способами: через резолв по имени либо когда жава генерирует прокси класс(это те которые для аннотаций). Таким образом мы, конечно, можем сгенерить любую проксю для любого класса, который Serializable, но, очевидно, нам это ничего не дает.

Таким образом мы не можем отправить произвольный класс на сервер и как следствие не можем отправить произовльный код.

Короче моя проблема с этим ресурсом, что он очень сильно вводит в заблуждение. Дырка не в OIS, в самом по себе, а в использовании OIS с каким то выпендристым классом. Фикс не фиксит проблему в целом, а только конкретно эти случаи. В целом в процессе просматривания кода я нашел, что с помощью SecurityManager можно что-то адекватное сделать и это можно было бы назвать фиксом.
 
Последнее редактирование:

tox1cozZ

aka Agravaine
8,455
598
2,892
Таким образом мы не можем отправить произвольный класс на сервер и как следствие не можем отправить произовльный код.
Всё отлично отправляется и через этот хак было сделано много пакостей )

Дырка не в OIS, в самом по себе, а в использовании OIS с каким то выпендристым классом
С любым пользовательским, который присылают с клиента.

Фикс не фиксит проблему в целом, а только конкретно эти случаи.
Мой фикс запрещает читать пакеты на невалидной стороне, что разом фиксит все моды, который вот так криво синхронизируют данные с помощью OIS.

 
Последнее редактирование:
1,111
47
420
Всё отлично отправляется и через этот хак было сделано много пакостей )
Выглядит как то голословно. Я верю, что можно найти комбинацию существующих классов на сервере, но я не верю, что можно отправить произвольный класс.

С любым пользовательским, который присылают с клиента.
Зачем ты мне врешь? Если прислать объект, класса которого нет на сервере, OIS выкинет ClassNotFoundException. Только что проверил.

Java Deserialization Tool Gadgetinspector First Glimpse

Author:Longofo@Knownsec 404 Team Time: September 4, 2019 Chinese version: https://paper.seebug.org/1034/
medium.com
medium.com
Окей вот это уже справедливо, но так ты сам себе и противоречишь. Эта штука литералли ищет способы заюзать существующие классы для загрузки эксплоитов. Я удовлетворен спасибо.
 
Последнее редактирование:
1,111
47
420
Мой фикс запрещает читать пакеты на невалидной стороне, что разом фиксит все моды, который вот так криво синхронизируют данные с помощью OIS.
Да. Факт. Крутой годный фикс этого кейса. Не костыльный и обстоятельный. Жаль это не фикс уязвимости OIS в целом. Ничего против не имею просто странно видеть в теме с уязвимостью OIS фикс не OIS, а этих модов. Было бы здорово, если б была приписка, что это фиксит конкретно эти моды.
 

will0376

Токсичная личность
2,076
55
584
что можно отправить произвольный класс.
Как я выше упоминал - в пейлоаде используется scala, махинациями которой как-то загружается .jar файл с хоста и выполняется метод, который находится в определённом классе в качестве точки входа...
 
1,111
47
420
Короче как я считаю как должно было бы выглядеть описание этого эксплоита:
1. Находим мод, который читает из OIS на сервере.
2. Как то добываем как можно больше классов, которые есть на сервере
3. Запускаем вот эту штуку на этих классах
4. Получаем на выходе путь из классов, которые нам нужно запаковать, чтобы вызвать Method#invoke
5. Пакуем эти классы и отправляем на сервер

Вот так красиво выглядит путь:

Код:
net/sf/jasperreports/charts/design/JRDesignPieDataset.readObject(Ljava/io/ObjectInputStream;)V (1)
  org/apache/commons/collections/FastArrayList.add(Ljava/lang/Object;)Z (0)
  java/util/ArrayList.clone()Ljava/lang/Object; (0)
  org/jfree/data/KeyToGroupMap.clone()Ljava/lang/Object; (0)
  org/jfree/data/KeyToGroupMap.clone(Ljava/lang/Object;)Ljava/lang/Object; (0)
  java/lang/reflect/Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; (0)


То есть правильно пакуя классы внезапно получится, что вызов readObject десериализуемого класса приведет нас к Method#invoke

Короче оч классно, что осветили эту тему, но было бы здорово чтоб описание было чуть более по фактам.
 

will0376

Токсичная личность
2,076
55
584
Просто наверно было б неплохо хотя б ссылочку на вот ето добавить.
А. Ну так-бы сразу) Добавил.
Да я не наезжаю, прости, если задело.
Та, никаких обид) всё по делу.
Просто поясняю - у меня не было и нет особо времени изучить всю подноготную, ища более глубокие подробности этой дырки.
 

tox1cozZ

aka Agravaine
8,455
598
2,892
Да. Факт. Крутой годный фикс этого кейса. Не костыльный и обстоятельный. Жаль это не фикс уязвимости OIS в целом. Ничего против не имею просто странно видеть в теме с уязвимостью OIS фикс не OIS, а этих модов. Было бы здорово, если б была приписка, что это фиксит конкретно эти моды.
Для дырок в модах этого достаточно)
Там еще кидали в теме тулзу для поиска юза OIS в модах, чтобы вообще вырезать всё нафиг.
 
7,099
324
1,510
Кст, никто не додумался зарепортить об этом авторам проблемных модов?
~~~
1691027231283.png
 
1,074
72
372
2
0
Вывод, сделайте списочек всех людей причастных к майн серверам (по сути профсоюз) и заприте их в 1 чате, берите бабки за вход туда, а там уже раскрывайте там инфу о уязвимостях, при этом баня за расглашение инфы оттуда. Получат выгоду как те кто раскрывает, так и те кто обслуживает/держит сервера.
 
Сверху