Skip to main content

wafrift_encoding/tamper/
builtins.rs

1//! Built-in tamper strategy implementations.
2
3use super::TamperStrategy;
4
5/// URL encoding tamper strategy.
6pub 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
26/// Double URL encoding tamper strategy.
27pub 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
47/// Unicode escape tamper strategy.
48pub 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
68/// HTML entity tamper strategy.
69pub 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
89/// Case alternation tamper strategy.
90pub 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
110/// Random case tamper strategy.
111pub 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
131/// Whitespace insertion tamper strategy.
132pub 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
152/// SQL comment tamper strategy.
153pub 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
174/// Null byte tamper strategy.
175pub 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            .unwrap_or_else(|_| payload.to_string())
189    }
190
191    fn aggressiveness(&self) -> f64 {
192        0.6
193    }
194}
195
196/// Overlong UTF-8 tamper strategy.
197pub struct OverlongUtf8Tamper;
198
199impl TamperStrategy for OverlongUtf8Tamper {
200    fn name(&self) -> &'static str {
201        "overlong_utf8"
202    }
203
204    fn description(&self) -> &'static str {
205        "Overlong UTF-8 encoding for ASCII non-alphanumeric"
206    }
207
208    fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
209        crate::encoding::structural::overlong_utf8(payload)
210            .unwrap_or_else(|_| payload.to_string())
211    }
212
213    fn aggressiveness(&self) -> f64 {
214        0.8
215    }
216}
217
218/// Base64 tamper strategy.
219pub struct Base64Tamper;
220
221impl TamperStrategy for Base64Tamper {
222    fn name(&self) -> &'static str {
223        "base64"
224    }
225
226    fn description(&self) -> &'static str {
227        "Base64 encoding"
228    }
229
230    fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
231        crate::encoding::structural::base64_encode(payload)
232    }
233
234    fn aggressiveness(&self) -> f64 {
235        0.75
236    }
237}
238
239/// Hex encoding tamper strategy.
240pub struct HexEncodeTamper;
241
242impl TamperStrategy for HexEncodeTamper {
243    fn name(&self) -> &'static str {
244        "hex_encode"
245    }
246
247    fn description(&self) -> &'static str {
248        "Hexadecimal encoding"
249    }
250
251    fn tamper(&self, payload: &str, _context: Option<&str>) -> String {
252        crate::encoding::structural::hex_encode(payload)
253    }
254
255    fn aggressiveness(&self) -> f64 {
256        0.85
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    use super::*;
263
264    #[test]
265    fn url_encode_tamper() {
266        let strategy = UrlEncodeTamper;
267        assert_eq!(strategy.tamper("A<", None), "A%3C");
268        assert_eq!(strategy.aggressiveness(), 0.15);
269    }
270
271    #[test]
272    fn double_url_encode_tamper() {
273        let strategy = DoubleUrlEncodeTamper;
274        assert_eq!(strategy.tamper("A", None), "%2541");
275        assert!(strategy.tamper("%20", None).contains("%25"));
276    }
277
278    #[test]
279    fn case_alternation_tamper() {
280        let strategy = CaseAlternationTamper;
281        assert_eq!(strategy.tamper("select", None), "SeLeCt");
282    }
283
284    #[test]
285    fn random_case_tamper() {
286        let strategy = RandomCaseTamper;
287        let result = strategy.tamper("select", None);
288        assert_eq!(result.to_ascii_lowercase(), "select");
289    }
290
291    #[test]
292    fn null_byte_with_extension() {
293        let strategy = NullByteTamper;
294        assert_eq!(strategy.tamper("file.php", None), "file.php%00.jpg");
295    }
296
297    #[test]
298    fn null_byte_without_extension() {
299        let strategy = NullByteTamper;
300        assert_eq!(strategy.tamper("payload", None), "payload%00");
301    }
302
303    #[test]
304    fn sql_comment_insertion() {
305        let strategy = SqlCommentTamper;
306        let result = strategy.tamper("SELECT * FROM users", Some("sql"));
307        assert!(result.contains("/**/"));
308        assert_eq!(result, "SELECT/**/*/**/FROM/**/users");
309    }
310
311    #[test]
312    fn whitespace_insertion() {
313        let strategy = WhitespaceInsertionTamper;
314        let result = strategy.tamper("SELECT * FROM users", None);
315        assert!(result.contains('\t'));
316        assert_eq!(result, "SELECT\t*\tFROM\tusers");
317    }
318
319    #[test]
320    fn base64_tamper() {
321        let strategy = Base64Tamper;
322        assert_eq!(strategy.tamper("hello", None), "aGVsbG8=");
323    }
324
325    #[test]
326    fn hex_encode_tamper() {
327        let strategy = HexEncodeTamper;
328        assert_eq!(strategy.tamper("ABC", None), "414243");
329    }
330
331    #[test]
332    fn unicode_escape_tamper() {
333        let strategy = UnicodeEscapeTamper;
334        assert_eq!(strategy.tamper("AB", None), "\\u0041\\u0042");
335    }
336
337    #[test]
338    fn html_entity_tamper() {
339        let strategy = HtmlEntityTamper;
340        assert_eq!(strategy.tamper("<>", None), "&#x3C;&#x3E;");
341    }
342
343    #[test]
344    fn overlong_utf8_tamper() {
345        let strategy = OverlongUtf8Tamper;
346        let result = strategy.tamper("/", None);
347        assert!(result.contains("%C0"));
348    }
349}