Время от времени пентестерам приходится сталкиваться с Java-приложениями. Это могут быть различные серверы, клиенты или просто десктопные программы. И иногда возникает необходимость «пропатчить» такое приложение. Зачем это нужно? Каждый случай возникновения такой необходимости уникален. К примеру:
- Сложный протокол общения между сервером и клиентом. Чтобы отправлять произвольные запросы – патчим;
- Захардкожены настройки. Чтобы поменять – патчим;
- Для демонстрации последствий проблем типа «race condition» – патчим.
Конечно, в каждом случае можно решить проблему, не прибегая к модификации приложения. Но зачастую это самый простой и быстрый способ добиться необходимого результата. В этой статье мы расскажем, как легко и быстро изменить функционал в приложении на Java.
Application
Для рассказа нам понадобится подопытное приложение. Конечно, мы напишем его сами. Его структура на рисунке 1.
рисунок 1
Как видим, оно достаточно простое: два класса, которые запускают приложение и рисуют GUI. Вот их исходники. Main.java:
1 package com.mycompany; 2 3 public class Main 4 { 5 public static void main(String[] args) 6 { 7 javax.swing.SwingUtilities.invokeLater(new Runnable() 8 { 9 public void run() { 10 new Window(); 11 } 12 }); 13 } 14 } 15
Window.java 1 package com.mycompany; 2 3 import com.mycompany.Targets.*; 4 import javax.swing.*; 5 6 public class Window extends JFrame 7 { 8 private JPanel panel1; 9 private JLabel Level1Value; 10 private JLabel Level2Value; 11 private JLabel Level3Value; 12 13 public Window() 14 { 15 super("Simple example"); 16 17 Level1Value.setText(new Level1().getText()); 18 Level2Value.setText(new Level2().getText()); 19 Level3Value.setText(new Level3().getText()); 20 21 getContentPane().add(panel1); 22 23 setSize(300,100); 24 setLocationRelativeTo(null); 25 26 setVisible(true); 27 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 28 } 29 } 30
Классы очень простые. Main – создаёт окно Window. Window – печатает текст в 3 поля. Текст он берёт из наших целевых классов, на примере которых мы и будем рассматривать способы модификации. Как выглядит запущенное приложение, смотрите на рисунке 2.
рисунок 2
Из инструментов нам понадобится только JDK и JavaDecompiler. Приступаем к патчу.
Level 1
Наше приложение – это jar-архив. Для начала просто вставляем его в JavaDecompiler и получаем исходник интересующего нас класса. Level1.java:
1 package com.mycompany.Targets; 2 3 public class Level1 4 { 5 public String getText() 6 { 7 return "Data"; 8 } 9 } 10
Замечательно, теперь мы копируем этот код в текстовый файл с расширением «java». Это самый простой класс, который только можно придумать. Теперь меняем этот исходник, как пожелаем. Мы заменили возвращаемое значение на «My msg». Далее выполняем команду:
В результате мы получим готовый Level1.class. Затем нам нужно просто добавить его в наш jar-архив. Сделаем это следующей командой:
Обратим внимание, что мы создали путь, идентичный названию пакета, в котором расположен наш класс, и переложили туда бинарник.
Результат – на рисунке 3.
рисунок 3
Рассмотрим случай посложнее.
Level 2
Проделываем всё то же самое и получаем исходник. Level2.java:
1 package com.mycompany.Targets; 2 3 public class Level2 4 { 5 public String getText() 6 { 7 return "Super " + (new Level1().getText()); 8 } 9 }
В нём я поменяю «Super» на «New». И попытаюсь скомпилировать:
Не получилось, потому что в классе есть ссылка на другой объект из этого пакета. Но java очень дружелюбна и позволяет указать при компиляции любой путь, где лежат классы. Т.е. можно просто выполнить команду:
В результате, у нас опять готовый бинарник. Точно так же обновляем jar-архив и смотрим результат на рисунке 4:
рисунок 4
Ну и рассмотрим последний случай, в котором добавится ещё немного сложностей.
Level 3
Декомпилируем наш класс. Level3.java:
1 package com.mycompany.Targets; 2 3 import jd.core.CoreConstants; 4 5 public class Level3 6 { 7 public String getText() 8 { 9 return CoreConstants.class.getSimpleName() + " " 10 + (new Level2().getText()); 11 } 12 }
Здесь добавим строчку "-update-". Как мы можем сразу заметить, добавился сторонний пакет. И, если мы попытаемся собрать, получим ошибку:
И опять же, java выручает своей дружелюбностью. Ей можно просто указать путь, где лежат jar-архивы зависимостей. Делается это так:
(да, тут указание пути класса лишнее, т.к. он запакован в архив и лежит в той же директории, но т.к. это не всегда так, я его всё же указал)
И далее всё так же – результат на рисунке 5.
Рисунок 5
Итог
В итоге мы рассмотрели примеры, как просто и быстро можно модифицировать Java-приложения. Конечно, рассмотрели мы на примере jar-архива, но вы же понимаете, что если классы не запакованы, то всё гораздо проще?
ссылка на оригинал статьи https://habrahabr.ru/post/282934/
Добавить комментарий