View Javadoc
1   package com.jsql.util;
2   
3   import com.jsql.util.tampering.TamperingType;
4   import org.apache.commons.lang3.StringUtils;
5   import org.apache.logging.log4j.LogManager;
6   import org.apache.logging.log4j.Logger;
7   
8   import javax.script.Invocable;
9   import javax.script.ScriptEngine;
10  import javax.script.ScriptEngineManager;
11  import javax.script.ScriptException;
12  import java.util.regex.Pattern;
13  
14  public class TamperingUtil {
15  
16      private static final Logger LOGGER = LogManager.getRootLogger();
17  
18      public static final String TAG_OPENED = "<tampering>";
19      public static final String TAG_CLOSED = "</tampering>";
20  
21      private boolean isBase64 = false;
22      private boolean isVersionComment = false;
23      private boolean isFunctionComment = false;
24      private boolean isEqualToLike = false;
25      private boolean isRandomCase = false;
26      private boolean isHexToChar = false;
27      private boolean isStringToChar = false;
28      private boolean isQuoteToUtf8 = false;
29      private boolean isEval = false;
30      private boolean isSpaceToMultilineComment = false;
31      private boolean isSpaceToDashComment = false;
32      private boolean isSpaceToSharpComment = false;
33  
34      private String customTamper = null;
35  
36      private static final ScriptEngineManager SCRIPT_ENGINE_MANAGER = new ScriptEngineManager();
37  
38      private static String eval(String sqlQuery, String jsTampering) {
39          Object resultSqlTampered;
40          try {
41              if (StringUtils.isEmpty(jsTampering)) {
42                  throw new ScriptException("Tampering context is empty");
43              }
44  
45              ScriptEngine nashornEngine = TamperingUtil.SCRIPT_ENGINE_MANAGER.getEngineByName("nashorn");
46              nashornEngine.eval(jsTampering);
47  
48              var nashornInvocable = (Invocable) nashornEngine;
49              resultSqlTampered = nashornInvocable.invokeFunction("tampering", sqlQuery);
50  
51          } catch (ScriptException e) {
52              LOGGER.log(
53                  LogLevelUtil.CONSOLE_ERROR,
54                  String.format("Tampering context contains errors: %s", e.getMessage()),
55                  e
56              );
57              resultSqlTampered = sqlQuery;
58          } catch (NoSuchMethodException e) {
59              LOGGER.log(
60                  LogLevelUtil.CONSOLE_ERROR,
61                  String.format("Tampering context is not properly defined: %s", e.getMessage()),
62                  e
63              );
64              LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Minimal tampering context is: var tampering = function(sql) {return sql}");
65              resultSqlTampered = sqlQuery;
66          }
67          return resultSqlTampered.toString();
68      }
69  
70      public String tamper(String sqlQueryDefault) {
71          String lead;
72          String sqlQuery;
73          String trail;
74  
75          // Transform only SQL query without HTTP parameters and syntax changed, like p=1'+[sql]
76          String regexToMatchTamperTags = String.format("(?s)(.*%s)(.*)(%s.*)", TamperingUtil.TAG_OPENED, TamperingUtil.TAG_CLOSED);
77          var matcherSql = Pattern.compile(regexToMatchTamperTags).matcher(sqlQueryDefault);
78  
79          if (matcherSql.find()) {
80              lead = matcherSql.group(1);
81              sqlQuery = matcherSql.group(2);
82              trail = matcherSql.group(3);
83          } else {
84              return sqlQueryDefault;
85          }
86  
87          if (this.isEval) {
88              sqlQuery = TamperingUtil.eval(sqlQuery, this.customTamper);
89          }
90  
91          sqlQuery = this.transform(sqlQuery, this.isHexToChar, TamperingType.HEX_TO_CHAR);
92          sqlQuery = this.transform(sqlQuery, this.isStringToChar, TamperingType.STRING_TO_CHAR);
93          sqlQuery = this.transform(sqlQuery, this.isFunctionComment, TamperingType.COMMENT_TO_METHOD_SIGNATURE);
94          sqlQuery = this.transform(sqlQuery, this.isVersionComment, TamperingType.VERSIONED_COMMENT_TO_METHOD_SIGNATURE);
95          sqlQuery = this.transform(sqlQuery, this.isRandomCase, TamperingType.RANDOM_CASE);
96          sqlQuery = this.transform(sqlQuery, this.isEqualToLike, TamperingType.EQUAL_TO_LIKE);
97  
98          sqlQuery = lead + sqlQuery + trail;
99  
100         String regexToremoveTamperTags = String.format("(?i)%s|%s", TamperingUtil.TAG_OPENED, TamperingUtil.TAG_CLOSED);
101         sqlQuery = sqlQuery.replaceAll(regexToremoveTamperTags, StringUtils.EMPTY);
102 
103         // Empty when checking character insertion
104         if (StringUtils.isEmpty(sqlQuery)) {
105             return StringUtils.EMPTY;
106         }
107 
108         // Transform all query, SQL and HTTP
109 
110         // Dependency to: EQUAL_TO_LIKE
111         if (this.isSpaceToDashComment) {
112             sqlQuery = TamperingUtil.eval(sqlQuery, TamperingType.SPACE_TO_DASH_COMMENT.instance().getJavascript());
113         } else if (this.isSpaceToMultilineComment) {
114             sqlQuery = TamperingUtil.eval(sqlQuery, TamperingType.SPACE_TO_MULTILINE_COMMENT.instance().getJavascript());
115         } else if (this.isSpaceToSharpComment) {
116             sqlQuery = TamperingUtil.eval(sqlQuery, TamperingType.SPACE_TO_SHARP_COMMENT.instance().getJavascript());
117         }
118 
119         sqlQuery = this.transform(sqlQuery, this.isBase64, TamperingType.BASE64);
120         sqlQuery = this.transform(sqlQuery, this.isQuoteToUtf8, TamperingType.QUOTE_TO_UTF8);  // char insertion included
121         return sqlQuery;
122     }
123 
124     private String transform(String sqlQuery, boolean shouldApply, TamperingType tamperingType) {
125         if (shouldApply) {
126             return TamperingUtil.eval(sqlQuery, tamperingType.instance().getJavascript());
127         }
128         return sqlQuery;
129     }
130 
131 
132     // Builder
133 
134     public TamperingUtil withBase64() {
135         this.isBase64 = true;
136         return this;
137     }
138 
139     public TamperingUtil withVersionComment() {
140         this.isVersionComment = true;
141         return this;
142     }
143 
144     public TamperingUtil withFunctionComment() {
145         this.isFunctionComment = true;
146         return this;
147     }
148 
149     public TamperingUtil withEqualToLike() {
150         this.isEqualToLike = true;
151         return this;
152     }
153 
154     public TamperingUtil withRandomCase() {
155         this.isRandomCase = true;
156         return this;
157     }
158 
159     public TamperingUtil withHexToChar() {
160         this.isHexToChar = true;
161         return this;
162     }
163 
164     public TamperingUtil withStringToChar() {
165         this.isStringToChar = true;
166         return this;
167     }
168 
169     public TamperingUtil withQuoteToUtf8() {
170         this.isQuoteToUtf8 = true;
171         return this;
172     }
173 
174     public TamperingUtil withEval() {
175         this.isEval = true;
176         return this;
177     }
178 
179     public TamperingUtil withSpaceToMultilineComment() {
180         this.isSpaceToMultilineComment = true;
181         return this;
182     }
183 
184     public TamperingUtil withSpaceToDashComment() {
185         this.isSpaceToDashComment = true;
186         return this;
187     }
188 
189     public TamperingUtil withSpaceToSharpComment() {
190         this.isSpaceToSharpComment = true;
191         return this;
192     }
193 
194     
195     // Getter and setter
196 
197     public String getCustomTamper() {
198         return this.customTamper;
199     }
200 
201     public void setCustomTamper(String customTamper) {
202         this.customTamper = customTamper;
203     }
204 
205     public TamperingUtil withBase64(boolean selected) {
206         this.isBase64 = selected;
207         return this;
208     }
209 
210     public TamperingUtil withEqualToLike(boolean selected) {
211         this.isEqualToLike = selected;
212         return this;
213     }
214 
215     public TamperingUtil withEval(boolean selected) {
216         this.isEval = selected;
217         return this;
218     }
219 
220     public TamperingUtil withFunctionComment(boolean selected) {
221         this.isFunctionComment = selected;
222         return this;
223     }
224 
225     public TamperingUtil withHexToChar(boolean selected) {
226         this.isHexToChar = selected;
227         return this;
228     }
229 
230     public TamperingUtil withQuoteToUtf8(boolean selected) {
231         this.isQuoteToUtf8 = selected;
232         return this;
233     }
234 
235     public TamperingUtil withRandomCase(boolean selected) {
236         this.isRandomCase = selected;
237         return this;
238     }
239 
240     public TamperingUtil withSpaceToDashComment(boolean selected) {
241         this.isSpaceToDashComment = selected;
242         return this;
243     }
244 
245     public TamperingUtil withSpaceToMultilineComment(boolean selected) {
246         this.isSpaceToMultilineComment = selected;
247         return this;
248     }
249 
250     public TamperingUtil withSpaceToSharpComment(boolean selected) {
251         this.isSpaceToSharpComment = selected;
252         return this;
253     }
254 
255     public TamperingUtil withStringToChar(boolean selected) {
256         this.isStringToChar = selected;
257         return this;
258     }
259 
260     public TamperingUtil withVersionComment(boolean selected) {
261         this.isVersionComment = selected;
262         return this;
263     }
264 }