wafrift_encoding/tamper/
builtins.rs1use super::TamperStrategy;
4
5pub struct UrlEncodeTamper;
7
8impl TamperStrategy for UrlEncodeTamper {
9 fn name(&self) -> &'static str {
10 "url_encode"
11 }
12
13 fn description(&self) -> &'static str {
14 "Standard URL encoding (%XX for each byte)"
15 }
16
17 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
18 crate::encoding::url::url_encode(payload)
19 }
20
21 fn aggressiveness(&self) -> f64 {
22 0.15
23 }
24}
25
26pub struct DoubleUrlEncodeTamper;
28
29impl TamperStrategy for DoubleUrlEncodeTamper {
30 fn name(&self) -> &'static str {
31 "double_url_encode"
32 }
33
34 fn description(&self) -> &'static str {
35 "Double URL encoding (%25XX) — bypasses WAFs that decode once"
36 }
37
38 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
39 crate::encoding::url::double_url_encode(payload)
40 }
41
42 fn aggressiveness(&self) -> f64 {
43 0.4
44 }
45}
46
47pub struct UnicodeEscapeTamper;
49
50impl TamperStrategy for UnicodeEscapeTamper {
51 fn name(&self) -> &'static str {
52 "unicode_escape"
53 }
54
55 fn description(&self) -> &'static str {
56 "Unicode escape sequences (\\uXXXX)"
57 }
58
59 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
60 crate::encoding::unicode::unicode_encode(payload)
61 }
62
63 fn aggressiveness(&self) -> f64 {
64 0.5
65 }
66}
67
68pub struct HtmlEntityTamper;
70
71impl TamperStrategy for HtmlEntityTamper {
72 fn name(&self) -> &'static str {
73 "html_entity"
74 }
75
76 fn description(&self) -> &'static str {
77 "HTML entity encoding (&#xXX;)"
78 }
79
80 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
81 crate::encoding::unicode::html_entity_encode(payload)
82 }
83
84 fn aggressiveness(&self) -> f64 {
85 0.3
86 }
87}
88
89pub struct CaseAlternationTamper;
91
92impl TamperStrategy for CaseAlternationTamper {
93 fn name(&self) -> &'static str {
94 "case_alternation"
95 }
96
97 fn description(&self) -> &'static str {
98 "Alternating upper/lower case (SeLeCt)"
99 }
100
101 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
102 crate::encoding::keyword::case_alternate(payload)
103 }
104
105 fn aggressiveness(&self) -> f64 {
106 0.1
107 }
108}
109
110pub struct RandomCaseTamper;
112
113impl TamperStrategy for RandomCaseTamper {
114 fn name(&self) -> &'static str {
115 "random_case"
116 }
117
118 fn description(&self) -> &'static str {
119 "Random mixed case"
120 }
121
122 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
123 crate::encoding::keyword::random_case_alternate(payload)
124 }
125
126 fn aggressiveness(&self) -> f64 {
127 0.12
128 }
129}
130
131pub struct WhitespaceInsertionTamper;
133
134impl TamperStrategy for WhitespaceInsertionTamper {
135 fn name(&self) -> &'static str {
136 "whitespace_insertion"
137 }
138
139 fn description(&self) -> &'static str {
140 "Replace spaces with tabs"
141 }
142
143 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
144 crate::encoding::keyword::whitespace_insert(payload)
145 }
146
147 fn aggressiveness(&self) -> f64 {
148 0.2
149 }
150}
151
152pub struct SqlCommentTamper;
154
155impl TamperStrategy for SqlCommentTamper {
156 fn name(&self) -> &'static str {
157 "sql_comment"
158 }
159
160 fn description(&self) -> &'static str {
161 "Replace spaces with SQL comments (/**/)"
162 }
163
164 fn tamper(&self, payload: &str, context: Option<&str>) -> String {
165 let _ = context;
166 crate::encoding::keyword::sql_comment_insert(payload)
167 }
168
169 fn aggressiveness(&self) -> f64 {
170 0.25
171 }
172}
173
174pub struct NullByteTamper;
176
177impl TamperStrategy for NullByteTamper {
178 fn name(&self) -> &'static str {
179 "null_byte"
180 }
181
182 fn description(&self) -> &'static str {
183 "Null byte injection (%00 or %00.jpg)"
184 }
185
186 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
187 crate::encoding::structural::null_byte_inject(payload)
188 }
189
190 fn aggressiveness(&self) -> f64 {
191 0.6
192 }
193}
194
195pub struct OverlongUtf8Tamper;
197
198impl TamperStrategy for OverlongUtf8Tamper {
199 fn name(&self) -> &'static str {
200 "overlong_utf8"
201 }
202
203 fn description(&self) -> &'static str {
204 "Overlong UTF-8 encoding for ASCII non-alphanumeric"
205 }
206
207 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
208 crate::encoding::structural::overlong_utf8(payload)
209 }
210
211 fn aggressiveness(&self) -> f64 {
212 0.8
213 }
214}
215
216pub struct Base64Tamper;
218
219impl TamperStrategy for Base64Tamper {
220 fn name(&self) -> &'static str {
221 "base64"
222 }
223
224 fn description(&self) -> &'static str {
225 "Base64 encoding"
226 }
227
228 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
229 crate::encoding::structural::base64_encode(payload)
230 }
231
232 fn aggressiveness(&self) -> f64 {
233 0.75
234 }
235}
236
237pub struct HexEncodeTamper;
239
240impl TamperStrategy for HexEncodeTamper {
241 fn name(&self) -> &'static str {
242 "hex_encode"
243 }
244
245 fn description(&self) -> &'static str {
246 "Hexadecimal encoding"
247 }
248
249 fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
250 crate::encoding::structural::hex_encode(payload)
251 }
252
253 fn aggressiveness(&self) -> f64 {
254 0.85
255 }
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 #[test]
263 fn url_encode_tamper() {
264 let strategy = UrlEncodeTamper;
265 assert_eq!(strategy.tamper("A<", None), "A%3C");
266 assert_eq!(strategy.aggressiveness(), 0.15);
267 }
268
269 #[test]
270 fn double_url_encode_tamper() {
271 let strategy = DoubleUrlEncodeTamper;
272 assert_eq!(strategy.tamper("A", None), "%2541");
273 assert!(strategy.tamper("%20", None).contains("%25"));
274 }
275
276 #[test]
277 fn case_alternation_tamper() {
278 let strategy = CaseAlternationTamper;
279 assert_eq!(strategy.tamper("select", None), "SeLeCt");
280 }
281
282 #[test]
283 fn random_case_tamper() {
284 let strategy = RandomCaseTamper;
285 let result = strategy.tamper("select", None);
286 assert_eq!(result.to_ascii_lowercase(), "select");
287 }
288
289 #[test]
290 fn null_byte_with_extension() {
291 let strategy = NullByteTamper;
292 assert_eq!(strategy.tamper("file.php", None), "file.php%00.jpg");
293 }
294
295 #[test]
296 fn null_byte_without_extension() {
297 let strategy = NullByteTamper;
298 assert_eq!(strategy.tamper("payload", None), "payload%00");
299 }
300
301 #[test]
302 fn sql_comment_insertion() {
303 let strategy = SqlCommentTamper;
304 let result = strategy.tamper("SELECT * FROM users", Some("sql"));
305 assert!(result.contains("/**/"));
306 assert_eq!(result, "SELECT/**/*/**/FROM/**/users");
307 }
308
309 #[test]
310 fn whitespace_insertion() {
311 let strategy = WhitespaceInsertionTamper;
312 let result = strategy.tamper("SELECT * FROM users", None);
313 assert!(result.contains('\t'));
314 assert_eq!(result, "SELECT\t*\tFROM\tusers");
315 }
316
317 #[test]
318 fn base64_tamper() {
319 let strategy = Base64Tamper;
320 assert_eq!(strategy.tamper("hello", None), "aGVsbG8=");
321 }
322
323 #[test]
324 fn hex_encode_tamper() {
325 let strategy = HexEncodeTamper;
326 assert_eq!(strategy.tamper("ABC", None), "414243");
327 }
328
329 #[test]
330 fn unicode_escape_tamper() {
331 let strategy = UnicodeEscapeTamper;
332 assert_eq!(strategy.tamper("AB", None), "\\u0041\\u0042");
333 }
334
335 #[test]
336 fn html_entity_tamper() {
337 let strategy = HtmlEntityTamper;
338 assert_eq!(strategy.tamper("<>", None), "<>");
339 }
340
341 #[test]
342 fn overlong_utf8_tamper() {
343 let strategy = OverlongUtf8Tamper;
344 let result = strategy.tamper("/", None);
345 assert!(result.contains("%C0"));
346 }
347}