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