From time to time pentesters have to deal with Java applications. These can be various servers, clients or just desktop programs. And sometimes it becomes necessary to patch such an application. Why do you need it? Each case of such a need is unique. For example:
- Sophisticated communication protocol between server and client. To send arbitrary requests - patchim;
- Zakhardkozheny settings. To change - patchim;
- To demonstrate the effects of problems like race condition - patchim.
Of course, in each case, you can solve the problem without resorting to modification of the application. But often this is the easiest and fastest way to achieve the desired result. In this article, we will describe how to quickly and easily change the functionality of a Java application.
Application
For the story we need an experimental application. Of course, we will write it ourselves. Its structure is shown in Figure 1.
picture 1')
As you can see, it is quite simple: two classes that run the application and draw the GUI. Here are their sources. 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
Classes are very simple. Main - creates a window. Window - prints text in 3 fields. He takes the text from our target classes, by the example of which we will consider methods of modification. How does the running application, see figure 2.
picture 2From the tools we need only JDK and JavaDecompiler. Getting down to the patch.
Level 1
Our application is a jar archive. To begin with, simply insert it into JavaDecompiler and get the source of the class of interest to us. Level1.java:
1 package com.mycompany.Targets; 2 3 public class Level1 4 { 5 public String getText() 6 { 7 return "Data"; 8 } 9 } 10
Great, now we copy this code into a text file with the extension "java". This is the easiest class to think of. Now we change this source as we wish. We replaced the return value with “My msg”. Next, execute the command:

As a result, we get the finished Level1.class. Then we just need to add it to our jar-archive. Let's do this with the following command:

Note that we have created a path identical to the name of the package in which our class is located, and put the binary there.
The result is in Figure 3.
picture 3Consider the case more difficult.
Level 2
We do the same thing and get the source. 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 }
In it, I will change the "Super" to "New". And try to compile:

It did not work, because the class has a link to another object from this package. But java is very friendly and allows you to specify when compiling any way where the classes are located. Those. you can simply execute the command:

As a result, we have a ready-made binary again. In the same way, we update the jar-archive and see the result in Figure 4:

figure 4Well, consider the last case, which will add a little more complexity.
Level 3
We decompile our class. 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 }
Here we add the line "-update-". As we can see right away, a third-party package has been added. And, if we try to collect, we get an error:

And again, java helps out with its friendliness. She can simply specify the path where the jar-archives of dependencies are located. This is done like this:

(yes, the indication of the class path is superfluous here, since it is packed in the archive and lies in the same directory, but since this is not always the case, I still pointed it out)
And then everything is the same - the result in Figure 5.

Figure 5Total
As a result, we looked at examples of how to quickly and easily modify Java applications. Of course, we looked at the example of the jar-archive, but you understand that if the classes are not packed, then everything is much simpler?