View Javadoc
1   /*******************************************************************************
2    * Copyhacked (H) 2012-2025.
3    * This program and the accompanying materials
4    * are made available under no term at all, use it like
5    * you want, but share and discuss it
6    * every time possible with every body.
7    * 
8    * Contributors:
9    *      ron190 at ymail dot com - initial implementation
10   ******************************************************************************/
11  package com.jsql.view.swing.manager;
12  
13  import com.jsql.model.accessible.ExploitMode;
14  import com.jsql.model.exception.JSqlException;
15  import com.jsql.model.injection.vendor.model.Vendor;
16  import com.jsql.util.I18nUtil;
17  import com.jsql.util.LogLevelUtil;
18  import com.jsql.view.swing.manager.util.*;
19  import com.jsql.view.swing.text.JPasswordFieldPlaceholder;
20  import com.jsql.view.swing.text.JPopupTextField;
21  import com.jsql.view.swing.text.JTextFieldPlaceholder;
22  import com.jsql.view.swing.text.JToolTipI18n;
23  import com.jsql.view.swing.util.I18nViewUtil;
24  import com.jsql.view.swing.util.MediatorHelper;
25  import org.apache.commons.lang3.StringUtils;
26  import org.apache.logging.log4j.LogManager;
27  import org.apache.logging.log4j.Logger;
28  
29  import javax.swing.*;
30  import java.awt.*;
31  import java.awt.event.ActionEvent;
32  import java.awt.event.ActionListener;
33  import java.awt.event.ItemEvent;
34  import java.awt.event.ItemListener;
35  import java.io.File;
36  import java.net.URI;
37  import java.net.URISyntaxException;
38  import java.util.Arrays;
39  import java.util.List;
40  import java.util.Objects;
41  import java.util.concurrent.atomic.AtomicReference;
42  
43  /**
44   * Manager for uploading PHP SQL shell to the host and send queries.
45   */
46  public class ManagerExploit extends AbstractManagerList {
47  
48      private static final Logger LOGGER = LogManager.getRootLogger();
49      public static final String SHELL_URL_TOOLTIP = "SHELL_URL_TOOLTIP";
50  
51      private final AtomicReference<JTextField> username = new AtomicReference<>();
52      private final AtomicReference<JTextField> password = new AtomicReference<>();
53      private final AtomicReference<JTextField> netshare = new AtomicReference<>();
54      protected final JTextField textfieldUrlShell;
55  
56      public static final String EXPLOIT_UDF = "EXPLOIT_UDF";
57      public static final String EXPLOIT_WEB = "EXPLOIT_WEB";
58      public static final String EXPLOIT_SQL = "EXPLOIT_SQL";
59      public static final String EXPLOIT_UPLOAD = "EXPLOIT_UPLOAD";
60  
61      private final JComboBox<Object> comboBoxExploitTypes = new JComboBox<>(new Object[]{
62          new ModelItemType(ManagerExploit.EXPLOIT_UDF, "EXPLOIT_UDF_TOOLTIP"),
63          ComboBoxMethodRenderer.SEPARATOR,
64          new ModelItemType(ManagerExploit.EXPLOIT_WEB, "EXPLOIT_WEB_TOOLTIP"),
65          new ModelItemType(ManagerExploit.EXPLOIT_SQL, "EXPLOIT_SQL_TOOLTIP"),
66          new ModelItemType(ManagerExploit.EXPLOIT_UPLOAD, "EXPLOIT_UPLOAD_TOOLTIP"),
67      });
68  
69      private final JComboBox<Object> comboBoxExploitModes = new JComboBox<>(new Object[]{
70          ExploitMode.AUTO,
71          ComboBoxMethodRenderer.SEPARATOR,
72          ExploitMode.QUERY_BODY,
73          ExploitMode.TEMP_TABLE,
74          ComboBoxMethodRenderer.SEPARATOR,
75          ExploitMode.NETSHARE
76      });
77  
78      public ManagerExploit() {
79          super("swing/list/payload.txt");
80  
81          var tooltipShellUrl = new AtomicReference<>(new JToolTipI18n(I18nUtil.valueByKey(ManagerExploit.SHELL_URL_TOOLTIP)));
82          var placeholderResult = new JTextFieldPlaceholder(I18nUtil.valueByKey("SHELL_URL_LABEL")) {
83              @Override
84              public JToolTip createToolTip() {
85                  return tooltipShellUrl.get();
86              }
87          };
88          this.textfieldUrlShell = new JPopupTextField(placeholderResult).getProxy();
89          I18nViewUtil.addComponentForKey("SHELL_URL_LABEL", this.textfieldUrlShell);
90          I18nViewUtil.addComponentForKey(ManagerExploit.SHELL_URL_TOOLTIP, tooltipShellUrl.get());
91          this.textfieldUrlShell.setToolTipText(I18nUtil.valueByKey(ManagerExploit.SHELL_URL_TOOLTIP));
92  
93          this.buildRunButton("SHELL_RUN_BUTTON_LABEL", "SHELL_RUN_BUTTON_TOOLTIP");
94          this.run.setEnabled(false);
95          this.buildPrivilege();
96  
97          var southPanel = new JPanel();
98          southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.Y_AXIS));
99          southPanel.add(this.textfieldUrlShell);
100         southPanel.add(this.lastLine);
101         this.add(southPanel, BorderLayout.SOUTH);
102 
103         var userPassPanel = new JPanel();
104         var groupLayout = new GroupLayout(userPassPanel);
105         userPassPanel.setLayout(groupLayout);
106 
107         this.run.addActionListener(new ActionExploit(this.comboBoxExploitTypes));
108 
109         Arrays.asList(
110             new ModelExploit(this.netshare, "EXPLOIT_NETSHARE_LABEL", "EXPLOIT_NETSHARE_TOOLTIP"),
111             new ModelExploit(this.username, "SQL_SHELL_USERNAME_LABEL", "SQL_SHELL_USERNAME_TOOLTIP"),
112             new ModelExploit(this.password, "SQL_SHELL_PASSWORD_LABEL", "SQL_SHELL_PASSWORD_TOOLTIP", true)
113         ).forEach(model -> {
114             var tooltip = new AtomicReference<>(new JToolTipI18n(I18nUtil.valueByKey(model.tooltipI18n)));
115             if (model.isPassword) {
116                 model.textfield.set(new JPopupTextField(new JPasswordFieldPlaceholder(I18nUtil.valueByKey(model.labelI18n)) {
117                     @Override
118                     public JToolTip createToolTip() {
119                         return tooltip.get();
120                     }
121                 }).getProxy());
122             } else {
123                 model.textfield.set(new JPopupTextField(new JTextFieldPlaceholder(I18nUtil.valueByKey(model.labelI18n)) {
124                     @Override
125                     public JToolTip createToolTip() {
126                         return tooltip.get();
127                     }
128                 }).getProxy());
129             }
130             I18nViewUtil.addComponentForKey(model.labelI18n, model.textfield.get());
131             I18nViewUtil.addComponentForKey(model.tooltipI18n, tooltip.get());
132             model.textfield.get().setToolTipText(I18nUtil.valueByKey(model.tooltipI18n));
133         });
134 
135         Arrays.asList(this.username.get(), this.password.get(), this.scrollListPaths, this.textfieldUrlShell, this.netshare.get())
136         .forEach(component -> component.setVisible(false));
137 
138         this.comboBoxExploitTypes.setRenderer(new ComboBoxTypeRenderer());
139         this.comboBoxExploitTypes.addActionListener(new SeparatorListener(this.comboBoxExploitTypes));
140         this.comboBoxExploitTypes.addItemListener(this.getTypesItemListener());
141         this.comboBoxExploitModes.addItemListener(this.getModesItemListener());
142 
143         this.comboBoxExploitModes.setRenderer(new ComboBoxMethodRenderer());
144         this.comboBoxExploitModes.addActionListener(new SeparatorListener(this.comboBoxExploitModes));
145         var labelUsing = new JLabel("via");
146         labelUsing.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
147         groupLayout.setHorizontalGroup(
148             groupLayout
149             .createParallelGroup()
150             .addGroup(
151                 groupLayout
152                 .createSequentialGroup()
153                 .addComponent(this.comboBoxExploitTypes)
154                 .addComponent(labelUsing, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
155                 .addComponent(this.comboBoxExploitModes, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
156             )
157             .addGroup(
158                 groupLayout.createParallelGroup()
159                 .addComponent(this.netshare.get())
160                 .addComponent(this.username.get())
161                 .addComponent(this.password.get())
162             )
163         );
164 
165         groupLayout.setVerticalGroup(
166             groupLayout
167             .createSequentialGroup()
168             .addGroup(
169                 groupLayout
170                 .createParallelGroup(GroupLayout.Alignment.BASELINE)
171                 .addComponent(this.comboBoxExploitTypes)
172                 .addComponent(labelUsing)
173                 .addComponent(this.comboBoxExploitModes)
174             )
175             .addGroup(
176                 groupLayout
177                 .createParallelGroup()
178                 .addComponent(this.netshare.get())
179             )
180             .addGroup(
181                 groupLayout
182                 .createParallelGroup()
183                 .addComponent(this.username.get())
184             )
185             .addGroup(
186                 groupLayout
187                 .createParallelGroup()
188                 .addComponent(this.password.get())
189             )
190         );
191         
192         this.add(userPassPanel, BorderLayout.NORTH);
193     }
194 
195     private ItemListener getModesItemListener() {
196         return itemEvent -> {
197             if (itemEvent.getStateChange() == ItemEvent.SELECTED && itemEvent.getItem() instanceof ExploitMode) {
198                 ExploitMode selectedItem = (ExploitMode) itemEvent.getItem();
199                 this.netshare.get().setVisible(false);
200                 if (selectedItem.equals(ExploitMode.NETSHARE)) {
201                     this.netshare.get().setVisible(true);
202                 }
203                 this.updateUI();  // required to adapt panel
204             }
205         };
206     }
207 
208     private ItemListener getTypesItemListener() {
209         return itemEvent -> {
210             if (itemEvent.getStateChange() != ItemEvent.SELECTED || itemEvent.getItem() == ComboBoxMethodRenderer.SEPARATOR) {
211                 return;
212             }
213             Arrays.asList(
214                 this.username.get(), this.password.get(), this.scrollListPaths, this.textfieldUrlShell
215             ).forEach(component -> component.setVisible(false));
216             ModelItemType selectedItem = (ModelItemType) itemEvent.getItem();
217             if (!ManagerExploit.EXPLOIT_UDF.equals(selectedItem.getKeyLabel())) {
218                 this.scrollListPaths.setVisible(true);
219                 this.textfieldUrlShell.setVisible(true);
220                 if (ManagerExploit.EXPLOIT_SQL.equals(selectedItem.getKeyLabel())) {
221                     this.username.get().setVisible(true);
222                     this.password.get().setVisible(true);
223                 }
224             }
225             this.updateUI();  // required to adapt panel
226         };
227     }
228 
229     protected class ActionExploit implements ActionListener {
230         private final JComboBox<Object> comboBoxExploitTypes;
231 
232         public ActionExploit(JComboBox<Object> comboBoxExploitTypes) {
233             this.comboBoxExploitTypes = comboBoxExploitTypes;
234         }
235 
236         @Override
237         public void actionPerformed(ActionEvent evt) {
238             var modelSelectItem = (ModelItemType) this.comboBoxExploitTypes.getSelectedItem();
239             var labelSelectItem = Objects.requireNonNull(modelSelectItem).getKeyLabel();
240             if (!ManagerExploit.isValid(labelSelectItem)) {
241                 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Currently unsupported for [{}], contribute and share exploit method on GitHub to improve the app", MediatorHelper.model().getMediatorVendor().getVendor());
242                 return;
243             }
244             if (ManagerExploit.EXPLOIT_UDF.equals(labelSelectItem)) {
245                 new SwingWorker<>() {
246                     @Override
247                     protected Object doInBackground() { Thread.currentThread().setName("SwingWorkerExploit");
248                         ActionExploit.this.start(null, null, null);
249                         return null;
250                     }
251                 }.execute();
252                 return;
253             }
254             if (
255                 ManagerExploit.EXPLOIT_SQL.equals(labelSelectItem)
256                 && (ManagerExploit.this.password.get().getText().isEmpty() || ManagerExploit.this.username.get().getText().isEmpty())
257             ) {
258                 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Missing credentials (tips: search and read file containing hardcoded credentials)");
259                 return;
260             }
261             if (ManagerExploit.this.listPaths.getSelectedValuesList().isEmpty()) {
262                 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Select at least one directory in the list");
263                 return;
264             }
265 
266             String urlShell = this.validateAndNormalizeUrlShell();
267             if (urlShell == null) {
268                 return;
269             }
270             AtomicReference<File> fileToUpload = new AtomicReference<>();
271             if (this.validateFileSelection(labelSelectItem, fileToUpload)) {
272                 return;
273             }
274 
275             new SwingWorker<>() {
276                 @Override
277                 protected Object doInBackground() { Thread.currentThread().setName("SwingWorkerExploitNonUdf");
278                     ManagerExploit.this.horizontalGlue.setVisible(false);
279                     ManagerExploit.this.progressBar.setVisible(true);
280                     ManagerExploit.this.listPaths.getSelectedValuesList().forEach(pathExploit -> {
281                         LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, String.format("Checking path [%s]...", pathExploit));
282                         ActionExploit.this.start(pathExploit.toString(), urlShell, fileToUpload.get());
283                     });
284                     ManagerExploit.this.endProcess();
285                     return null;
286                 }
287             }.execute();
288         }
289 
290         private boolean validateFileSelection(String labelSelectItem, AtomicReference<File> fileToUpload) {
291             if (ManagerExploit.EXPLOIT_UPLOAD.equals(labelSelectItem)) {
292                 fileToUpload.set(ManagerExploit.chooseFile());
293                 if (fileToUpload.get() == null) {
294                     LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Missing file, please select a file");
295                     return true;
296                 }
297             }
298             return false;
299         }
300 
301         private String validateAndNormalizeUrlShell() {
302             String urlShell = ManagerExploit.this.textfieldUrlShell.getText();
303             if (!urlShell.isEmpty() && !urlShell.matches("(?i)^https?://.*")) {
304                 if (!urlShell.matches("(?i)^\\w+://.*")) {
305                     LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Undefined shell URL protocol, forcing to [https://]");
306                     urlShell = "https://"+ urlShell;
307                 } else {
308                     LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Unknown URL protocol");
309                     return null;
310                 }
311             }
312             if (StringUtils.isNotEmpty(urlShell)) {
313                 try {
314                     new URI(urlShell);
315                 } catch (URISyntaxException e) {
316                     LOGGER.log(LogLevelUtil.CONSOLE_ERROR, String.format("Incorrect URL: %s", e.getMessage()));
317                     return null;
318                 }
319             }
320             return urlShell;
321         }
322 
323         private void start(String pathExploit, String urlShellFinal, File fileToUpload) {
324             try {
325                 ManagerExploit.this.createPayload(pathExploit, urlShellFinal, fileToUpload);
326             } catch (JSqlException | IllegalArgumentException e) {
327                 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, String.format("Payload creation failure: %s", e.getMessage()));
328             }
329         }
330     }
331 
332     private static boolean isValid(String labelSelectItem) {
333         return
334             ManagerExploit.EXPLOIT_UDF.equals(labelSelectItem) && Arrays.asList(
335                 MediatorHelper.model().getMediatorVendor().getSqlite(),
336                 MediatorHelper.model().getMediatorVendor().getMysql(),
337                 MediatorHelper.model().getMediatorVendor().getPostgres(),
338                 MediatorHelper.model().getMediatorVendor().getH2()
339             ).contains(MediatorHelper.model().getMediatorVendor().getVendor())
340             || Arrays.asList(ManagerExploit.EXPLOIT_WEB, ManagerExploit.EXPLOIT_UPLOAD).contains(labelSelectItem) && Arrays.asList(
341                 MediatorHelper.model().getMediatorVendor().getDerby(),
342                 MediatorHelper.model().getMediatorVendor().getHsqldb(),
343                 MediatorHelper.model().getMediatorVendor().getH2(),
344                 MediatorHelper.model().getMediatorVendor().getSqlite(),
345                 MediatorHelper.model().getMediatorVendor().getMysql(),
346                 MediatorHelper.model().getMediatorVendor().getPostgres()
347             ).contains(MediatorHelper.model().getMediatorVendor().getVendor())
348             || List.of(ManagerExploit.EXPLOIT_SQL).contains(labelSelectItem) && Arrays.asList(
349                 MediatorHelper.model().getMediatorVendor().getMysql(),
350                 MediatorHelper.model().getMediatorVendor().getPostgres()
351             ).contains(MediatorHelper.model().getMediatorVendor().getVendor());
352     }
353 
354     private static File chooseFile() {
355         var filechooser = new JFileChooser(MediatorHelper.model().getMediatorUtils().getPreferencesUtil().getPathFile());
356         filechooser.setDialogTitle(I18nUtil.valueByKey("UPLOAD_DIALOG_TEXT"));
357         int returnVal = filechooser.showOpenDialog(MediatorHelper.frame());
358         if (returnVal == JFileChooser.APPROVE_OPTION) {
359             return filechooser.getSelectedFile();
360         }
361         return null;
362     }
363 
364     protected void createPayload(String pathExploit, String urlShell, File fileToUpload) throws JSqlException {
365         var exploitMethod = ExploitMode.forName(
366             Objects.requireNonNull(this.comboBoxExploitModes.getSelectedItem()).toString()
367         ).orElse(ExploitMode.AUTO);
368 
369         String pathExploitFixed = pathExploit;
370         if (pathExploitFixed != null && !pathExploitFixed.endsWith("/")) {
371             pathExploitFixed += "/";
372         }
373         String pathNetshare = this.netshare.get().getText();
374         if (exploitMethod == ExploitMode.NETSHARE && !pathNetshare.endsWith("\\")) {
375             pathNetshare += "\\";
376         }
377 
378         var modelItemType = (ModelItemType) Objects.requireNonNull(this.comboBoxExploitTypes.getSelectedItem());
379         var keyLabel = modelItemType.getKeyLabel();
380         var vendor = MediatorHelper.model().getMediatorVendor().getVendor();
381 
382         if (ManagerExploit.EXPLOIT_UDF.equals(keyLabel)) {
383             ManagerExploit.handleUdfExploit(vendor, pathNetshare, exploitMethod);
384         } else if (ManagerExploit.EXPLOIT_WEB.equals(keyLabel)) {
385             ManagerExploit.handleWebExploit(pathExploitFixed, urlShell, vendor, pathNetshare, exploitMethod);
386         } else if (ManagerExploit.EXPLOIT_SQL.equals(keyLabel)) {
387             this.handleSqlExploit(pathExploitFixed, urlShell, vendor, pathNetshare, exploitMethod);
388         } else if (ManagerExploit.EXPLOIT_UPLOAD.equals(keyLabel)) {
389             ManagerExploit.handleUploadExploit(pathExploitFixed, urlShell, fileToUpload, vendor, pathNetshare, exploitMethod);
390         }
391     }
392 
393     private static void handleUdfExploit(Vendor vendor, String pathNetshare, ExploitMode exploitMethod) throws JSqlException {
394         if (vendor == MediatorHelper.model().getMediatorVendor().getMysql()) {
395             MediatorHelper.model().getResourceAccess().getExploitMysql().createUdf(pathNetshare, exploitMethod);
396         } else if (vendor == MediatorHelper.model().getMediatorVendor().getPostgres()) {
397             MediatorHelper.model().getResourceAccess().getExploitPostgres().createUdf(null);
398         } else if (vendor == MediatorHelper.model().getMediatorVendor().getSqlite()) {
399             MediatorHelper.model().getResourceAccess().getExploitSqlite().createUdf();
400         } else if (vendor == MediatorHelper.model().getMediatorVendor().getH2()) {
401             MediatorHelper.model().getResourceAccess().getExploitH2().createUdf();
402         }
403     }
404 
405     private static void handleWebExploit(String pathExploit, String urlShell, Vendor vendor, String pathNetshare, ExploitMode exploitMethod) throws JSqlException {
406         if (vendor == MediatorHelper.model().getMediatorVendor().getMysql()) {
407             MediatorHelper.model().getResourceAccess().getExploitMysql().createWeb(pathExploit, urlShell, pathNetshare, exploitMethod);
408         } else if (vendor == MediatorHelper.model().getMediatorVendor().getPostgres()) {
409             MediatorHelper.model().getResourceAccess().getExploitPostgres().createWeb(pathExploit, urlShell);
410         } else if (vendor == MediatorHelper.model().getMediatorVendor().getSqlite()) {
411             MediatorHelper.model().getResourceAccess().getExploitSqlite().createWeb(pathExploit, urlShell);
412         } else if (vendor == MediatorHelper.model().getMediatorVendor().getHsqldb()) {
413             MediatorHelper.model().getResourceAccess().getExploitHsqldb().createWeb(pathExploit, urlShell);
414         } else if (vendor == MediatorHelper.model().getMediatorVendor().getH2()) {
415             MediatorHelper.model().getResourceAccess().getExploitH2().createWeb(pathExploit, urlShell);
416         } else if (vendor == MediatorHelper.model().getMediatorVendor().getDerby()) {
417             MediatorHelper.model().getResourceAccess().getExploitDerby().createWeb(pathExploit, urlShell);
418         }
419     }
420 
421     private void handleSqlExploit(String pathExploit, String urlShell, Vendor vendor, String pathNetshare, ExploitMode exploitMethod) throws JSqlException {
422         String login = this.username.get().getText();
423         String pass = this.password.get().getText();
424         if (vendor == MediatorHelper.model().getMediatorVendor().getMysql()) {
425             MediatorHelper.model().getResourceAccess().getExploitMysql().createSql(pathExploit, urlShell, pathNetshare, exploitMethod, login, pass);
426         } else if (vendor == MediatorHelper.model().getMediatorVendor().getPostgres()) {
427             MediatorHelper.model().getResourceAccess().getExploitPostgres().createSql(pathExploit, urlShell, login, pass);
428         }
429     }
430 
431     private static void handleUploadExploit(String pathExploit, String urlShell, File fileToUpload, Vendor vendor, String pathNetshare, ExploitMode exploitMethod) throws JSqlException {
432         if (vendor == MediatorHelper.model().getMediatorVendor().getMysql()) {
433             MediatorHelper.model().getResourceAccess().getExploitMysql().createUpload(pathExploit, urlShell, pathNetshare, exploitMethod, fileToUpload);
434         } else if (vendor == MediatorHelper.model().getMediatorVendor().getPostgres()) {
435             MediatorHelper.model().getResourceAccess().getExploitPostgres().createUpload(pathExploit, urlShell, fileToUpload);
436         } else if (vendor == MediatorHelper.model().getMediatorVendor().getSqlite()) {
437             MediatorHelper.model().getResourceAccess().getExploitSqlite().createUpload(pathExploit, urlShell, fileToUpload);
438         } else if (vendor == MediatorHelper.model().getMediatorVendor().getHsqldb()) {
439             MediatorHelper.model().getResourceAccess().getExploitHsqldb().createUpload(pathExploit, urlShell, fileToUpload);
440         } else if (vendor == MediatorHelper.model().getMediatorVendor().getH2()) {
441             MediatorHelper.model().getResourceAccess().getExploitH2().createUpload(pathExploit, urlShell, fileToUpload);
442         } else if (vendor == MediatorHelper.model().getMediatorVendor().getDerby()) {
443             MediatorHelper.model().getResourceAccess().getExploitDerby().createUpload(pathExploit, urlShell, fileToUpload);
444         }
445     }
446 }