├── .flake8
├── .github
├── dependabot.yml
└── workflows
│ └── docker-release.yml
├── .gitignore
├── .travis.yml
├── Dockerfile
├── ISSUE_TEMPLATE.md
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── docs
├── Makefile
├── _static
│ ├── logo.png
│ └── logo
│ │ ├── wfuzz.svg
│ │ └── wfuzz_letters.svg
├── _templates
│ └── sidebarlogo.html
├── conf.py
├── dev
│ └── plugins.rst
├── index.rst
├── library
│ └── guide.rst
├── make.bat
└── user
│ ├── advanced.rst
│ ├── basicusage.rst
│ ├── breaking.rst
│ ├── getting.rst
│ ├── installation.rst
│ └── wfpayload.rst
├── requirements.txt
├── setup.py
├── src
├── wfencode.py
├── wfpayload.py
├── wfuzz-cli.py
├── wfuzz
│ ├── __init__.py
│ ├── __main__.py
│ ├── api.py
│ ├── core.py
│ ├── dictionaries.py
│ ├── exception.py
│ ├── externals
│ │ ├── __init__.py
│ │ ├── moduleman
│ │ │ ├── __init__.py
│ │ │ ├── loader.py
│ │ │ ├── modulefilter.py
│ │ │ ├── plugin.py
│ │ │ └── registrant.py
│ │ ├── reqresp
│ │ │ ├── Request.py
│ │ │ ├── Response.py
│ │ │ ├── TextParser.py
│ │ │ ├── Variables.py
│ │ │ ├── __init__.py
│ │ │ ├── cache.py
│ │ │ └── exceptions.py
│ │ └── settings
│ │ │ ├── __init__.py
│ │ │ └── settings.py
│ ├── facade.py
│ ├── factories
│ │ ├── __init__.py
│ │ ├── dictfactory.py
│ │ ├── fuzzfactory.py
│ │ ├── fuzzresfactory.py
│ │ ├── payman.py
│ │ ├── plugin_factory.py
│ │ └── reqresp_factory.py
│ ├── filters
│ │ ├── __init__.py
│ │ ├── ppfilter.py
│ │ └── simplefilter.py
│ ├── fuzzobjects.py
│ ├── fuzzqueues.py
│ ├── fuzzrequest.py
│ ├── helpers
│ │ ├── __init__.py
│ │ ├── file_func.py
│ │ ├── obj_dic.py
│ │ ├── obj_dyn.py
│ │ ├── obj_factory.py
│ │ ├── str_func.py
│ │ └── utils.py
│ ├── mixins.py
│ ├── myhttp.py
│ ├── myqueues.py
│ ├── options.py
│ ├── plugin_api
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── mixins.py
│ │ ├── payloadtools.py
│ │ └── urlutils.py
│ ├── plugins
│ │ ├── __init__.py
│ │ ├── encoders
│ │ │ ├── __init__.py
│ │ │ └── encoders.py
│ │ ├── iterators
│ │ │ ├── __init__.py
│ │ │ └── iterations.py
│ │ ├── payloads
│ │ │ ├── __init__.py
│ │ │ ├── autorize.py
│ │ │ ├── bing.py
│ │ │ ├── buffer_overflow.py
│ │ │ ├── burpitem.py
│ │ │ ├── burplog.py
│ │ │ ├── burpstate.py
│ │ │ ├── dirwalk.py
│ │ │ ├── file.py
│ │ │ ├── guitab.py
│ │ │ ├── hexrand.py
│ │ │ ├── hexrange.py
│ │ │ ├── ipnet.py
│ │ │ ├── iprange.py
│ │ │ ├── list.py
│ │ │ ├── names.py
│ │ │ ├── permutation.py
│ │ │ ├── range.py
│ │ │ ├── shodanp.py
│ │ │ ├── stdin.py
│ │ │ └── wfuzzp.py
│ │ ├── printers
│ │ │ ├── __init__.py
│ │ │ └── printers.py
│ │ └── scripts
│ │ │ ├── __init__.py
│ │ │ ├── backups.py
│ │ │ ├── cookies.py
│ │ │ ├── cvs_extractor.py
│ │ │ ├── errors.py
│ │ │ ├── grep.py
│ │ │ ├── headers.py
│ │ │ ├── links.py
│ │ │ ├── listing.py
│ │ │ ├── npm_deps.py
│ │ │ ├── robots.py
│ │ │ ├── screenshot.py
│ │ │ ├── sitemap.py
│ │ │ ├── svn_extractor.py
│ │ │ ├── title.py
│ │ │ └── wcdb.py
│ ├── ui
│ │ ├── __init__.py
│ │ ├── console
│ │ │ ├── __init__.py
│ │ │ ├── clparser.py
│ │ │ ├── common.py
│ │ │ ├── getch.py
│ │ │ ├── mvc.py
│ │ │ └── output.py
│ │ └── gui
│ │ │ ├── __init__.py
│ │ │ ├── controller.py
│ │ │ ├── guicontrols.py
│ │ │ └── model.py
│ └── wfuzz.py
└── wxfuzz.py
├── tests
├── acceptance
│ └── test_saved_filter.py
├── api
│ ├── test_encoders.py
│ ├── test_payload.py
│ └── test_session.py
├── conftest.py
├── factories
│ └── test_seedbasebuilder.py
├── filters
│ ├── test_filter.py
│ ├── test_filter_codes.py
│ ├── test_filter_urlp.py
│ ├── test_prefilter_mangle.py
│ └── test_prefilter_mangle_codes.py
├── helpers
│ ├── test_dotdict.py
│ └── test_insensitive_dict.py
├── plugins
│ ├── test_burplog.py
│ ├── test_links.py
│ └── test_summary.py
├── server_dir
│ ├── Dockerfile
│ ├── dir
│ │ ├── a
│ │ ├── b
│ │ ├── c
│ │ └── one
│ ├── docker-compose.yml
│ ├── iterators
│ │ ├── aa
│ │ ├── ac
│ │ └── bb
│ ├── plugins
│ │ └── robots.txt
│ ├── recursive_dir
│ │ └── a
│ │ │ └── b
│ │ │ └── c
│ │ │ └── placeholder.txt
│ ├── simple_server.py
│ └── static
│ │ └── placeholder.txt
├── test_acceptance.py
├── test_api.py
├── test_clparser.py
├── test_filterintro.py
├── test_moduleman.py
├── test_relativeurl.py
├── test_req_parse.py
└── test_reqresp.py
├── tox.ini
├── wfencode
├── wfencode.bat
├── wfpayload
├── wfpayload.bat
├── wfuzz
├── wfuzz.bat
├── wfuzz_bash_completion
├── wordlist
├── Injections
│ ├── All_attack.txt
│ ├── SQL.txt
│ ├── Traversal.txt
│ ├── XML.txt
│ ├── XSS.txt
│ └── bad_chars.txt
├── general
│ ├── admin-panels.txt
│ ├── big.txt
│ ├── catala.txt
│ ├── common.txt
│ ├── euskera.txt
│ ├── extensions_common.txt
│ ├── http_methods.txt
│ ├── medium.txt
│ ├── megabeast.txt
│ ├── mutations_common.txt
│ ├── spanish.txt
│ └── test.txt
├── others
│ ├── common_pass.txt
│ └── names.txt
├── stress
│ ├── alphanum_case.txt
│ ├── alphanum_case_extra.txt
│ ├── char.txt
│ ├── doble_uri_hex.txt
│ ├── test_ext.txt
│ └── uri_hex.txt
├── vulns
│ ├── apache.txt
│ ├── cgis.txt
│ ├── coldfusion.txt
│ ├── dirTraversal-nix.txt
│ ├── dirTraversal-win.txt
│ ├── dirTraversal.txt
│ ├── domino.txt
│ ├── fatwire.txt
│ ├── fatwire_pagenames.txt
│ ├── frontpage.txt
│ ├── iis.txt
│ ├── iplanet.txt
│ ├── jrun.txt
│ ├── netware.txt
│ ├── oracle9i.txt
│ ├── sharepoint.txt
│ ├── sql_inj.txt
│ ├── sunas.txt
│ ├── tests.txt
│ ├── tomcat.txt
│ ├── vignette.txt
│ ├── weblogic.txt
│ └── websphere.txt
└── webservices
│ ├── ws-dirs.txt
│ └── ws-files.txt
├── wxfuzz
└── wxfuzz.bat
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 80
3 | select = C,E,F,W,B,B950
4 | ignore = E203, E501, W503, E402, F401, W504
5 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 |
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "daily"
8 |
9 | - package-ecosystem: "docker"
10 | directory: "/"
11 | schedule:
12 | interval: "daily"
13 |
14 | - package-ecosystem: "pip"
15 | directory: "/"
16 | schedule:
17 | interval: "daily"
18 |
--------------------------------------------------------------------------------
/.github/workflows/docker-release.yml:
--------------------------------------------------------------------------------
1 | name: docker-release
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | docker:
9 | name: Build and push Docker image
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout repo
13 | uses: actions/checkout@v2
14 |
15 | - name: Set up QEMU
16 | uses: docker/setup-qemu-action@v1
17 |
18 | - name: Set up Docker Buildx
19 | uses: docker/setup-buildx-action@v1
20 |
21 | - name: Login to ghcr.io
22 | uses: docker/login-action@v1.4.1
23 | with:
24 | registry: ghcr.io
25 | username: ${{ github.repository_owner }}
26 | password: ${{ secrets.CR_PAT }}
27 |
28 | - name: Build and push Docker images
29 | uses: docker/build-push-action@v2
30 | with:
31 | context: .
32 | file: Dockerfile
33 | push: true
34 | tags: |
35 | ghcr.io/${{ github.repository_owner }}/wfuzz:${{ github.event.release.tag_name }}
36 | ghcr.io/${{ github.repository_owner }}/wfuzz:latest
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | wfuzz.ini
2 |
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 |
7 | # C extensions
8 | *.so
9 |
10 | # Distribution / packaging
11 | .Python
12 | env/
13 | build/
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .coverage
41 | .cache
42 | nosetests.xml
43 | coverage.xml
44 |
45 | # Translations
46 | *.mo
47 | *.pot
48 |
49 | # Django stuff:
50 | *.log
51 |
52 | # Sphinx documentation
53 | docs/_build/
54 |
55 | # PyBuilder
56 | target/
57 |
58 | # vim
59 | *.swp
60 | *.swo
61 |
62 | wfuzz.ini
63 |
64 | # Jetbrains IDE
65 | .idea
66 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: python
3 | services:
4 | - docker
5 | python:
6 | - "3.4"
7 | - "3.5"
8 | - "3.6"
9 | - "3.7"
10 | - "3.8"
11 | before_install:
12 | - docker-compose -f tests/server_dir/docker-compose.yml up -d
13 | install:
14 | - make install-dev
15 | - python setup.py install
16 |
17 | script:
18 | - flake8 src tests
19 | - coverage run --append -m unittest discover -v -s tests/
20 | - if [[ $TRAVIS_PYTHON_VERSION == '3.6' && $TRAVIS_BRANCH == 'master' ]]; then codecov; fi
21 | - if [[ $TRAVIS_PYTHON_VERSION != '3.4' && $TRAVIS_PYTHON_VERSION != '3.5' ]]; then black --check src tests; fi
22 | deploy:
23 | provider: pypi
24 | user: x4vi_mendez
25 | password:
26 | secure: qE2hD6gyopogdJh6Qs9B1s8LkTLiZ2b4jZzDojDOnhITve2hosOfoi2T/a9JrRxP9xeMJmt7t4B7F6h+qiSdi6fz2CLT8qAG5zJFfk/+ZqIQX3zvhthoG6QS8F4Qk7kNDMuaMOeMF3qtK5oSR/cqBY3Fs7SiF9wmH2OH7XBjFdOhRzs7Y8vVEXfxy6O4wHqXkwa6ZHXfuFPly/aZGj8CwlVF4qT6zQGpOrTAJneUonQGei2qIBGVSMSLGXHxndN3a1/RA0L+J3jZKb7zi6XyqAJvXTa3OqbxwSSEdLlUdzPrjLPuMuArgTgDErgSiDlwbceDwx7TlBJy2VEF2OwQ9KAIQFKkE6Rp/sp38l3Dnriv8gzi7N0sdaSAMDH5n8zvl6xJ5hqOnB+1jfpEiSQmvr7chi3OxpniG0eW9ThgZOSLjGp0TXGSh9P3jAiZPlt1HWmNoiwOuTwjue0Lx0MH2vYW1smHJSM+FMbdCL1GwFMsEmBX+2bFzaniuyUEmM5GBpj66Pa9yULho4FTC00Aumffl2A7gnSinYwLzjIB3zUMWFzZBaijLr8caeTYMnMdccNYxWcU4kE1h584FGtMDAO8IdEwW907ZTn0H/sTrb+lFs+x3H4oLc9i+/9j/K1G3jrKJfcTOuMm4D9df+lcfgRCQzB6RyiHJWlEdGEBrJM=
27 | distributions: sdist bdist_wheel
28 | on:
29 | branch:
30 | - master
31 | - /^v.*$/
32 | tags: true
33 | python: 3.6
34 | addons:
35 | apt:
36 | packages:
37 | - libcurl4-openssl-dev
38 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.8-alpine3.12 as builder
2 |
3 | RUN apk add --no-cache build-base curl-dev
4 |
5 | COPY . wfuzz/
6 |
7 | WORKDIR wfuzz/
8 |
9 | RUN python setup.py install
10 |
11 |
12 | FROM python:3.8-alpine3.12
13 |
14 | RUN apk add --no-cache curl-dev
15 |
16 | COPY --from=builder /usr/local /usr/local
17 |
18 | CMD wfuzz
19 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # Issue template
2 |
3 | ## Context
4 |
5 | **Please check:**
6 |
7 | - [ ] I've read the docs for [Wfuzz](http://wfuzz.readthedocs.io/)
8 |
9 | **Please describe your local environment:**
10 |
11 | Wfuzz version: Output of wfuzz --version
12 |
13 | Python version: Output of python --version
14 |
15 | OS: X
16 |
17 | ## Report
18 |
19 | **What is the current behavior?**
20 |
21 | X
22 |
23 | **What is the expected or desired behavior?**
24 |
25 | X
26 |
27 | **Please provide steps to reproduce, including exact wfuzz command executed and output:**
28 |
29 | X
30 |
31 | **Other relevant information:**
32 |
33 | X
34 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include README.md
2 | include LICENSE
3 | include docs/*
4 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: docs
2 | tox:
3 | pip install tox
4 | tox --recreate
5 | test:
6 | pytest -v -s tests/
7 | flake8:
8 | black --check src tests
9 | flake8 src tests
10 | publish:
11 | pip install 'twine>=1.5.0'
12 | python setup.py sdist
13 | twine upload dist/*
14 | rm -fr build dist
15 |
16 | publish-dev:
17 | pip install 'twine>=1.5.0'
18 | python setup.py sdist
19 | twine upload --repository-url https://test.pypi.org/legacy/ dist/*
20 | rm -fr build dist
21 | docs:
22 | pip install -e ".[docs]"
23 | cd docs && make html
24 |
25 | coverage:
26 | coverage report --skip-covered --include "*python3.8/site-packages/wfuzz*" -m
27 |
28 | install: install-dev
29 | pip install -r requirements.txt
30 |
31 | install-dev:
32 | pip install -e ".[dev]"
33 |
34 | freeze:
35 | pip-compile --output-file requirements.txt setup.py
36 | help:
37 | @echo "make help Show this help message"
38 | @echo "make test Run local tests with tox"
39 | @echo "make flake8 Run the code linter(s) and print any warnings"
40 | @echo "make publish Publish pip lib to pypi"
41 | @echo "make publish-dev Publish pip lib to pypi test"
42 | @echo "make docs Create html docs"
43 | @echo "make install Install requirements"
44 | @echo "make install-dev Install dev requirements"
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | [](https://travis-ci.org/xmendez/wfuzz)
4 |
5 |
6 |
7 |
8 |
9 |
10 | # Wfuzz - The Web Fuzzer
11 |
12 | Wfuzz has been created to facilitate the task in web applications assessments and it is based on a simple concept: it replaces any reference to the FUZZ keyword by the value of a given payload.
13 |
14 | A payload in Wfuzz is a source of data.
15 |
16 | This simple concept allows any input to be injected in any field of an HTTP request, allowing to perform complex web security attacks in different web application components such as: parameters, authentication, forms, directories/files, headers, etc.
17 |
18 | Wfuzz is more than a web content scanner:
19 |
20 | * Wfuzz could help you to secure your web applications by finding and exploiting web application vulnerabilities. Wfuzz’s web application vulnerability scanner is supported by plugins.
21 |
22 | * Wfuzz is a completely modular framework and makes it easy for even the newest of Python developers to contribute. Building plugins is simple and takes little more than a few minutes.
23 |
24 | * Wfuzz exposes a simple language interface to the previous HTTP requests/responses performed using Wfuzz or other tools, such as Burp. This allows you to perform manual and semi-automatic tests with full context and understanding of your actions, without relying on a web application scanner underlying implementation.
25 |
26 |
27 | It was created to facilitate the task in web applications assessments, it's a tool by pentesters for pentesters ;)
28 |
29 | ## Installation
30 |
31 | To install WFuzz, simply use pip:
32 |
33 | ```
34 | pip install wfuzz
35 | ```
36 |
37 | To run Wfuzz from a docker image, run:
38 |
39 | ```
40 | $ docker run -v $(pwd)/wordlist:/wordlist/ -it ghcr.io/xmendez/wfuzz wfuzz
41 | ```
42 |
43 | ## Documentation
44 |
45 | Documentation is available at http://wfuzz.readthedocs.io
46 |
47 | ## Download
48 |
49 | Check github releases. Latest is available at https://github.com/xmendez/wfuzz/releases/latest
50 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | SPHINXPROJ = Wfuzz
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
--------------------------------------------------------------------------------
/docs/_static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/docs/_static/logo.png
--------------------------------------------------------------------------------
/docs/_templates/sidebarlogo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 | 8 |
9 | WFuzz is a web application security fuzzer tool and library for Python. 10 |
11 | 12 | 13 |16 | Be part of the Wfuzz's community via GitHub tickets and pull requests.
17 | 18 | 20 | 21 | 22 |25 | Don’t forget to follow my github, twitter for news, releases and feedback. 26 |
27 | 28 | 30 | 31 |32 | 33 | Follow @x4vi_mendez 34 |
35 | 36 | -------------------------------------------------------------------------------- /docs/dev/plugins.rst: -------------------------------------------------------------------------------- 1 | Plugin template 2 | =============== 3 | 4 | Printer template 5 | =============== 6 | 7 | Encoder template 8 | =============== 9 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=Wfuzz 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/user/breaking.rst: -------------------------------------------------------------------------------- 1 | Breaking changes 2 | ============= 3 | 4 | Following https://semver.org/ versioning since Wfuzz 3.0.0. 5 | 6 | * Wfuzz 3.0.0: 7 | * In wfuzz library prefilter is a list of filters not a string. 8 | * When using --recipe, stored options that are a list are appended. Previously, the last one took precedence. 9 | -------------------------------------------------------------------------------- /docs/user/wfpayload.rst: -------------------------------------------------------------------------------- 1 | wfpayload 2 | ========= 3 | 4 | wfpayload uses the same motor as wfuzz but instead of performing HTTP requests, uses wfuzz's payload plugins to generate new content or analyse saved sessions. 5 | 6 | Generating new dictionaries 7 | ------------------- 8 | 9 | You can use wfpayload to create new dictionaries:: 10 | 11 | $ wfpayload -z range --zD 0-10 12 | 0 13 | 1 14 | 2 15 | 3 16 | 4 17 | 5 18 | 6 19 | 7 20 | 8 21 | 9 22 | 10 23 | 24 | The same wfuzz's syntax can be used, for example:: 25 | 26 | $ wfpayload -z range --zD 0-10 --filter "FUZZ<3" 27 | 0 28 | 1 29 | 2 30 | 31 | 32 | Analysing saved sessions 33 | ------------------ 34 | 35 | Previously performed HTTP requests/responses contain a treasure trove of data. You can use wfpayload to filter and analyse previously saved sessions. Wfpayload can also read sessions from external tools, such as burp. 36 | 37 | This allows you to look for new vulnerabilities or understand the underlying target without performing new HTTP requests. 38 | 39 | For example, the following will return a unique list of HTTP requests including the authtoken parameter as a GET parameter:: 40 | 41 | $ wfpayload -z burplog,a_burp_log.log --slice "params.get~'authtoken'" 42 | 43 | Authtoken is the parameter used by BEA WebLogic Commerce Servers (TM) as a CSRF token, and therefore the above will find all the requests exposing the CSRF token in the URL. 44 | 45 | You can also look for specific parameters or headers, for example, the following will look for HTTP responses accepting any CORS origin:: 46 | 47 | $ wfpayload -z burplog --zD burp_log_05032020.log --prefilter "r.headers.response.Access-Control-Allow-Origin='*'" 48 | 49 | It is worth noting that, if the header is not present in the response it will be return an empty value, not raising any error. 50 | 51 | You can also select the fields to show with --efield and --field, for example:: 52 | 53 | $ wfpayload -z wfuzzp --zD /tmp/session --field r.params.get 54 | artist=5 55 | ... 56 | 57 | Or:: 58 | 59 | $ wfpayload -z wfuzzp --zD /tmp/session --efield r.params.get 60 | 000000006: 200 99 L 272 W 3868 Ch "5 | artist=5" 61 | ... 62 | 63 | Running plugins against saved sessions 64 | ------------------- 65 | 66 | Plugins can be run against a saved session. For example:: 67 | 68 | $ ./wfpayload -z burplog --zD ./burp_log_05032020.log --script=headers --filter "plugins~'akamai'" 69 | ... 70 | 000000124: 302 0 L 0 W 0 Ch "https://trial-eum-clientnsv4-s.akamaihd.net/eum/getdns.txt?c=pjq71x1r7" 71 | |_ New Server header - AkamaiGHost 72 | 000000913: 200 10 L 6571 W 289832 Ch "https://assets.adobedtm.com/2eed2bf00c8bca0c98d97ffee50a306922bc8c98/satelliteLib-27b81756e778cc85cc1a2f067764cd3abf072aa9.js" 73 | |_ New Server header - AkamaiNetStorage 74 | ... 75 | 76 | Re-writing saved sessions 77 | ------------------- 78 | 79 | The content of a saved session can be re-written. For example, let's say there is a session with a bunch of 404/400 results that you want to remove:: 80 | 81 | $ wfpayload -z burplog --zD ./burp_log_05032020.log --hc 404 --oF /tmp/no404 82 | 83 | and then:: 84 | 85 | $ wfpayload -z wfuzzp --zD /tmp/no404 86 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile 3 | # To update, run: 4 | # 5 | # pip-compile --output-file=requirements.txt setup.py 6 | # 7 | attrs==20.1.0 # via pytest 8 | chardet==3.0.4 # via wfuzz (setup.py) 9 | iniconfig==1.0.1 # via pytest 10 | more-itertools==8.5.0 # via pytest 11 | packaging==20.4 # via pytest 12 | pluggy==0.13.1 # via pytest 13 | py==1.9.0 # via pytest 14 | pycurl==7.43.0.6 # via wfuzz (setup.py) 15 | pyparsing==2.4.7 # via packaging 16 | pytest==6.0.1 # via wfuzz (setup.py) 17 | six==1.15.0 # via packaging, wfuzz (setup.py) 18 | toml==0.10.1 # via pytest 19 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import re 4 | from setuptools import setup, find_packages 5 | 6 | with open("README.md", "rb") as f: 7 | long_descr = f.read().decode("utf-8") 8 | 9 | 10 | version = re.search( 11 | r'^__version__\s*=\s*"(.*)"', 12 | open('src/wfuzz/__init__.py').read(), 13 | re.M 14 | ).group(1) 15 | 16 | docs_requires = [ 17 | "Sphinx", 18 | ] 19 | 20 | dev_requires = [ 21 | 'mock', 22 | 'coverage', 23 | 'codecov', 24 | 'netaddr', # tests/api/test_payload.py uses ipranges payload 25 | 'pip-tools', 26 | 'flake8==3.8.3', 27 | 'black==19.10b0;python_version>"3.5"', 28 | 'pytest', 29 | ] 30 | 31 | install_requires = [ 32 | 'pycurl', 33 | 'pyparsing<2.4.2;python_version<="3.4"', 34 | 'pyparsing>=2.4*;python_version>="3.5"', 35 | 'six', 36 | 'configparser;python_version<"3.5"', 37 | 'chardet', 38 | ] 39 | 40 | 41 | if sys.platform.startswith("win"): 42 | install_requires += ["colorama>=0.4.0"] 43 | 44 | 45 | try: 46 | os.symlink('../../docs/user/advanced.rst', 'src/wfuzz/advanced.rst') 47 | setup( 48 | name="wfuzz", 49 | packages=find_packages(where='src'), 50 | package_dir={'wfuzz': 'src/wfuzz'}, 51 | include_package_data=True, 52 | package_data={'wfuzz': ['*.rst']}, 53 | entry_points={ 54 | 'console_scripts': [ 55 | 'wfuzz = wfuzz.wfuzz:main', 56 | 'wfpayload = wfuzz.wfuzz:main_filter', 57 | 'wfencode = wfuzz.wfuzz:main_encoder', 58 | ], 59 | 'gui_scripts': [ 60 | 'wxfuzz = wfuzz.wfuzz:main_gui', 61 | ] 62 | }, 63 | version=version, 64 | description="Wfuzz - The web fuzzer", 65 | long_description=long_descr, 66 | long_description_content_type='text/markdown', 67 | author="Xavi Mendez (@x4vi_mendez)", 68 | author_email="xmendez@edge-security.com", 69 | url="http://wfuzz.org", 70 | license="GPLv2", 71 | install_requires=install_requires, 72 | extras_require={ 73 | 'dev': dev_requires, 74 | 'docs': docs_requires, 75 | }, 76 | python_requires=">=2.6", 77 | classifiers=( 78 | 'Development Status :: 4 - Beta', 79 | 'Natural Language :: English', 80 | 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', 81 | 'Programming Language :: Python', 82 | 'Programming Language :: Python :: 3', 83 | 'Programming Language :: Python :: 3.4', 84 | 'Programming Language :: Python :: 3.5', 85 | 'Programming Language :: Python :: 3.6', 86 | 'Programming Language :: Python :: 3.7', 87 | 'Programming Language :: Python :: 3.8', 88 | ), 89 | ) 90 | finally: 91 | os.unlink('src/wfuzz/advanced.rst') 92 | -------------------------------------------------------------------------------- /src/wfencode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from wfuzz.wfuzz import main_encoder 3 | 4 | if __name__ == "__main__": 5 | main_encoder() 6 | -------------------------------------------------------------------------------- /src/wfpayload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from wfuzz.wfuzz import main_filter 3 | 4 | if __name__ == "__main__": 5 | main_filter() 6 | -------------------------------------------------------------------------------- /src/wfuzz-cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from wfuzz.wfuzz import main 4 | 5 | if __name__ == "__main__": 6 | main() 7 | -------------------------------------------------------------------------------- /src/wfuzz/__init__.py: -------------------------------------------------------------------------------- 1 | __title__ = "wfuzz" 2 | __version__ = "3.1.0" 3 | __build__ = 0x023000 4 | __author__ = "Xavier Mendez" 5 | __license__ = "GPL 2.0" 6 | __copyright__ = "Copyright 2011-2020 Xavier Mendez" 7 | 8 | import logging 9 | import sys 10 | 11 | import warnings 12 | 13 | 14 | # define a logging Handler 15 | console = logging.StreamHandler() 16 | console.setLevel(logging.WARNING) 17 | formatter = logging.Formatter("%(name)-12s: %(levelname)-8s %(message)s") 18 | console.setFormatter(formatter) 19 | logging.getLogger("").addHandler(console) 20 | 21 | 22 | # define warnings format 23 | def warning_on_one_line(message, category, filename, lineno, file=None, line=None): 24 | return " %s:%s: %s:%s\n" % (filename, lineno, category.__name__, message) 25 | 26 | 27 | warnings.formatwarning = warning_on_one_line 28 | 29 | 30 | try: 31 | import pycurl 32 | 33 | if "openssl".lower() not in pycurl.version.lower(): 34 | warnings.warn( 35 | "Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information." 36 | ) 37 | 38 | if not hasattr(pycurl, "CONNECT_TO"): 39 | warnings.warn( 40 | "Pycurl and/or libcurl version is old. CONNECT_TO option is missing. Wfuzz --ip option will not be available." 41 | ) 42 | 43 | if not hasattr(pycurl, "PATH_AS_IS"): 44 | warnings.warn( 45 | "Pycurl and/or libcurl version is old. PATH_AS_IS option is missing. Wfuzz might not correctly fuzz URLS with '..'." 46 | ) 47 | 48 | except ImportError: 49 | warnings.warn( 50 | "fuzz needs pycurl to run. Pycurl could be installed using the following command: $ pip install pycurl" 51 | ) 52 | 53 | sys.exit(1) 54 | 55 | from .options import FuzzSession 56 | from .api import fuzz, get_payload, get_payloads, encode, decode, payload, get_session 57 | -------------------------------------------------------------------------------- /src/wfuzz/__main__.py: -------------------------------------------------------------------------------- 1 | from .wfuzz import main 2 | 3 | main() 4 | -------------------------------------------------------------------------------- /src/wfuzz/api.py: -------------------------------------------------------------------------------- 1 | from .options import FuzzSession 2 | from .facade import Facade 3 | from .ui.console.clparser import CLParser 4 | 5 | """ 6 | Wfuzz API 7 | """ 8 | 9 | 10 | def fuzz(**kwargs): 11 | return FuzzSession(**kwargs).fuzz() 12 | 13 | 14 | def get_payloads(iterator): 15 | fs = FuzzSession() 16 | 17 | return fs.get_payloads(iterator) 18 | 19 | 20 | def get_payload(iterator): 21 | fs = FuzzSession() 22 | return fs.get_payload(iterator) 23 | 24 | 25 | def encode(name, value): 26 | return Facade().encoders.get_plugin(name)().encode(value) 27 | 28 | 29 | def decode(name, value): 30 | return Facade().encoders.get_plugin(name)().decode(value) 31 | 32 | 33 | def payload(**kwargs): 34 | return FuzzSession(**kwargs).payload() 35 | 36 | 37 | def get_session(cline): 38 | cl = ["wfuzz"] + cline.split(" ") 39 | return FuzzSession(**CLParser(cl).parse_cl()) 40 | -------------------------------------------------------------------------------- /src/wfuzz/exception.py: -------------------------------------------------------------------------------- 1 | class FuzzException(Exception): 2 | pass 3 | 4 | 5 | class FuzzExceptBadOptions(FuzzException): 6 | pass 7 | 8 | 9 | class FuzzExceptNoPluginError(FuzzException): 10 | pass 11 | 12 | 13 | class FuzzExceptPluginLoadError(FuzzException): 14 | pass 15 | 16 | 17 | class FuzzExceptIncorrectFilter(FuzzException): 18 | pass 19 | 20 | 21 | class FuzzExceptBadAPI(FuzzException): 22 | pass 23 | 24 | 25 | class FuzzExceptInternalError(FuzzException): 26 | pass 27 | 28 | 29 | class FuzzExceptBadFile(FuzzException): 30 | pass 31 | 32 | 33 | class FuzzExceptBadInstall(FuzzException): 34 | pass 35 | 36 | 37 | class FuzzExceptBadRecipe(FuzzException): 38 | pass 39 | 40 | 41 | class FuzzExceptMissingAPIKey(FuzzException): 42 | pass 43 | 44 | 45 | class FuzzExceptPluginBadParams(FuzzException): 46 | pass 47 | 48 | 49 | class FuzzExceptResourceParseError(FuzzException): 50 | pass 51 | 52 | 53 | class FuzzExceptPluginError(FuzzException): 54 | pass 55 | 56 | 57 | class FuzzExceptNetError(FuzzException): 58 | pass 59 | -------------------------------------------------------------------------------- /src/wfuzz/externals/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/externals/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/externals/moduleman/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/externals/moduleman/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/externals/moduleman/plugin.py: -------------------------------------------------------------------------------- 1 | try: 2 | from collections.abc import Callable 3 | except ImportError: 4 | from collections import Callable 5 | 6 | 7 | def moduleman_plugin(*args): 8 | method_args = [] 9 | 10 | def inner_decorator(cls): 11 | for method in method_args: 12 | if not (method in dir(cls)): 13 | raise Exception("Required method %s not implemented" % method) 14 | cls.__PLUGIN_MODULEMAN_MARK = "Plugin mark" 15 | 16 | return cls 17 | 18 | if not isinstance(args[0], Callable): 19 | method_args += args 20 | return inner_decorator 21 | 22 | return inner_decorator(args[0]) 23 | -------------------------------------------------------------------------------- /src/wfuzz/externals/reqresp/__init__.py: -------------------------------------------------------------------------------- 1 | from .Request import Request 2 | from .Response import Response 3 | -------------------------------------------------------------------------------- /src/wfuzz/externals/reqresp/cache.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | class HttpCache: 5 | def __init__(self): 6 | # cache control 7 | self.__cache_map = defaultdict(list) 8 | 9 | def update_cache(self, req, category="default"): 10 | key = req.to_cache_key() 11 | 12 | # first hit 13 | if key not in self.__cache_map: 14 | self.__cache_map[key].append(category) 15 | return True 16 | elif key in self.__cache_map and category not in self.__cache_map[key]: 17 | self.__cache_map[key].append(category) 18 | return True 19 | 20 | return False 21 | 22 | def msg_in_cache(self, req, category="default"): 23 | key = req.to_cache_key() 24 | 25 | return key in self.__cache_map and category in self.__cache_map[key] 26 | -------------------------------------------------------------------------------- /src/wfuzz/externals/reqresp/exceptions.py: -------------------------------------------------------------------------------- 1 | class ReqRespException(Exception): 2 | FATAL, RESOLVE_PROXY, RESOLVE_HOST, CONNECT_HOST, SSL, TIMEOUT = list(range(6)) 3 | 4 | def __init__(self, etype, msg): 5 | self.etype = etype 6 | self.msg = msg 7 | Exception.__init__(self, msg) 8 | -------------------------------------------------------------------------------- /src/wfuzz/externals/settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/externals/settings/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/externals/settings/settings.py: -------------------------------------------------------------------------------- 1 | # Python 2 and 3 (after ``pip install configparser``): 2 | try: 3 | from configparser import ConfigParser 4 | except ImportError: 5 | import ConfigParser 6 | import os 7 | import sys 8 | 9 | 10 | class SettingsBase: 11 | """ 12 | Contains application settings. uses a ConfigParser 13 | """ 14 | 15 | def __init__(self, save=False): 16 | self.cparser = ConfigParser() 17 | 18 | self.set_all(self.set_defaults()) 19 | self.filename = os.path.join( 20 | self._path_to_program_dir(), self.get_config_file() 21 | ) 22 | self.cparser.read(self.filename) 23 | 24 | # Base members should implement 25 | 26 | def get_config_file(self): 27 | """Returns the name of the file where the config is saved.""" 28 | raise NotImplementedError 29 | 30 | def set_defaults(self): 31 | """ 32 | Returns a dictionary with the default settings in the form of 33 | { \ 34 | Section: [ \ 35 | ("setting_x", '5'), 36 | ... 37 | ("setting_y", '5'), 38 | ], 39 | ... 40 | } 41 | """ 42 | raise NotImplementedError 43 | 44 | def has_option(self, section, setting): 45 | return self.cparser.has_option(section, setting) 46 | 47 | def set(self, section, setting, value): 48 | self.cparser.set(section, setting, value) 49 | 50 | def get(self, section, setting): 51 | value = self.cparser.get(section, setting) 52 | return value 53 | 54 | def get_section(self, section): 55 | return self.cparser.items(section) 56 | 57 | def get_options(self, section): 58 | return self.cparser.options(section) 59 | 60 | def get_sections(self): 61 | return self.cparser.sections() 62 | 63 | def get_all(self): 64 | sett = {} 65 | 66 | # dump entire config file 67 | for section in self.cparser.sections(): 68 | for option in self.cparser.options(section): 69 | if section not in sett: 70 | sett[section] = [] 71 | sett[section].append((option, self.cparser.get(section, option))) 72 | 73 | return sett 74 | 75 | def set_all(self, sett): 76 | self.cparser = ConfigParser() 77 | for section, settings in sett.items(): 78 | self.cparser.add_section(section) 79 | for key, value in settings: 80 | self.cparser.set(section, key, value) 81 | 82 | def save(self): 83 | try: 84 | with open(self.filename, "w") as iniFile: 85 | self.cparser.write(iniFile) 86 | except Exception: 87 | return False 88 | return True 89 | 90 | def _path_to_program_dir(self): 91 | """ 92 | Returns path to program directory 93 | """ 94 | path = sys.argv[0] 95 | 96 | if not os.path.isdir(path): 97 | path = os.path.dirname(path) 98 | 99 | if not path: 100 | return "." 101 | 102 | return path 103 | -------------------------------------------------------------------------------- /src/wfuzz/facade.py: -------------------------------------------------------------------------------- 1 | from .helpers.file_func import get_home, get_path, get_config_dir 2 | from .helpers.obj_factory import Singleton 3 | from . import __version__ as version 4 | from .externals.moduleman.registrant import MulRegistrant 5 | from .externals.moduleman.loader import DirLoader 6 | from .externals.settings.settings import SettingsBase 7 | from .exception import FuzzExceptNoPluginError, FuzzExceptPluginLoadError 8 | 9 | import os 10 | 11 | 12 | ERROR_CODE = -1 13 | BASELINE_CODE = -2 14 | 15 | 16 | class Settings(SettingsBase): 17 | def get_config_file(self): 18 | config_file = "wfuzz.ini" 19 | 20 | config = os.path.join(get_config_dir(check=False), config_file) 21 | legacy_config = os.path.join(get_home(check=False), config_file) 22 | 23 | if os.path.exists(config): 24 | return config 25 | elif os.path.exists(legacy_config): 26 | return legacy_config 27 | return os.path.join(get_config_dir(check=True), config_file) 28 | 29 | def set_defaults(self): 30 | return dict( 31 | plugins=[("bing_apikey", ""), ("shodan_apikey", "")], 32 | kbase=[ 33 | ( 34 | "discovery.blacklist", 35 | ".svg-.css-.js-.jpg-.gif-.png-.jpeg-.mov-.avi-.flv-.ico", 36 | ) 37 | ], 38 | connection=[ 39 | ("concurrent", "10"), 40 | ("conn_delay", "90"), 41 | ("req_delay", "90"), 42 | ("retries", "3"), 43 | ("User-Agent", "Wfuzz/%s" % version), 44 | ], 45 | general=[ 46 | ("default_printer", "raw"), 47 | ("cancel_on_plugin_except", "0"), 48 | ("concurrent_plugins", "3"), 49 | ("lookup_dirs", "."), 50 | ("encode_space", "1"), 51 | ], 52 | ) 53 | 54 | 55 | class MyRegistrant(MulRegistrant): 56 | def get_plugin(self, identifier): 57 | try: 58 | return MulRegistrant.get_plugin(self, identifier) 59 | except KeyError as e: 60 | raise FuzzExceptNoPluginError( 61 | "Requested plugin %s. Error: %s" % (identifier, str(e)) 62 | ) 63 | 64 | 65 | class Facade(metaclass=Singleton): 66 | def __init__(self): 67 | 68 | self.__plugins = dict( 69 | printers=None, scripts=None, encoders=None, iterators=None, payloads=None, 70 | ) 71 | 72 | self.sett = Settings() 73 | 74 | def _load(self, cat): 75 | try: 76 | if cat not in self.__plugins: 77 | raise FuzzExceptNoPluginError("Non-existent plugin category %s" % cat) 78 | 79 | if not self.__plugins[cat]: 80 | loader_list = [] 81 | loader_list.append( 82 | DirLoader(**{"base_dir": cat, "base_path": get_path("../plugins")}) 83 | ) 84 | loader_list.append( 85 | DirLoader(**{"base_dir": cat, "base_path": get_home()}) 86 | ) 87 | self.__plugins[cat] = MyRegistrant(loader_list) 88 | 89 | return self.__plugins[cat] 90 | except Exception as e: 91 | raise FuzzExceptPluginLoadError("Error loading plugins: %s" % str(e)) 92 | 93 | def proxy(self, which): 94 | return self._load(which) 95 | 96 | def get_registrants(self): 97 | return self.__plugins.keys() 98 | 99 | def __getattr__(self, name): 100 | if name in ["printers", "payloads", "iterators", "encoders", "scripts"]: 101 | return self._load(name) 102 | else: 103 | raise AttributeError 104 | -------------------------------------------------------------------------------- /src/wfuzz/factories/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/factories/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/factories/fuzzfactory.py: -------------------------------------------------------------------------------- 1 | from ..fuzzrequest import FuzzRequest 2 | 3 | from ..helpers.obj_factory import ObjectFactory, SeedBuilderHelper 4 | 5 | 6 | class FuzzRequestFactory(ObjectFactory): 7 | def __init__(self): 8 | ObjectFactory.__init__( 9 | self, 10 | { 11 | "request_from_options": RequestBuilder(), 12 | "seed_from_options": SeedBuilder(), 13 | }, 14 | ) 15 | 16 | 17 | class RequestBuilder: 18 | def __call__(self, options): 19 | fr = FuzzRequest() 20 | 21 | fr.url = options["url"] 22 | fr.wf_fuzz_methods = options["method"] 23 | fr.update_from_options(options) 24 | 25 | return fr 26 | 27 | 28 | class SeedBuilder: 29 | def __call__(self, options): 30 | seed = reqfactory.create("request_from_options", options) 31 | marker_dict = SeedBuilderHelper.get_marker_dict(seed) 32 | SeedBuilderHelper.remove_baseline_markers(seed, marker_dict) 33 | 34 | return seed 35 | 36 | 37 | reqfactory = FuzzRequestFactory() 38 | -------------------------------------------------------------------------------- /src/wfuzz/factories/payman.py: -------------------------------------------------------------------------------- 1 | from ..fuzzobjects import FPayloadManager, FuzzWord, FuzzWordType 2 | 3 | from ..helpers.obj_factory import ObjectFactory, SeedBuilderHelper 4 | 5 | 6 | class PayManFactory(ObjectFactory): 7 | def __init__(self): 8 | ObjectFactory.__init__( 9 | self, 10 | { 11 | "payloadman_from_baseline": BaselinePayloadManBuilder(), 12 | "payloadman_from_request": FuzzReqPayloadManBuilder(), 13 | "empty_payloadman": OnePayloadManBuilder(), 14 | }, 15 | ) 16 | 17 | 18 | class FuzzReqPayloadManBuilder: 19 | def __call__(self, freq): 20 | fpm = FPayloadManager() 21 | 22 | for pdict in [ 23 | pdict 24 | for pdict in SeedBuilderHelper.get_marker_dict(freq) 25 | if pdict["word"] is not None 26 | ]: 27 | fpm.add(pdict) 28 | 29 | return fpm 30 | 31 | 32 | class OnePayloadManBuilder: 33 | def __call__(self, content): 34 | fpm = FPayloadManager() 35 | fpm.add( 36 | {"full_marker": None, "word": None, "index": None, "field": None}, content 37 | ) 38 | 39 | return fpm 40 | 41 | 42 | class BaselinePayloadManBuilder: 43 | def __call__(self, freq): 44 | fpm = FPayloadManager() 45 | 46 | for pdict in [ 47 | pdict 48 | for pdict in SeedBuilderHelper.get_marker_dict(freq) 49 | if pdict["bl_value"] is not None 50 | ]: 51 | fpm.add(pdict, FuzzWord(pdict["bl_value"], FuzzWordType.WORD), True) 52 | 53 | return fpm 54 | 55 | 56 | payman_factory = PayManFactory() 57 | -------------------------------------------------------------------------------- /src/wfuzz/factories/plugin_factory.py: -------------------------------------------------------------------------------- 1 | from ..helpers.obj_factory import ObjectFactory 2 | 3 | from ..fuzzobjects import FuzzPlugin, FuzzError 4 | from ..factories.fuzzresfactory import resfactory 5 | 6 | 7 | class PluginFactory(ObjectFactory): 8 | def __init__(self): 9 | ObjectFactory.__init__( 10 | self, 11 | { 12 | "plugin_from_recursion": PluginRecursiveBuilder(), 13 | "plugin_from_error": PluginErrorBuilder(), 14 | "plugin_from_finding": PluginFindingBuilder(), 15 | "plugin_from_summary": PluginFindingSummaryBuilder(), 16 | }, 17 | ) 18 | 19 | 20 | class PluginRecursiveBuilder: 21 | def __call__(self, name, seed, url): 22 | plugin = FuzzPlugin() 23 | plugin.source = name 24 | plugin._exception = None 25 | plugin._seed = resfactory.create("fuzzres_from_recursion", seed, url) 26 | 27 | return plugin 28 | 29 | 30 | class PluginErrorBuilder: 31 | def __call__(self, name, exception): 32 | plugin = FuzzPlugin() 33 | plugin.source = name 34 | plugin.issue = "Exception within plugin %s: %s" % (name, str(exception)) 35 | plugin._exception = FuzzError(exception) 36 | plugin._seed = None 37 | 38 | return plugin 39 | 40 | 41 | class PluginFindingBuilder: 42 | def __call__(self, name, itype, message, data, severity): 43 | plugin = FuzzPlugin() 44 | plugin.source = name 45 | plugin.issue = message 46 | plugin.itype = itype 47 | plugin.data = data 48 | plugin._exception = None 49 | plugin._seed = None 50 | plugin.severity = severity 51 | 52 | return plugin 53 | 54 | 55 | class PluginFindingSummaryBuilder: 56 | def __call__(self, message): 57 | plugin = FuzzPlugin() 58 | plugin.source = FuzzPlugin.OUTPUT_SOURCE 59 | plugin.itype = FuzzPlugin.SUMMARY_ITYPE 60 | plugin.severity = FuzzPlugin.NONE 61 | plugin._exception = None 62 | plugin.data = None 63 | plugin._seed = None 64 | plugin.issue = message 65 | 66 | return plugin 67 | 68 | 69 | plugin_factory = PluginFactory() 70 | -------------------------------------------------------------------------------- /src/wfuzz/filters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/filters/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/helpers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/helpers/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/helpers/obj_dic.py: -------------------------------------------------------------------------------- 1 | from collections.abc import MutableMapping 2 | from itertools import chain 3 | 4 | 5 | class CaseInsensitiveDict(MutableMapping): 6 | def __init__(self, *args, **kwargs): 7 | self.store = dict() 8 | self.proxy = dict() 9 | 10 | self.update(dict(*args, **kwargs)) # use the free update to set keys 11 | 12 | def __contains__(self, k): 13 | return k.lower() in self.proxy 14 | 15 | def __delitem__(self, k): 16 | key = self.proxy[k.lower()] 17 | 18 | del self.store[key] 19 | del self.proxy[k.lower()] 20 | 21 | def __getitem__(self, k): 22 | key = self.proxy[k.lower()] 23 | return self.store[key] 24 | 25 | def get(self, k, default=None): 26 | key = self.proxy[k.lower()] 27 | return self.store[key] if key in self.store else default 28 | 29 | def __setitem__(self, k, v): 30 | self.store[k] = v 31 | self.proxy[k.lower()] = k 32 | 33 | def __iter__(self): 34 | return iter(self.store) 35 | 36 | def __len__(self): 37 | return len(self.store) 38 | 39 | 40 | class DotDict(CaseInsensitiveDict): 41 | def __getattr__(obj, name): 42 | # Return {} if non-existent attr 43 | if name not in obj: 44 | return DotDict({}) 45 | 46 | # python 3 val = dict.get(*args, None) 47 | val = obj.get(name) 48 | return DotDict(val) if type(val) is dict else val 49 | # return DotDict(val) if type(val) is dict else DotDict({args[1]: val}) 50 | 51 | def __add__(self, other): 52 | if isinstance(other, str): 53 | return DotDict({k: v + other for k, v in self.items() if v}) 54 | elif isinstance(other, DotDict): 55 | # python 3 return DotDict({**self, **other}) 56 | new_dic = DotDict(self) 57 | new_dic.update(other) 58 | return new_dic 59 | 60 | def __radd__(self, other): 61 | if isinstance(other, str): 62 | return DotDict({k: other + v for k, v in self.items() if v}) 63 | 64 | def __getitem__(self, key): 65 | try: 66 | return super(DotDict, self).__getitem__(key) 67 | except KeyError: 68 | return DotDict({}) 69 | 70 | def __str__(self): 71 | return "\n".join( 72 | [ 73 | "{}{} {}".format(k, "->" if isinstance(v, DotDict) else ":", v) 74 | for k, v in self.items() 75 | ] 76 | ) 77 | -------------------------------------------------------------------------------- /src/wfuzz/helpers/obj_dyn.py: -------------------------------------------------------------------------------- 1 | import functools 2 | from .obj_dic import DotDict 3 | 4 | 5 | allowed_fields = [ 6 | "description", 7 | "nres", 8 | "code", 9 | "chars", 10 | "lines", 11 | "words", 12 | "md5", 13 | "l", 14 | "h", 15 | "w", 16 | "c", 17 | "history", 18 | "plugins", 19 | "url", 20 | "content", 21 | "history.url", 22 | "history.method", 23 | "history.scheme", 24 | "history.host", 25 | "history.content", 26 | "history.raw_content" "history.is_path", 27 | "history.pstrip", 28 | "history.cookies", 29 | "history.headers", 30 | "history.params", 31 | "r", 32 | "r.reqtime", 33 | "r.url", 34 | "r.method", 35 | "r.scheme", 36 | "r.host", 37 | "r.content", 38 | "r.raw_content" "r.is_path", 39 | "r.pstrip", 40 | "r.cookies.", 41 | "r.headers.", 42 | "r.params.", 43 | ] 44 | 45 | 46 | def _check_allowed_field(attr): 47 | if [field for field in allowed_fields if attr.startswith(field)]: 48 | return True 49 | return False 50 | 51 | 52 | def _get_alias(attr): 53 | attr_alias = { 54 | "l": "lines", 55 | "h": "chars", 56 | "w": "words", 57 | "c": "code", 58 | "r": "history", 59 | } 60 | 61 | if attr in attr_alias: 62 | return attr_alias[attr] 63 | 64 | return attr 65 | 66 | 67 | def rsetattr(obj, attr, new_val, operation): 68 | # if not _check_allowed_field(attr): 69 | # raise AttributeError("Unknown field {}".format(attr)) 70 | 71 | pre, _, post = attr.rpartition(".") 72 | 73 | pre_post = None 74 | if len(attr.split(".")) > 3: 75 | pre_post = post 76 | pre, _, post = pre.rpartition(".") 77 | 78 | post = _get_alias(post) 79 | 80 | try: 81 | obj_to_set = rgetattr(obj, pre) if pre else obj 82 | prev_val = rgetattr(obj, attr) 83 | if pre_post is not None: 84 | prev_val = DotDict({pre_post: prev_val}) 85 | 86 | if operation is not None: 87 | val = operation(prev_val, new_val) 88 | else: 89 | if isinstance(prev_val, DotDict): 90 | val = {k: new_val for k, v in prev_val.items()} 91 | else: 92 | val = new_val 93 | 94 | return setattr(obj_to_set, post, val) 95 | except AttributeError: 96 | raise AttributeError( 97 | "rsetattr: Can't set '{}' attribute of {}.".format( 98 | post, obj_to_set.__class__ 99 | ) 100 | ) 101 | 102 | 103 | def rgetattr(obj, attr, *args): 104 | def _getattr(obj, attr): 105 | attr = _get_alias(attr) 106 | try: 107 | return getattr(obj, attr, *args) 108 | except AttributeError: 109 | raise AttributeError( 110 | "rgetattr: Can't get '{}' attribute from '{}'.".format( 111 | attr, obj.__class__ 112 | ) 113 | ) 114 | 115 | # if not _check_allowed_field(attr): 116 | # raise AttributeError("Unknown field {}".format(attr)) 117 | 118 | return functools.reduce(_getattr, [obj] + attr.split(".")) 119 | -------------------------------------------------------------------------------- /src/wfuzz/helpers/str_func.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sys 3 | import six 4 | 5 | 6 | from .obj_dic import DotDict 7 | 8 | 9 | def json_minify(string, strip_space=True): 10 | """ 11 | Created on 20/01/2011 12 | v0.2 (C) Gerald Storer 13 | MIT License 14 | Based on JSON.minify.js: 15 | https://github.com/getify/JSON.minify 16 | Contributers: 17 | - Pradyun S. Gedam (conditions and variable names changed) 18 | """ 19 | 20 | tokenizer = re.compile(r'"|(/\*)|(\*/)|(//)|\n|\r') 21 | end_slashes_re = re.compile(r"(\\)*$") 22 | 23 | in_string = False 24 | in_multi = False 25 | in_single = False 26 | 27 | new_str = [] 28 | index = 0 29 | 30 | for match in re.finditer(tokenizer, string): 31 | 32 | if not (in_multi or in_single): 33 | tmp = string[index : match.start()] 34 | if not in_string and strip_space: 35 | # replace white space as defined in standard 36 | tmp = re.sub("[ \t\n\r]+", "", tmp) 37 | new_str.append(tmp) 38 | 39 | index = match.end() 40 | val = match.group() 41 | 42 | if val == '"' and not (in_multi or in_single): 43 | escaped = end_slashes_re.search(string, 0, match.start()) 44 | 45 | # start of string or unescaped quote character to end string 46 | if not in_string or (escaped is None or len(escaped.group()) % 2 == 0): 47 | in_string = not in_string 48 | # include " character in next catch 49 | index -= 1 50 | elif not (in_string or in_multi or in_single): 51 | if val == "/*": 52 | in_multi = True 53 | elif val == "//": 54 | in_single = True 55 | elif val == "*/" and in_multi and not (in_string or in_single): 56 | in_multi = False 57 | elif val in "\r\n" and not (in_multi or in_string) and in_single: 58 | in_single = False 59 | elif not ((in_multi or in_single) or (val in " \r\n\t" and strip_space)): 60 | new_str.append(val) 61 | 62 | new_str.append(string[index:]) 63 | return "".join(new_str) 64 | 65 | 66 | def python2_3_convert_from_unicode(text): 67 | if sys.version_info >= (3, 0): 68 | return text 69 | else: 70 | return convert_to_unicode(text) 71 | 72 | 73 | def python2_3_convert_to_unicode(text): 74 | if sys.version_info >= (3, 0): 75 | return convert_to_unicode(text) 76 | else: 77 | return text 78 | 79 | 80 | def convert_to_unicode(text): 81 | if isinstance(text, dict) or isinstance(text, DotDict): 82 | return { 83 | convert_to_unicode(key): convert_to_unicode(value) 84 | for key, value in list(text.items()) 85 | } 86 | elif isinstance(text, list): 87 | return [convert_to_unicode(element) for element in text] 88 | elif isinstance(text, six.string_types): 89 | return text.encode("utf-8", errors="ignore") 90 | else: 91 | return text 92 | 93 | 94 | def value_in_any_list_item(value, list_obj): 95 | if isinstance(list_obj, list): 96 | return len([item for item in list_obj if value.lower() in item.lower()]) > 0 97 | elif isinstance(list_obj, str): 98 | return value.lower() in list_obj.lower() 99 | -------------------------------------------------------------------------------- /src/wfuzz/helpers/utils.py: -------------------------------------------------------------------------------- 1 | from threading import Lock 2 | import difflib 3 | 4 | 5 | class MyCounter: 6 | def __init__(self, count=0): 7 | self._count = count 8 | self._mutex = Lock() 9 | 10 | def inc(self): 11 | return self._operation(1) 12 | 13 | def dec(self): 14 | return self._operation(-1) 15 | 16 | def _operation(self, dec): 17 | with self._mutex: 18 | self._count += dec 19 | return self._count 20 | 21 | def __call__(self): 22 | with self._mutex: 23 | return self._count 24 | 25 | 26 | def diff(param1, param2): 27 | delta = difflib.unified_diff( 28 | str(param1).splitlines(False), 29 | str(param2).splitlines(False), 30 | fromfile="prev", 31 | tofile="current", 32 | n=0, 33 | ) 34 | 35 | return "\n".join(delta) 36 | -------------------------------------------------------------------------------- /src/wfuzz/mixins.py: -------------------------------------------------------------------------------- 1 | from .plugin_api.urlutils import parse_url 2 | from .exception import FuzzExceptBadInstall 3 | 4 | # python 2 and 3 5 | import sys 6 | 7 | if sys.version_info >= (3, 0): 8 | from urllib.parse import urljoin, urlparse 9 | else: 10 | from urlparse import urljoin, urlparse 11 | 12 | 13 | class FuzzRequestSoupMixing(object): 14 | def get_soup(self): 15 | try: 16 | from bs4 import BeautifulSoup 17 | except ImportError: 18 | raise FuzzExceptBadInstall("You need to install beautifulsoup4 first!") 19 | 20 | soup = BeautifulSoup(self.content, "html.parser") 21 | 22 | return soup 23 | 24 | 25 | class FuzzRequestUrlMixing(object): 26 | # urlparse functions 27 | @property 28 | def urlparse(self): 29 | return parse_url(self.url) 30 | 31 | @property 32 | def urlp(self): 33 | return parse_url(self.url) 34 | 35 | @property 36 | def pstrip(self): 37 | return self.to_cache_key() 38 | 39 | @property 40 | def is_path(self): 41 | if self.recursive_url and self.recursive_url[-1] == "/": 42 | return True 43 | 44 | return False 45 | 46 | @property 47 | def recursive_url(self): 48 | if self.code >= 300 and self.code < 308 and "Location" in self.headers.response: 49 | location_url = self.headers.response["Location"] 50 | location_parsed_url = urlparse(location_url) 51 | 52 | if not location_parsed_url.scheme and not location_parsed_url.netloc: 53 | return urljoin(self.url, location_url) 54 | elif self.code in [200, 401] and self.url[-1] == "/": 55 | return self.url 56 | 57 | return None 58 | -------------------------------------------------------------------------------- /src/wfuzz/plugin_api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/plugin_api/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/plugin_api/mixins.py: -------------------------------------------------------------------------------- 1 | # Plugins specializations with common methods useful for their own type 2 | from wfuzz.plugin_api.urlutils import parse_url 3 | from .base import BasePlugin 4 | 5 | 6 | class DiscoveryPluginMixin: 7 | def queue_url(self, url): 8 | if not parse_url(url).isbllist: 9 | BasePlugin.queue_url(self, url) 10 | return True 11 | return False 12 | -------------------------------------------------------------------------------- /src/wfuzz/plugin_api/urlutils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | # Python 2 and 3 5 | import sys 6 | 7 | if sys.version_info >= (3, 0): 8 | from urllib.parse import ParseResult 9 | from urllib.parse import urlparse 10 | from urllib.parse import parse_qs 11 | else: 12 | from urlparse import ParseResult 13 | from urlparse import urlparse 14 | from urlparse import parse_qs 15 | 16 | from wfuzz.facade import Facade 17 | from wfuzz.exception import FuzzExceptBadAPI 18 | 19 | 20 | class FuzzRequestParse(ParseResult): 21 | @property 22 | def ffname(self): 23 | """ 24 | Returns script plus extension from an URL. ie. http://www.localhost.com/kk/index.html?id=3 25 | will return index.html 26 | """ 27 | u = self.path.split("/")[-1:][0] 28 | 29 | return u 30 | 31 | @property 32 | def fext(self): 33 | """ 34 | Returns script extension from an URL. ie. http://www.localhost.com/kk/index.html?id=3 35 | will return .html 36 | """ 37 | return os.path.splitext(self.ffname)[1] 38 | 39 | @property 40 | def fname(self): 41 | """ 42 | Returns script name from an URL. ie. http://www.localhost.com/kk/index.html?id=3 43 | will return index 44 | """ 45 | return os.path.splitext(self.ffname)[0] 46 | 47 | @property 48 | def isbllist(self): 49 | fext = self.fext 50 | return fext != "." and fext in Facade().sett.get( 51 | "kbase", "discovery.blacklist" 52 | ).split("-") 53 | 54 | @property 55 | def hasquery(self): 56 | return self.query != "" 57 | 58 | def cache_key(self, base_urlp=None): 59 | scheme = self.scheme 60 | netloc = self.netloc 61 | 62 | if base_urlp: 63 | scheme = self.scheme if self.scheme else base_urlp.scheme 64 | netloc = self.netloc if self.netloc else base_urlp.netloc 65 | 66 | key = "{}-{}-{}-{}".format(scheme, netloc, self.path, self.params) 67 | dicc = {"g{}".format(key): True for key in parse_qs(self.query).keys()} 68 | 69 | # take URL parameters into consideration 70 | url_params = list(dicc.keys()) 71 | url_params.sort() 72 | key += "-" + "-".join(url_params) 73 | 74 | return key 75 | 76 | 77 | def parse_url(url): 78 | # >>> urlparse.urlparse("http://some.page.pl/nothing.py;someparam=some;otherparam=other?query1=val1&query2=val2#frag") 79 | # ParseResult(scheme='http', netloc='some.page.pl', path='/nothing.py', params='someparam=some;otherparam=other', query='query1=val1&query2=val2', fragment='frag') 80 | 81 | scheme, netloc, path, params, query, fragment = urlparse(url) 82 | return FuzzRequestParse(scheme, netloc, path, params, query, fragment) 83 | 84 | 85 | def check_content_type(fuzzresult, which): 86 | ctype = None 87 | if "Content-Type" in fuzzresult.history.headers.response: 88 | ctype = fuzzresult.history.headers.response["Content-Type"] 89 | 90 | if which == "text": 91 | return not ctype or ( 92 | ctype and any([ctype.find(x) >= 0 for x in ["text/plain"]]) 93 | ) 94 | else: 95 | raise FuzzExceptBadAPI("Unknown content type") 96 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/plugins/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/plugins/encoders/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/plugins/encoders/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/plugins/iterators/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/plugins/iterators/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/plugins/iterators/iterations.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.dictionaries import BaseIterator 3 | 4 | import itertools 5 | from functools import reduce 6 | 7 | from builtins import zip as builtinzip 8 | 9 | 10 | @moduleman_plugin 11 | class zip(BaseIterator): 12 | name = "zip" 13 | author = ("Xavi Mendez (@xmendez)",) 14 | version = "0.1" 15 | summary = "Returns an iterator that aggregates elements from each of the iterables." 16 | category = ["default"] 17 | priority = 99 18 | 19 | def __init__(self, *i): 20 | self._payload_list = i 21 | self.__width = len(i) 22 | self.__count = min([x.count() for x in i]) 23 | self.it = builtinzip(*i) 24 | 25 | def count(self): 26 | return self.__count 27 | 28 | def width(self): 29 | return self.__width 30 | 31 | def payloads(self): 32 | return self._payload_list 33 | 34 | def __next__(self): 35 | return next(self.it) 36 | 37 | def __iter__(self): 38 | return self 39 | 40 | 41 | @moduleman_plugin 42 | class product(BaseIterator): 43 | name = "product" 44 | author = ("Xavi Mendez (@xmendez)",) 45 | version = "0.1" 46 | summary = "Returns an iterator cartesian product of input iterables." 47 | category = ["default"] 48 | priority = 99 49 | 50 | def __init__(self, *i): 51 | self._payload_list = i 52 | self.__width = len(i) 53 | self.__count = reduce(lambda x, y: x * y.count(), i[1:], i[0].count()) 54 | self.it = itertools.product(*i) 55 | 56 | def count(self): 57 | return self.__count 58 | 59 | def width(self): 60 | return self.__width 61 | 62 | def payloads(self): 63 | return self._payload_list 64 | 65 | def __next__(self): 66 | return next(self.it) 67 | 68 | def __iter__(self): 69 | return self 70 | 71 | 72 | @moduleman_plugin 73 | class chain(BaseIterator): 74 | name = "chain" 75 | author = ("Xavi Mendez (@xmendez)",) 76 | version = "0.1" 77 | summary = "Returns an iterator returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted." 78 | category = ["default"] 79 | priority = 99 80 | 81 | def __init__(self, *i): 82 | self._payload_list = i 83 | self.__count = sum([x.count() for x in i]) 84 | self.it = itertools.chain(*i) 85 | 86 | def count(self): 87 | return self.__count 88 | 89 | def width(self): 90 | return 1 91 | 92 | def payloads(self): 93 | return self._payload_list 94 | 95 | def __next__(self): 96 | return (next(self.it),) 97 | 98 | def __iter__(self): 99 | return self 100 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/plugins/payloads/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/autorize.py: -------------------------------------------------------------------------------- 1 | import re 2 | import base64 3 | 4 | from wfuzz.exception import FuzzExceptBadFile 5 | from wfuzz.fuzzobjects import FuzzResult, FuzzWordType 6 | from wfuzz.fuzzrequest import FuzzRequest 7 | from wfuzz.plugin_api.base import BasePayload 8 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 9 | from wfuzz.helpers.obj_dyn import rgetattr 10 | 11 | 12 | @moduleman_plugin 13 | class autorize(BasePayload): 14 | name = "autorize" 15 | author = ("Xavi Mendez (@xmendez)",) 16 | version = "0.2" 17 | description = ("Reads burp extension autorize states",) 18 | summary = "Returns fuzz results' from autorize." 19 | category = ["default"] 20 | priority = 99 21 | 22 | parameters = ( 23 | ("fn", "", True, "Filename of a valid autorize state file."), 24 | ( 25 | "attr", 26 | None, 27 | False, 28 | "Attribute of fuzzresult to return. If not specified the whole object is returned.", 29 | ), 30 | ) 31 | 32 | default_parameter = "fn" 33 | 34 | def __init__(self, params): 35 | BasePayload.__init__(self, params) 36 | 37 | self.__max = -1 38 | self.attr = self.params["attr"] 39 | self._it = self._gen_wfuzz(self.params["fn"]) 40 | 41 | def count(self): 42 | return self.__max 43 | 44 | def get_next(self): 45 | next_item = next(self._it) 46 | 47 | return next_item if not self.attr else rgetattr(next_item, self.attr) 48 | 49 | def get_type(self): 50 | return FuzzWordType.WORD 51 | 52 | def _gen_wfuzz(self, output_fn): 53 | try: 54 | 55 | with open(self.find_file(output_fn), "r") as f: 56 | for ( 57 | url1, 58 | port1, 59 | schema1, 60 | req1, 61 | resp1, 62 | url2, 63 | port2, 64 | schema2, 65 | req2, 66 | resp2, 67 | url3, 68 | port3, 69 | schema3, 70 | req3, 71 | resp3, 72 | res1, 73 | res2, 74 | ) in [re.split(r"\t+", x) for x in f.readlines()]: 75 | raw_req1 = base64.decodestring(req2) 76 | # raw_res1 = base64.decodestring(res2) 77 | 78 | item = FuzzResult() 79 | item.history = FuzzRequest() 80 | item.history.update_from_raw_http(raw_req1, schema1) 81 | 82 | yield item 83 | except IOError as e: 84 | raise FuzzExceptBadFile("Error opening wfuzz payload file. %s" % str(e)) 85 | except EOFError: 86 | raise StopIteration 87 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/bing.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.payloadtools import BingIter 3 | from wfuzz.plugin_api.base import BasePayload 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | 7 | @moduleman_plugin 8 | class bing(BasePayload): 9 | name = "bing" 10 | author = ("Xavi Mendez (@xmendez)",) 11 | version = "0.2" 12 | description = ( 13 | 'intitle:"JBoss JMX Management Console"', 14 | "Some examples of bing hacking:", 15 | "http://www.elladodelmal.com/2010/02/un-poco-de-bing-hacking-i-de-iii.html", 16 | ) 17 | 18 | summary = "Returns URL results of a given bing API search (needs api key)." 19 | category = ["default"] 20 | priority = 99 21 | 22 | parameters = ( 23 | ("dork", "", True, "Google dork search string."), 24 | ("offset", "0", False, "Offset index, starting at zero."), 25 | ("limit", "0", False, "Number of results. Zero for all."), 26 | ) 27 | 28 | default_parameter = "dork" 29 | 30 | def __init__(self, params): 31 | BasePayload.__init__(self, params) 32 | 33 | offset = int(params["offset"]) 34 | limit = int(params["limit"]) 35 | 36 | self._it = BingIter(params["dork"], offset, limit) 37 | 38 | def count(self): 39 | return self._it.max_count 40 | 41 | def get_next(self): 42 | return next(self._it) 43 | 44 | def get_type(self): 45 | return FuzzWordType.WORD 46 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/buffer_overflow.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.fuzzobjects import FuzzWordType 4 | 5 | 6 | @moduleman_plugin 7 | class buffer_overflow(BasePayload): 8 | name = "buffer_overflow" 9 | author = ("Xavi Mendez (@xmendez)",) 10 | version = "0.2" 11 | description = () 12 | summary = "Returns a string using the following pattern A * given number." 13 | category = ["default"] 14 | priority = 99 15 | 16 | parameters = (("size", "", True, "Size of the overflow string."),) 17 | 18 | default_parameter = "size" 19 | 20 | def __init__(self, params): 21 | BasePayload.__init__(self, params) 22 | 23 | self.bov_list = ["A" * int(self.params["size"])] 24 | self.current = 0 25 | 26 | def count(self): 27 | return 1 28 | 29 | def get_next(self): 30 | if self.current == 0: 31 | elem = self.bov_list[self.current] 32 | self.current += 1 33 | return elem 34 | else: 35 | raise StopIteration 36 | 37 | def get_type(self): 38 | return FuzzWordType.WORD 39 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/burpitem.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.exception import FuzzExceptBadFile 3 | from wfuzz.fuzzobjects import FuzzResult, FuzzWordType 4 | from wfuzz.fuzzrequest import FuzzRequest 5 | from wfuzz.plugin_api.base import BasePayload 6 | from wfuzz.helpers.obj_dyn import rgetattr 7 | import xml.etree.cElementTree as ET 8 | from base64 import b64decode 9 | 10 | 11 | @moduleman_plugin 12 | class burpitem(BasePayload): 13 | name = "burpitem" 14 | author = ("Bendegúz Nagy (@PaperTsar)",) 15 | version = "0.1" 16 | description = ( 17 | "This payload loads request/response from items saved from Burpsuite.", 18 | ) 19 | summary = "This payload loads request/response from items saved from Burpsuite." 20 | category = ["default"] 21 | priority = 99 22 | 23 | parameters = ( 24 | ("fn", "", True, "Filename of a valid Burp item file."), 25 | ( 26 | "attr", 27 | None, 28 | False, 29 | "Attribute of fuzzresult to return. If not specified the whole object is returned.", 30 | ), 31 | ) 32 | 33 | default_parameter = "fn" 34 | 35 | def __init__(self, params): 36 | BasePayload.__init__(self, params) 37 | 38 | self.__max = -1 39 | self.attr = self.params["attr"] 40 | self._it = self._gen_burpitem(self.params["fn"]) 41 | 42 | def count(self): 43 | return self.__max 44 | 45 | def get_next(self): 46 | next_item = next(self._it) 47 | 48 | return next_item if not self.attr else rgetattr(next_item, self.attr) 49 | 50 | def get_type(self): 51 | return FuzzWordType.FUZZRES if not self.attr else FuzzWordType.WORD 52 | 53 | def _gen_burpitem(self, output_fn): 54 | try: 55 | tree = ET.parse(self.find_file(output_fn)) 56 | for item in tree.getroot().iter("item"): 57 | fr = FuzzRequest() 58 | fr.update_from_raw_http( 59 | raw=b64decode(item.find("request").text or "").decode("utf-8"), 60 | scheme=item.find("protocol").text, 61 | raw_response=b64decode(item.find("response").text or ""), 62 | ) 63 | fr.wf_ip = { 64 | "ip": item.find("host").attrib.get("ip", None) 65 | or item.find("host").text, 66 | "port": item.find("port").text, 67 | } 68 | frr = FuzzResult(history=fr) 69 | 70 | yield frr.update() 71 | return 72 | except IOError as e: 73 | raise FuzzExceptBadFile( 74 | "Error opening Burp items payload file. %s" % str(e) 75 | ) 76 | except EOFError: 77 | return 78 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/dirwalk.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.fuzzobjects import FuzzWordType 4 | 5 | import os 6 | 7 | # Python 2 and 3: alternative 4 8 | try: 9 | from urllib.parse import quote 10 | except ImportError: 11 | from urllib import quote 12 | 13 | 14 | @moduleman_plugin 15 | class dirwalk(BasePayload): 16 | name = "dirwalk" 17 | author = ("Xavi Mendez (@xmendez)",) 18 | version = "0.1" 19 | description = ( 20 | "Returns all the file paths found in the specified directory.", 21 | "Handy if you want to check a directory structure against a webserver,", 22 | "for example, because you have previously downloaded a specific version", 23 | "of what is supposed to be on-line.", 24 | ) 25 | summary = "Returns filename's recursively from a local directory." 26 | category = ["default"] 27 | priority = 99 28 | 29 | parameters = ( 30 | ("dir", "", True, "Directory path to walk and generate payload from."), 31 | ) 32 | 33 | default_parameter = "dir" 34 | 35 | def __init__(self, params): 36 | BasePayload.__init__(self, params) 37 | 38 | self.g = self._my_gen(self.params["dir"]) 39 | 40 | def _my_gen(self, directory): 41 | for root, dirs, fnames in os.walk(directory): 42 | for f in fnames: 43 | relative_path = os.path.relpath(os.path.join(root, f), directory) 44 | yield quote(relative_path) 45 | 46 | def get_next(self): 47 | return next(self.g) 48 | 49 | def get_type(self): 50 | return FuzzWordType.WORD 51 | 52 | def count(self): 53 | return -1 54 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/file.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.exception import FuzzExceptBadFile 3 | from wfuzz.plugin_api.base import BasePayload 4 | from wfuzz.helpers.file_func import FileDetOpener 5 | from wfuzz.fuzzobjects import FuzzWordType 6 | 7 | 8 | @moduleman_plugin 9 | class file(BasePayload): 10 | name = "file" 11 | author = ( 12 | "Carlos del Ojo", 13 | "Christian Martorella", 14 | "Adapted to newer versions Xavi Mendez (@xmendez)", 15 | ) 16 | version = "0.2" 17 | description = ("Returns the contents of a dictionary file line by line.",) 18 | summary = "Returns each word from a file." 19 | category = ["default"] 20 | priority = 99 21 | 22 | parameters = ( 23 | ("fn", "", True, "Filename of a valid dictionary"), 24 | ( 25 | "count", 26 | "True", 27 | False, 28 | "Indicates if the number of words in the file should be counted.", 29 | ), 30 | ("encoding", "Auto", False, "Indicates the file encoding."), 31 | ) 32 | 33 | default_parameter = "fn" 34 | 35 | def __init__(self, params): 36 | BasePayload.__init__(self, params) 37 | 38 | try: 39 | encoding = ( 40 | self.params["encoding"] 41 | if self.params["encoding"].lower() != "auto" 42 | else None 43 | ) 44 | self.f = FileDetOpener(self.find_file(self.params["fn"]), encoding) 45 | except IOError as e: 46 | raise FuzzExceptBadFile("Error opening file. %s" % str(e)) 47 | 48 | self.__count = None 49 | 50 | def get_type(self): 51 | return FuzzWordType.WORD 52 | 53 | def get_next(self): 54 | line = next(self.f) 55 | if not line: 56 | self.f.close() 57 | raise StopIteration 58 | return line.strip() 59 | 60 | def count(self): 61 | if self.params["count"].lower() == "false": 62 | return -1 63 | 64 | if self.__count is None: 65 | self.__count = len(list(self.f)) 66 | self.f.reset() 67 | 68 | return self.__count 69 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/guitab.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.fuzzobjects import FuzzWordType 4 | 5 | from wfuzz.facade import Facade 6 | 7 | 8 | @moduleman_plugin 9 | class guitab(BasePayload): 10 | name = "guitab" 11 | author = ("Xavi Mendez (@xmendez)",) 12 | version = "0.1" 13 | description = ( 14 | "** This is a beta plugin for the GUI under construction.", 15 | "This payload reads requests from a tab in the GUI", 16 | ) 17 | summary = "This payload reads requests from a tab in the GUI" 18 | category = ["default"] 19 | priority = 99 20 | 21 | parameters = ( 22 | ("tab", "", True, "Name of a valid GUI tab."), 23 | ( 24 | "attr", 25 | None, 26 | False, 27 | "Attribute of fuzzresult to return. If not specified the whole object is returned.", 28 | ), 29 | ) 30 | 31 | default_parameter = "tab" 32 | 33 | def __init__(self, params): 34 | BasePayload.__init__(self, params) 35 | 36 | self.attr = self.params["attr"] 37 | self._it = iter(Facade().data[self.params["tab"]]) 38 | 39 | def count(self): 40 | return len(Facade().data[self.params["tab"]]) 41 | 42 | def get_type(self): 43 | return FuzzWordType.WORD 44 | 45 | def get_next(self): 46 | next_item = next(self._it) 47 | 48 | return next_item if not self.attr else next_item.get_field(self.attr) 49 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/hexrand.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.exception import FuzzExceptPluginBadParams 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | import random 7 | 8 | 9 | @moduleman_plugin 10 | class hexrand(BasePayload): 11 | name = "hexrand" 12 | author = ( 13 | "Carlos del Ojo", 14 | "Christian Martorella", 15 | "Adapted to newer versions Xavi Mendez (@xmendez)", 16 | ) 17 | version = "0.1" 18 | description = () 19 | summary = "Returns random hex numbers from the given range." 20 | category = ["default"] 21 | priority = 99 22 | 23 | parameters = ( 24 | ( 25 | "range", 26 | "", 27 | True, 28 | "Range of hex numbers to randomly generate in the form of 00-ff.", 29 | ), 30 | ) 31 | 32 | default_parameter = "range" 33 | 34 | def __init__(self, params): 35 | BasePayload.__init__(self, params) 36 | 37 | try: 38 | ran = self.params["range"].split("-") 39 | self.minimum = int(ran[0], 16) 40 | self.maximum = int(ran[1], 16) 41 | self.__count = -1 42 | except ValueError: 43 | raise FuzzExceptPluginBadParams('Bad range format (eg. "0-ffa")') 44 | 45 | def __iter__(self): 46 | return self 47 | 48 | def count(self): 49 | return self.__count 50 | 51 | def get_type(self): 52 | return FuzzWordType.WORD 53 | 54 | def get_next(self): 55 | self.current = random.SystemRandom().randint(self.minimum, self.maximum) 56 | 57 | lgth = len(hex(self.maximum).replace("0x", "")) 58 | pl = "%" + str(lgth) + "s" 59 | num = hex(self.current).replace("0x", "") 60 | pl = pl % (num) 61 | payl = pl.replace(" ", "0") 62 | 63 | return payl 64 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/hexrange.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.exception import FuzzExceptBadOptions 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | 7 | @moduleman_plugin 8 | class hexrange(BasePayload): 9 | name = "hexrange" 10 | author = ( 11 | "Carlos del Ojo", 12 | "Christian Martorella", 13 | "Adapted to newer versions Xavi Mendez (@xmendez)", 14 | ) 15 | version = "0.1" 16 | description = () 17 | summary = "Returns each hex number of the given hex range." 18 | category = ["default"] 19 | priority = 99 20 | 21 | parameters = ( 22 | ("range", "", True, "Range of hex numbers to generate in the form of 00-ff."), 23 | ) 24 | 25 | default_parameter = "range" 26 | 27 | def __init__(self, params): 28 | BasePayload.__init__(self, params) 29 | 30 | try: 31 | ran = self.params["range"].split("-") 32 | self.minimum = int(ran[0], 16) 33 | self.maximum = int(ran[1], 16) 34 | self.__count = self.maximum - self.minimum + 1 35 | self.current = self.minimum 36 | self.lgth = max( 37 | len(ran[0]), len(ran[1]), len(hex(self.maximum).replace("0x", "")) 38 | ) 39 | except ValueError: 40 | raise FuzzExceptBadOptions('Bad range format (eg. "0-ffa")') 41 | 42 | def count(self): 43 | return self.__count 44 | 45 | def get_type(self): 46 | return FuzzWordType.WORD 47 | 48 | def get_next(self): 49 | if self.current > self.maximum: 50 | raise StopIteration 51 | 52 | pl = "%" + str(self.lgth) + "s" 53 | num = hex(self.current).replace("0x", "") 54 | pl = pl % (num) 55 | payl = pl.replace(" ", "0") 56 | 57 | self.current += 1 58 | 59 | return payl 60 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/ipnet.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.exception import FuzzExceptPluginBadParams, FuzzExceptBadInstall 3 | from wfuzz.plugin_api.base import BasePayload 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | 7 | @moduleman_plugin 8 | class ipnet(BasePayload): 9 | name = "ipnet" 10 | author = ("Xavi Mendez (@xmendez)",) 11 | version = "0.1" 12 | description = ("ie. 192.168.1.0/24", "Requires: netaddr module") 13 | summary = "Returns list of IP addresses of a network." 14 | category = ["default"] 15 | priority = 99 16 | 17 | parameters = (("net", "", True, "Network range in the form ip/mask."),) 18 | 19 | default_parameter = "net" 20 | 21 | def __init__(self, params): 22 | BasePayload.__init__(self, params) 23 | 24 | try: 25 | from netaddr import IPNetwork 26 | from netaddr.core import AddrFormatError 27 | 28 | net = IPNetwork("%s" % self.params["net"]) 29 | self.f = net.iter_hosts() 30 | self.__count = net.size - 2 31 | 32 | if self.__count <= 0: 33 | raise FuzzExceptPluginBadParams( 34 | "There are not hosts in the specified network" 35 | ) 36 | 37 | except ValueError: 38 | raise FuzzExceptPluginBadParams( 39 | "The specified network has an incorrect format." 40 | ) 41 | except ImportError: 42 | raise FuzzExceptBadInstall( 43 | "ipnet plugin requires netaddr module. Please install it using pip." 44 | ) 45 | except AddrFormatError: 46 | raise FuzzExceptPluginBadParams( 47 | "The specified network has an incorrect format." 48 | ) 49 | 50 | def get_type(self): 51 | return FuzzWordType.WORD 52 | 53 | def get_next(self): 54 | return str(next(self.f)) 55 | 56 | def count(self): 57 | return self.__count 58 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/iprange.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.exception import FuzzExceptPluginBadParams, FuzzExceptBadInstall 3 | from wfuzz.plugin_api.base import BasePayload 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | 7 | @moduleman_plugin 8 | class iprange(BasePayload): 9 | name = "iprange" 10 | author = ("Xavi Mendez (@xmendez)",) 11 | version = "0.1" 12 | description = ( 13 | "ie. 192.168.1.0-192.168.1.12", 14 | "Requires: netaddr module", 15 | ) 16 | summary = "Returns list of IP addresses of a given IP range." 17 | category = ["default"] 18 | priority = 99 19 | 20 | parameters = ( 21 | ("iprange", "", True, "IP address range int the form 192.168.1.0-192.168.1.12"), 22 | ) 23 | 24 | default_parameter = "iprange" 25 | 26 | def __init__(self, params): 27 | BasePayload.__init__(self, params) 28 | 29 | try: 30 | from netaddr import IPRange 31 | from netaddr.core import AddrFormatError 32 | 33 | ran = self.params["iprange"].split("-") 34 | net = IPRange(ran[0], ran[1]) 35 | self.f = iter(net) 36 | self.__count = net.size 37 | except ImportError: 38 | raise FuzzExceptBadInstall( 39 | "ipnet plugin requires netaddr module. Please install it using pip." 40 | ) 41 | except AddrFormatError: 42 | raise FuzzExceptPluginBadParams( 43 | "The specified network range has an incorrect format." 44 | ) 45 | except IndexError: 46 | raise FuzzExceptPluginBadParams( 47 | "The specified network range has an incorrect format." 48 | ) 49 | 50 | def get_type(self): 51 | return FuzzWordType.WORD 52 | 53 | def get_next(self): 54 | return str(next(self.f)) 55 | 56 | def count(self): 57 | return self.__count 58 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/list.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.fuzzobjects import FuzzWordType 4 | 5 | 6 | @moduleman_plugin 7 | class list(BasePayload): 8 | name = "list" 9 | author = ("Xavi Mendez (@xmendez)",) 10 | version = "0.1" 11 | description = ("ie word1-word2",) 12 | summary = "Returns each element of the given word list separated by -." 13 | category = ["default"] 14 | priority = 99 15 | 16 | parameters = ( 17 | ("values", "", True, "Values separated by - to return as a dictionary."), 18 | ) 19 | 20 | default_parameter = "values" 21 | 22 | def __init__(self, params): 23 | BasePayload.__init__(self, params) 24 | 25 | if self.params["values"].find("\\") >= 0: 26 | self.params["values"] = self.params["values"].replace("\\-", "$SEP$") 27 | self.params["values"] = self.params["values"].replace("\\\\", "$SCAP$") 28 | 29 | self.value_list = self.params["values"].split("-") 30 | 31 | for i in range(len(self.value_list)): 32 | self.value_list[i] = self.value_list[i].replace("$SEP$", "-") 33 | self.value_list[i] = self.value_list[i].replace("$SCAP$", "\\") 34 | else: 35 | self.value_list = self.params["values"].split("-") 36 | 37 | self.__count = len(self.value_list) 38 | self.current = 0 39 | 40 | def count(self): 41 | return self.__count 42 | 43 | def get_type(self): 44 | return FuzzWordType.WORD 45 | 46 | def get_next(self): 47 | if self.current >= self.__count: 48 | raise StopIteration 49 | else: 50 | elem = self.value_list[self.current] 51 | self.current += 1 52 | return elem 53 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/names.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.fuzzobjects import FuzzWordType 4 | 5 | 6 | @moduleman_plugin 7 | class names(BasePayload): 8 | name = "names" 9 | author = ( 10 | "Christian Martorella", 11 | "Adapted to newer versions Xavi Mendez (@xmendez)", 12 | ) 13 | version = "0.1" 14 | description = ("ie. jon-smith",) 15 | summary = "Returns possible usernames by mixing the given words, separated by -, using known typical constructions." 16 | category = ["default"] 17 | priority = 99 18 | 19 | parameters = (("name", "", True, "Name and surname in the form of name-surname."),) 20 | 21 | default_parameter = "name" 22 | 23 | def __init__(self, params): 24 | BasePayload.__init__(self, params) 25 | 26 | possibleusernames = [] 27 | name = "" 28 | llist = self.params["name"].split("-") 29 | 30 | for x in llist: 31 | if name == "": 32 | name = name + x 33 | else: 34 | name = name + " " + x 35 | 36 | if " " in name: 37 | parts = name.split() 38 | possibleusernames.append(parts[0]) 39 | possibleusernames.append(parts[0] + "." + parts[1]) 40 | possibleusernames.append(parts[0] + parts[1]) 41 | possibleusernames.append(parts[0] + "." + parts[1][0]) 42 | possibleusernames.append(parts[0][0] + "." + parts[1]) 43 | possibleusernames.append(parts[0] + parts[1][0]) 44 | possibleusernames.append(parts[0][0] + parts[1]) 45 | str1 = "" 46 | str2 = "" 47 | str3 = "" 48 | str4 = "" 49 | for i in range(0, len(parts) - 1): 50 | str1 = str1 + parts[i] + "." 51 | str2 = str2 + parts[i] 52 | str3 = str3 + parts[i][0] + "." 53 | str4 = str4 + parts[i][0] 54 | str5 = str1 + parts[-1] 55 | str6 = str2 + parts[-1] 56 | str7 = str4 + parts[-1] 57 | str8 = str3 + parts[-1] 58 | str9 = str2 + parts[-1][0] 59 | str10 = str4 + parts[-1][0] 60 | possibleusernames.append(str5) 61 | possibleusernames.append(str6) 62 | possibleusernames.append(str7) 63 | possibleusernames.append(str8) 64 | possibleusernames.append(str9) 65 | possibleusernames.append(str10) 66 | possibleusernames.append(parts[-1]) 67 | possibleusernames.append(parts[0] + "." + parts[-1]) 68 | possibleusernames.append(parts[0] + parts[-1]) 69 | possibleusernames.append(parts[0] + "." + parts[-1][0]) 70 | possibleusernames.append(parts[0][0] + "." + parts[-1]) 71 | possibleusernames.append(parts[0] + parts[-1][0]) 72 | possibleusernames.append(parts[0][0] + parts[-1]) 73 | else: 74 | possibleusernames.append(name) 75 | 76 | self.creatednames = possibleusernames 77 | self.__count = len(possibleusernames) 78 | 79 | def count(self): 80 | return self.__count 81 | 82 | def get_type(self): 83 | return FuzzWordType.WORD 84 | 85 | def get_next(self): 86 | if self.creatednames: 87 | payl = self.creatednames.pop() 88 | return payl 89 | else: 90 | raise StopIteration 91 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/permutation.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.exception import FuzzExceptBadOptions 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | 7 | @moduleman_plugin 8 | class permutation(BasePayload): 9 | name = "permutation" 10 | author = ("Xavi Mendez (@xmendez)",) 11 | version = "0.1" 12 | description = () 13 | summary = "Returns permutations of the given charset and length." 14 | category = ["default"] 15 | priority = 99 16 | 17 | parameters = (("ch", "", True, "Charset and len to permute in the form of abc-2."),) 18 | 19 | default_parameter = "ch" 20 | 21 | def __init__(self, params): 22 | BasePayload.__init__(self, params) 23 | self.charset = [] 24 | 25 | try: 26 | ran = self.params["ch"].split("-") 27 | self.charset = ran[0] 28 | self.width = int(ran[1]) 29 | except ValueError: 30 | raise FuzzExceptBadOptions('Bad range format (eg. "0-ffa")') 31 | 32 | pset = [] 33 | for x in self.charset: 34 | pset.append(x) 35 | 36 | words = self.xcombinations(pset, self.width) 37 | self.lista = [] 38 | for x in words: 39 | self.lista.append("".join(x)) 40 | 41 | self.__count = len(self.lista) 42 | 43 | def count(self): 44 | return self.__count 45 | 46 | def get_type(self): 47 | return FuzzWordType.WORD 48 | 49 | def get_next(self): 50 | if self.lista != []: 51 | payl = self.lista.pop() 52 | return payl 53 | else: 54 | raise StopIteration 55 | 56 | def xcombinations(self, items, n): 57 | if n == 0: 58 | yield [] 59 | else: 60 | for i in range(len(items)): 61 | for cc in self.xcombinations(items[:i] + items[i:], n - 1): 62 | yield [items[i]] + cc 63 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/range.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.exception import FuzzExceptPluginBadParams 3 | from wfuzz.plugin_api.base import BasePayload 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | 7 | @moduleman_plugin 8 | class range(BasePayload): 9 | name = "range" 10 | author = ( 11 | "Carlos del Ojo", 12 | "Christian Martorella", 13 | "Adapted to newer versions Xavi Mendez (@xmendez)", 14 | ) 15 | version = "0.1" 16 | description = ("ie. 0-10",) 17 | summary = "Returns each number of the given range." 18 | category = ["default"] 19 | priority = 99 20 | 21 | parameters = (("range", "", True, "Range of numbers in the form 0-10."),) 22 | 23 | default_parameter = "range" 24 | 25 | def __init__(self, params): 26 | BasePayload.__init__(self, params) 27 | 28 | try: 29 | ran = self.params["range"].split("-") 30 | self.minimum = int(ran[0]) 31 | self.maximum = int(ran[1]) 32 | self.__count = self.maximum - self.minimum + 1 33 | self.width = len(ran[0]) 34 | self.current = self.minimum 35 | except ValueError: 36 | raise FuzzExceptPluginBadParams('Bad range format (eg. "23-56")') 37 | 38 | def get_type(self): 39 | return FuzzWordType.WORD 40 | 41 | def get_next(self): 42 | if self.current > self.maximum: 43 | raise StopIteration 44 | else: 45 | if self.width: 46 | payl = "%0" + str(self.width) + "d" 47 | payl = payl % (self.current) 48 | else: 49 | payl = str(self.current) 50 | 51 | self.current += 1 52 | return payl 53 | 54 | def count(self): 55 | return self.__count 56 | 57 | def __iter__(self): 58 | return self 59 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/shodanp.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.payloadtools import ShodanIter 3 | from wfuzz.plugin_api.base import BasePayload 4 | from wfuzz.fuzzobjects import FuzzWordType 5 | 6 | 7 | @moduleman_plugin 8 | class shodanp(BasePayload): 9 | name = "shodanp" 10 | author = ("Xavi Mendez (@xmendez)",) 11 | version = "0.1" 12 | description = ("Queries the Shodan API",) 13 | 14 | summary = "Returns URLs of a given Shodan API search (needs api key)." 15 | category = ["default"] 16 | priority = 99 17 | 18 | parameters = ( 19 | ("search", "", True, "Shodan search string."), 20 | ("page", "0", False, "Offset page, starting at zero."), 21 | ( 22 | "limit", 23 | "0", 24 | False, 25 | "Number of pages (1 query credit = 100 results). Zero for all.", 26 | ), 27 | ) 28 | 29 | default_parameter = "search" 30 | 31 | def __init__(self, params): 32 | BasePayload.__init__(self, params) 33 | 34 | search = params["search"] 35 | page = int(params["page"]) 36 | limit = int(params["limit"]) 37 | 38 | self._it = ShodanIter(search, page, limit) 39 | 40 | def count(self): 41 | return -1 42 | 43 | def close(self): 44 | self._it._stop() 45 | 46 | def get_type(self): 47 | return FuzzWordType.WORD 48 | 49 | def get_next(self): 50 | match = next(self._it) 51 | 52 | port = match["port"] 53 | scheme = "https" if "ssl" in match or port == 443 else "http" 54 | 55 | if match["hostnames"]: 56 | for hostname in match["hostnames"]: 57 | return "{}://{}:{}".format(scheme, hostname, port) 58 | else: 59 | return "{}://{}:{}".format(scheme, match["ip_str"], port) 60 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/stdin.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePayload 3 | from wfuzz.fuzzobjects import FuzzWordType 4 | 5 | import sys 6 | 7 | 8 | @moduleman_plugin 9 | class stdin(BasePayload): 10 | name = "stdin" 11 | author = ("Xavi Mendez (@xmendez)",) 12 | version = "0.1" 13 | description = () 14 | summary = "Returns each item read from stdin." 15 | category = ["default"] 16 | priority = 99 17 | 18 | parameters = () 19 | 20 | default_parameter = "" 21 | 22 | def __init__(self, params): 23 | BasePayload.__init__(self, params) 24 | self.__count = -1 25 | 26 | def count(self): 27 | return self.__count 28 | 29 | def get_type(self): 30 | return FuzzWordType.WORD 31 | 32 | def get_next(self): 33 | line = next(sys.stdin).strip() 34 | 35 | return line 36 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/payloads/wfuzzp.py: -------------------------------------------------------------------------------- 1 | import pickle as pickle 2 | import gzip 3 | 4 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 5 | from wfuzz.exception import FuzzExceptBadFile 6 | from wfuzz.fuzzobjects import FuzzResult, FuzzWordType 7 | from wfuzz.plugin_api.base import BasePayload 8 | from wfuzz.helpers.obj_dyn import rgetattr 9 | 10 | 11 | @moduleman_plugin 12 | class wfuzzp(BasePayload): 13 | name = "wfuzzp" 14 | author = ("Xavi Mendez (@xmendez)",) 15 | version = "0.2" 16 | description = ( 17 | "This payload uses pickle.", 18 | "Warning: The pickle module is not intended to be secure against erroneous or maliciously constructed data.", 19 | "Never unpickle data received from an untrusted or unauthenticated source.", 20 | "See: https://blog.nelhage.com/2011/03/exploiting-pickle/", 21 | ) 22 | summary = "Returns fuzz results' URL from a previous stored wfuzz session." 23 | category = ["default"] 24 | priority = 99 25 | 26 | parameters = ( 27 | ("fn", "", True, "Filename of a valid wfuzz result file."), 28 | ( 29 | "attr", 30 | None, 31 | False, 32 | "Attribute of fuzzresult to return. If not specified the whole object is returned.", 33 | ), 34 | ) 35 | 36 | default_parameter = "fn" 37 | 38 | def __init__(self, params): 39 | BasePayload.__init__(self, params) 40 | 41 | self.__max = -1 42 | self.attr = self.params["attr"] 43 | self._it = self._gen_wfuzz(self.params["fn"]) 44 | 45 | def count(self): 46 | return self.__max 47 | 48 | def get_next(self): 49 | next_item = next(self._it) 50 | 51 | return next_item if not self.attr else rgetattr(next_item, self.attr) 52 | 53 | def get_type(self): 54 | return FuzzWordType.FUZZRES if not self.attr else FuzzWordType.WORD 55 | 56 | def _gen_wfuzz(self, output_fn): 57 | try: 58 | with gzip.open(self.find_file(output_fn), "r+b") as output: 59 | while 1: 60 | item = pickle.load(output) 61 | if not isinstance(item, FuzzResult): 62 | raise FuzzExceptBadFile( 63 | "Wrong wfuzz payload format, the object read is not a valid fuzz result." 64 | ) 65 | 66 | yield item 67 | except IOError as e: 68 | raise FuzzExceptBadFile("Error opening wfuzz payload file. %s" % str(e)) 69 | except EOFError: 70 | return 71 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/printers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/plugins/printers/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/plugins/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmendez/wfuzz/1b695ee9a87d66a7d7bf6cae70d60a33fae51541/src/wfuzz/plugins/scripts/__init__.py -------------------------------------------------------------------------------- /src/wfuzz/plugins/scripts/backups.py: -------------------------------------------------------------------------------- 1 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 2 | from wfuzz.plugin_api.base import BasePlugin 3 | 4 | # Python 2 and 3 5 | try: 6 | from urllib.parse import urljoin 7 | except ImportError: 8 | from urlparse import urljoin 9 | 10 | 11 | @moduleman_plugin 12 | class backups(BasePlugin): 13 | name = "backups" 14 | summary = "Looks for known backup filenames." 15 | description = ("Looks for known backup filenames.",) 16 | "For example, given http://localhost.com/dir/index.html, it will perform the following requests", 17 | "* http://localhost/dir/index.EXTENSIONS", 18 | "* http://localhost/dir/index.html.EXTENSIONS", 19 | "* http://localhost/dir.EXTENSIONS", 20 | author = ("Xavi Mendez (@xmendez)",) 21 | version = "0.1" 22 | category = ["fuzzer", "active"] 23 | priority = 99 24 | 25 | parameters = ( 26 | ( 27 | "ext", 28 | ".bak,.tgz,.zip,.tar.gz,~,.rar,.old,.-.swp", 29 | False, 30 | "Extensions to look for.", 31 | ), 32 | ) 33 | 34 | def __init__(self): 35 | BasePlugin.__init__(self) 36 | self.extensions = self.kbase["backups.ext"][0].split(",") 37 | 38 | def validate(self, fuzzresult): 39 | return fuzzresult.code != 404 and ( 40 | fuzzresult.history.urlparse.fext not in self.extensions 41 | ) 42 | 43 | def process(self, fuzzresult): 44 | # >>> urlparse.urlparse("http://www.localhost.com/kk/index.html?id=1") 45 | # ParseResult(scheme='http', netloc='www.localhost.com', path='/kk/index.html', params='', query='id=1', fragment='') 46 | 47 | for pre_extension in self.extensions: 48 | pre, nothing, extension = pre_extension.partition("-") 49 | 50 | # http://localhost/dir/test.html -----> test.BAKKK 51 | self.queue_url( 52 | urljoin( 53 | fuzzresult.url, pre + fuzzresult.history.urlparse.fname + extension 54 | ) 55 | ) 56 | 57 | # http://localhost/dir/test.html ---> test.html.BAKKK 58 | self.queue_url( 59 | urljoin(fuzzresult.url, fuzzresult.history.urlparse.ffname + extension) 60 | ) 61 | 62 | # http://localhost/dir/test.html ----> dir.BAKKK 63 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/scripts/cookies.py: -------------------------------------------------------------------------------- 1 | from wfuzz.plugin_api.base import BasePlugin 2 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 3 | 4 | 5 | KBASE_NEW_COOKIE = "cookies.cookie" 6 | 7 | 8 | @moduleman_plugin 9 | class cookies(BasePlugin): 10 | name = "cookies" 11 | author = ("Xavi Mendez (@xmendez)",) 12 | version = "0.1" 13 | summary = "Looks for new cookies" 14 | description = ("Looks for new cookies",) 15 | category = ["info", "passive", "default"] 16 | priority = 99 17 | 18 | parameters = () 19 | 20 | def __init__(self): 21 | BasePlugin.__init__(self) 22 | 23 | def validate(self, fuzzresult): 24 | return True 25 | 26 | def process(self, fuzzresult): 27 | new_cookies = list(fuzzresult.history.cookies.response.items()) 28 | 29 | if len(new_cookies) > 0: 30 | for name, value in new_cookies: 31 | 32 | if ( 33 | name != "" 34 | and KBASE_NEW_COOKIE not in self.kbase 35 | or name not in self.kbase[KBASE_NEW_COOKIE] 36 | ): 37 | self.kbase[KBASE_NEW_COOKIE] = name 38 | self.add_result( 39 | "cookie", "Cookie first set", "%s=%s" % (name, value) 40 | ) 41 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/scripts/cvs_extractor.py: -------------------------------------------------------------------------------- 1 | # Python 2 and 3 2 | try: 3 | from urllib.parse import urljoin 4 | except ImportError: 5 | from urlparse import urljoin 6 | 7 | from wfuzz.plugin_api.urlutils import check_content_type 8 | 9 | from wfuzz.plugin_api.mixins import DiscoveryPluginMixin 10 | from wfuzz.plugin_api.base import BasePlugin 11 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 12 | 13 | # Entries format based on: 14 | # http://docstore.mik.ua/orelly/other/cvs/cvs-CHP-6-SECT-9.htm 15 | # Good example at http://webscantest.com/CVS/Entries 16 | 17 | 18 | @moduleman_plugin 19 | class cvs_extractor(BasePlugin, DiscoveryPluginMixin): 20 | name = "cvs_extractor" 21 | author = ("Xavi Mendez (@xmendez)",) 22 | version = "0.1" 23 | summary = "Parses CVS/Entries file." 24 | description = ("Parses CVS/Entries file and enqueues found entries",) 25 | category = ["active", "discovery"] 26 | priority = 99 27 | parameters = () 28 | 29 | def __init__(self): 30 | BasePlugin.__init__(self) 31 | 32 | def validate(self, fuzzresult): 33 | return ( 34 | fuzzresult.url.find("CVS/Entries") >= 0 35 | and fuzzresult.code == 200 36 | and check_content_type(fuzzresult, "text") 37 | ) 38 | 39 | def process(self, fuzzresult): 40 | base_url = urljoin(fuzzresult.url, "..") 41 | 42 | for line in fuzzresult.history.content.splitlines(): 43 | record = line.split("/") 44 | if len(record) == 6 and record[1]: 45 | self.queue_url(urljoin(base_url, record[1])) 46 | 47 | # Directory 48 | if record[0] == "D": 49 | self.queue_url(urljoin(base_url, record[1])) 50 | self.queue_url(urljoin(base_url, "%s/CVS/Entries" % (record[1]))) 51 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/scripts/grep.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from wfuzz.plugin_api.base import BasePlugin 4 | from wfuzz.exception import FuzzExceptPluginBadParams 5 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 6 | 7 | 8 | @moduleman_plugin 9 | class grep(BasePlugin): 10 | name = "grep" 11 | author = ("Xavi Mendez (@xmendez)",) 12 | version = "0.1" 13 | summary = "HTTP response grep" 14 | description = ( 15 | "Extracts the given regex pattern from the HTTP response and prints it", 16 | "(It is not a filter operator)", 17 | ) 18 | category = ["tools"] 19 | priority = 99 20 | 21 | parameters = (("regex", "", True, "Regex to perform the grep against."),) 22 | 23 | def __init__(self): 24 | BasePlugin.__init__(self) 25 | try: 26 | print(self.kbase["grep.regex"]) 27 | self.regex = re.compile( 28 | self.kbase["grep.regex"][0], re.MULTILINE | re.DOTALL 29 | ) 30 | except Exception: 31 | raise FuzzExceptPluginBadParams( 32 | "Incorrect regex or missing regex parameter." 33 | ) 34 | 35 | def validate(self, fuzzresult): 36 | return True 37 | 38 | def process(self, fuzzresult): 39 | for r in self.regex.findall(fuzzresult.history.content): 40 | self.add_result("match", "Pattern match", r) 41 | -------------------------------------------------------------------------------- /src/wfuzz/plugins/scripts/listing.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from wfuzz.plugin_api.base import BasePlugin 4 | from wfuzz.externals.moduleman.plugin import moduleman_plugin 5 | 6 | 7 | @moduleman_plugin 8 | class listing(BasePlugin): 9 | name = "listing" 10 | author = ("Xavi Mendez (@xmendez)",) 11 | version = "0.1" 12 | summary = "Looks for directory listing vulnerabilities" 13 | description = ("Looks for directory listing vulnerabilities",) 14 | category = ["default", "passive"] 15 | priority = 99 16 | 17 | parameters = () 18 | 19 | def __init__(self): 20 | BasePlugin.__init__(self) 21 | 22 | dir_indexing_regexes = [] 23 | 24 | dir_indexing_regexes.append("