Skip to content

Commit 02a809d

Browse files
authored
Merge pull request xmendez#244 from xmendez/deve
Deve
2 parents 52e6b05 + 3198d60 commit 02a809d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1164
-292
lines changed

Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
.PHONY: docs
2-
test:
2+
tox:
33
pip install tox
44
tox --recreate
5+
test:
6+
pytest -v -s tests/
57
flake8:
68
black --check src tests
79
flake8 src tests

docs/user/advanced.rst

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ value|replace('what', 'with') value|r('what', 'with') Returns value replacing
466466
value|unique() value|u() Returns True if a value is unique.
467467
value|startswith('value') value|sw('value') Returns true if the value string starts with param
468468
value|gregex('expression') value|gre('exp') Returns first regex group that matches in value
469+
value|diff(expression) Returns diff comparison between value and expression
469470
================================ ======================= =============================================
470471

471472
* When a FuzzResult is available, you could perform runtime introspection of the objects using the following symbols
@@ -482,7 +483,7 @@ lines l Wfuzz's result HTTP response lines
482483
words w Wfuzz's result HTTP response words
483484
md5 Wfuzz's result HTTP response md5 hash
484485
history r Wfuzz's result associated FuzzRequest object
485-
plugins Wfuzz's results associated plugins result in the form of {'plugin id': ['result']}
486+
plugins Wfuzz's plugins scan results
486487
============ ============== =============================================
487488

488489
FuzzRequest object's attribute (you need to use the r. prefix) such as:
@@ -609,7 +610,7 @@ The payload to filter, specified by the -z switch must precede --slice command l
609610

610611
The specified expression must return a boolean value, an example, using the unique operator is shown below::
611612

612-
$ wfuzz-cli.py -z list --zD one-two-one-one --slice "FUZZ|u()" http://localhost:9000/FUZZ
613+
$ wfuzz -z list --zD one-two-one-one --slice "FUZZ|u()" http://localhost:9000/FUZZ
613614

614615
********************************************************
615616
* Wfuzz 2.2 - The Web Fuzzer *
@@ -633,6 +634,37 @@ The specified expression must return a boolean value, an example, using the uniq
633634
It is worth noting that, the type of payload dictates the available language symbols. For example, a dictionary payload such as in the example
634635
above does not have a full FuzzResult object context and therefore object fields cannot be used.
635636

637+
When slicing a FuzzResult payload, you are accessing the FuzzResult directly, therefore given a previous session such as::
638+
639+
$ wfuzz -z range --zD 0-0 -u http://www.google.com/FUZZ --oF /tmp/test1
640+
...
641+
000000001: 404 11 L 72 W 1558 Ch "0"
642+
...
643+
644+
this can be used to filter the payload::
645+
646+
$ wfpayload -z wfuzzp --zD /tmp/test1 --slice "c=404"
647+
...
648+
000000001: 404 11 L 72 W 1558 Ch "0"
649+
...
650+
651+
$ wfpayload -z wfuzzp --zD /tmp/test1 --slice "c!=404"
652+
...
653+
wfuzz.py:168: UserWarning:Fatal exception: Empty dictionary! Please check payload or filter.
654+
...
655+
656+
In fact, in this situation, FUZZ refers to the previous result (if any)::
657+
658+
$ wfuzz -z wfuzzp --zD /tmp/test1 -u FUZZ --oF /tmp/test2
659+
...
660+
000000001: 404 11 L 72 W 1558 Ch "http://www.google.com/0"
661+
...
662+
663+
$ wfpayload -z wfuzzp --zD /tmp/test2 --efield r.headers.response.date --efield FUZZ[r.headers.response.date]
664+
...
665+
000000001: 404 11 L 72 W 1558 Ch "http://www.google.com/0 | Mon, 02 Nov 2020 19:29:03 GMT | Mon, 02 Nov 2020 19:27:27 GMT"
666+
...
667+
636668
Re-writing a payload
637669
"""""""
638670

@@ -740,6 +772,12 @@ The above command will generate HTTP requests such as the following::
740772

741773
You can filter the payload using the filter grammar as described before.
742774

775+
Reutilising previous results
776+
--------------------------------------
777+
778+
Plugins results contain a treasure trove of data. Wfuzz payloads and object introspection (explained in the filter grammar section) exposes a Python object interface to plugins results.
779+
This allows you to perform semi-automatic tests based on plugins results or compile a set of results to be used in another tool.
780+
743781
Request mangling
744782
^^^^^^^^^
745783

docs/user/basicusage.rst

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ For example, to show results in JSON format use the following command::
252252

253253
$ wfuzz -o json -w wordlist/general/common.txt http://testphp.vulnweb.com/FUZZ
254254

255-
When using the default output you can also select additional FuzzResult's fields to show, using --efield, together with the payload description::
255+
When using the default or raw output you can also select additional FuzzResult's fields to show, using --efield, together with the payload description::
256256

257257
$ wfuzz -z range --zD 0-1 -u http://testphp.vulnweb.com/artists.php?artist=FUZZ --efield r
258258
...
@@ -262,7 +262,7 @@ When using the default output you can also select additional FuzzResult's fields
262262
Host: testphp.vulnweb.com
263263
...
264264

265-
The above is useful, for example, to debug what exact HTTP request Wfuzz sent to the remote Web server.
265+
The above command is useful, for example, to debug what exact HTTP request Wfuzz sent to the remote Web server.
266266

267267
To completely replace the default payload output you can use --field instead::
268268

@@ -279,4 +279,14 @@ To completely replace the default payload output you can use --field instead::
279279
000000001: 200 104 L 364 W 4735 Ch "0 | http://testphp.vulnweb.com/artists.php?artist=0 | 4735"
280280
...
281281

282+
The field printer can be used with a --efield or --field expression to list only the specified filter expressions without a header or footer::
283+
284+
285+
$ wfuzz -z list --zD https://www.airbnb.com/ --script=links --script-args=links.regex=.*js$,links.enqueue=False -u FUZZ -o field --field plugins.links.link | head -n3
286+
https://a0.muscache.com/airbnb/static/packages/4e8d-d5c346ee.js
287+
https://a0.muscache.com/airbnb/static/packages/7afc-ac814a17.js
288+
https://a0.muscache.com/airbnb/static/packages/7642-dcf4f8dc.js
289+
290+
The above command is useful, for example, to pipe wfuzz into other tools or perform console scripts.
291+
282292
--efield and --field are in fact filter expressions. Check the filter language section in the advance usage document for the available fields and operators.

docs/user/installation.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ You can either clone the public repository::
2626

2727
$ git clone git://github.com/xmendez/wfuzz.git
2828

29-
Or download last `release <https://github.com/xmendez/wfuzz/releases/latest>_`.
29+
Or download last `release <https://github.com/xmendez/wfuzz/releases/latest>`_.
3030

3131
Once you have a copy of the source, you can embed it in your own Python
3232
package, or install it into your site-packages easily::
@@ -91,6 +91,16 @@ If you get errors such as::
9191
9292
Run brew update && brew upgrade
9393

94+
If you get an error such as::
95+
96+
ImportError: pycurl: libcurl link-time ssl backends (secure-transport, openssl) do not include compile-time ssl backend (none/other)
97+
98+
That might indicate that pycurl was reinstalled and not linked to the SSL correctly. Uninstall pycurl as follows::
99+
100+
$ pip uninstall pycurl
101+
102+
and re-install pycurl starting from step 4 above.
103+
94104
Pycurl on Windows
95105
-----------------
96106

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#
77
attrs==20.1.0 # via pytest
88
chardet==3.0.4 # via wfuzz (setup.py)
9-
future==0.18.2 # via wfuzz (setup.py)
109
iniconfig==1.0.1 # via pytest
1110
more-itertools==8.5.0 # via pytest
1211
packaging==20.4 # via pytest

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
'pycurl',
3333
'pyparsing<2.4.2;python_version<="3.4"',
3434
'pyparsing>=2.4*;python_version>="3.5"',
35-
'future',
3635
'six',
3736
'configparser;python_version<"3.5"',
3837
'chardet',

src/wfuzz/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
__title__ = "wfuzz"
2-
__version__ = "3.0.3"
2+
__version__ = "3.1.0"
33
__build__ = 0x023000
44
__author__ = "Xavier Mendez"
55
__license__ = "GPL 2.0"

src/wfuzz/core.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ def __init__(self, options):
3030
# genReq ---> seed_queue -> [slice_queue] -> http_queue/dryrun -> [round_robin -> plugins_queue] * N
3131
# -> [recursive_queue -> routing_queue] -> [filter_queue] -> [save_queue] -> [printer_queue] ---> results
3232

33+
self.options = options
3334
self.qmanager = QueueManager(options)
3435
self.results_queue = MyPriorityQueue()
3536

3637
if options["allvars"]:
37-
self.qmanager.add("allvars_queue", AllVarQ(options))
38+
self.qmanager.add("seed_queue", AllVarQ(options))
3839
else:
3940
self.qmanager.add("seed_queue", SeedQ(options))
4041

@@ -56,8 +57,12 @@ def __init__(self, options):
5657
if options.get("script"):
5758
self.qmanager.add("plugins_queue", JobQ(options))
5859

59-
if options.get("script") or options.get("rlevel") > 0:
60+
if options.get("rlevel") > 0:
6061
self.qmanager.add("recursive_queue", RecursiveQ(options))
62+
63+
if (options.get("script") or options.get("rlevel") > 0) and options.get(
64+
"transport"
65+
) == "http":
6166
rq = RoutingQ(
6267
options,
6368
{
@@ -115,7 +120,7 @@ def __next__(self):
115120
def stats(self):
116121
return dict(
117122
list(self.qmanager.get_stats().items())
118-
+ list(self.qmanager["transport_queue"].job_stats().items())
123+
+ list(self.qmanager["transport_queue"].http_pool.job_stats().items())
119124
+ list(self.options.stats.get_stats().items())
120125
)
121126

src/wfuzz/dictionaries.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from .exception import FuzzExceptNoPluginError, FuzzExceptBadOptions
22
from .facade import Facade
3-
from .filters.ppfilter import FuzzResFilterSlice
3+
from .filters.ppfilter import FuzzResFilterSlice, FuzzResFilter
44
from .fuzzobjects import FuzzWord, FuzzWordType
55

66

@@ -119,7 +119,8 @@ def next_word(self):
119119

120120
class SliceIt(BaseDictionary):
121121
def __init__(self, payload, slicestr):
122-
self.ffilter = FuzzResFilterSlice(filter_string=slicestr)
122+
self.ffilter = FuzzResFilter(filter_string=slicestr)
123+
self.ffilter_slice = FuzzResFilterSlice(filter_string=slicestr)
123124
self.payload = payload
124125

125126
def count(self):
@@ -128,10 +129,18 @@ def count(self):
128129
def get_type(self):
129130
return self.payload.get_type()
130131

132+
def _get_filtered_value(self, item):
133+
if item.type == FuzzWordType.FUZZRES:
134+
filter_ret = self.ffilter.is_visible(item.content)
135+
else:
136+
filter_ret = self.ffilter_slice.is_visible(item.content)
137+
138+
return filter_ret
139+
131140
def next_word(self):
132141
# can be refactored using the walrus operator in python 3.8
133142
item = next(self.payload)
134-
filter_ret = self.ffilter.is_visible(item.content)
143+
filter_ret = self._get_filtered_value(item)
135144

136145
if not isinstance(filter_ret, bool) and item.type == FuzzWordType.FUZZRES:
137146
raise FuzzExceptBadOptions(
@@ -140,7 +149,7 @@ def next_word(self):
140149

141150
while isinstance(filter_ret, bool) and not filter_ret:
142151
item = next(self.payload)
143-
filter_ret = self.ffilter.is_visible(item.content)
152+
filter_ret = self._get_filtered_value(item)
144153

145154
if not isinstance(filter_ret, bool):
146155
return FuzzWord(filter_ret, item.type)

src/wfuzz/externals/reqresp/Response.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def parseResponse(self, rawheader, rawbody=None, type="curl"):
146146
tp = TextParser()
147147
tp.setSource("string", rawheader)
148148

149-
tp.readUntil(r"(HTTP\S*) ([0-9]+)")
149+
tp.readUntil(r"(HTTP/[0-9.]+) ([0-9]+)")
150150
while True:
151151
while True:
152152
try:
@@ -162,7 +162,7 @@ def parseResponse(self, rawheader, rawbody=None, type="curl"):
162162
if self.code != "100":
163163
break
164164
else:
165-
tp.readUntil(r"(HTTP\S*) ([0-9]+)")
165+
tp.readUntil(r"(HTTP/[0-9.]+) ([0-9]+)")
166166

167167
self.code = int(self.code)
168168

@@ -176,7 +176,7 @@ def parseResponse(self, rawheader, rawbody=None, type="curl"):
176176
# curl sometimes sends two headers when using follow, 302 and the final header
177177
# also when using proxies
178178
tp.readLine()
179-
if not tp.search(r"(HTTP\S*) ([0-9]+)"):
179+
if not tp.search(r"(HTTP/[0-9.]+) ([0-9]+)"):
180180
break
181181
else:
182182
self._headers = []

0 commit comments

Comments
 (0)