: Show the specified language expression together with the current payload
""")
from .api import payload
@@ -82,7 +88,7 @@ def usage():
import getopt
try:
- opts, args = getopt.getopt(sys.argv[1:], "hz:m:w:", ["help", "slice=", "zP="])
+ opts, args = getopt.getopt(sys.argv[1:], "vhz:m:w:", ["field=", "help", "slice=", "zD=", "zP=", "efield="])
except getopt.GetoptError as err:
print((str(err)))
usage()
@@ -92,22 +98,44 @@ def usage():
usage()
sys.exit()
+ field = None
+ raw_output = False
+
for o, value in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
+ if o in ("--efield"):
+ field = value
+ if o in ("--field"):
+ field = value
+ raw_output = True
try:
- for res in payload(**CLParser(sys.argv).parse_cl()):
+ session_options = CLParser(sys.argv).parse_cl()
+ printer = None
+
+ for res in payload(**session_options):
if len(res) > 1:
raise FuzzExceptBadOptions("wfpayload can only be used to generate one word dictionaries")
else:
r = res[0]
- if "FuzzResult" in str(r.__class__):
- r._description = r.url
-
- print(r)
+ # TODO: all should be same object type and no need for isinstance
+ if isinstance(r, FuzzResult):
+ if raw_output:
+ print(r.eval(field if field is not None else "url"))
+ else:
+ if printer is None:
+ printer = View(session_options)
+ printer.header(None)
+
+ if field:
+ r._description = field
+ r._show_field = False
+ printer.result(r)
+ else:
+ print(r)
except KeyboardInterrupt:
pass
diff --git a/tests/test_acceptance.py b/tests/test_acceptance.py
index a1410bbf..086f2528 100644
--- a/tests/test_acceptance.py
+++ b/tests/test_acceptance.py
@@ -1,13 +1,13 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+import copy
import os
import unittest
import tempfile
import wfuzz
-
LOCAL_DOMAIN = "http://localhost"
URL_LOCAL = "%s:8000/dir" % (LOCAL_DOMAIN)
HTTPD_PORT = 8000
@@ -38,10 +38,61 @@
# conn delays?
# script args
+testing_savedsession_tests = [
+]
+
testing_tests = [
]
+savedsession_tests = [
+ # parse post params
+ ("test_novalue_post_fuzz", "-z list --zD a -u {}/anything -d FUZZ".format(HTTPBIN_URL), "-z wfuzzp --zD $$PREVFILE$$ -u FUZZ --filter r.params.post.a:=1 --field r.params.post.a", ["1"], None),
+ ("test_json_post_fuzz2", "-z list --zD anything -u {}/FUZZ -d {{\"a\":\"2\"}} -H Content-Type:application/json".format(HTTPBIN_URL), "-z wfuzzp --zD $$PREVFILE$$ -u FUZZ --field r.params.post.a", ["2"], None),
+ ("test_json_post_fuzz3", "-z list --zD anything -u {}/FUZZ -d {{\"a\":\"2\"}} -H Content-Type:application/json".format(HTTPBIN_URL), "-z wfuzzp --zD $$PREVFILE$$ -u FUZZ --filter r.params.post.a:=1 --field r.params.post.a", ["1"], None),
+
+ # field fuzz values
+ ("test_desc_fuzz", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ FUZZ", ["http://localhost:9000/1"], None),
+ ("test_desc_attr", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ FUZZ[url]", ["http://localhost:9000/1"], None),
+ ("test_desc_concat_number", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ FUZZ[url]FUZZ[c]", ["http://localhost:9000/1 - 404"], None),
+ ("test_desc_url_number", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ FUZZ[c]", ["http://localhost:9000/1 - 404"], "Pycurl error 7:"),
+
+ # set values
+ ("test_desc_concat_number", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice r.c:=302 FUZZ[url]FUZZ[c]", ["http://localhost:9000/1 - 302"], None),
+ ("test_desc_rewrite_url", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --prefilter=r.url:=r.url|replace('1','2') FUZZ", ["http://localhost:9000/2"], None),
+ ("test_desc_rewrite_url2", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice r.url:=r.url|replace('1','2') FUZZ[url]", ["http://localhost:9000/2"], None),
+
+ # fuzz value slice filters
+ ("test_desc_concat_fuzz_symbol_op", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --prefilter FUZZ[r.url]=+'2' FUZZ", ["http://localhost:9000/12"], None),
+ ("test_fuzz_symbol_code", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice FUZZ[c]=404 FUZZ", ["http://localhost:9000/1"], None),
+ ("test_fuzz_value_code", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice c=404 FUZZ", ["http://localhost:9000/1"], None),
+
+ # fuzz value exceptions
+ ("test_fuzz_symbol_code", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice FUZ1Z[c]=404 FUZZ", ["http://localhost:9000/1"], "Unknown field"),
+ ("test_fuzz_symbol_code2", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice FUZ2Z[c]=404 FUZZ", ["http://localhost:9000/1"], "Non existent FUZZ payload"),
+ ("test_desc_assign_fuzz_symbol_op", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice FUZZ[r.url]:=FUZZ[r.url|replace('1','2')] FUZZ[url]", ["http://localhost:9000/2"], None),
+ ("test_fuzz_param_int", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --slice r.params.get:=2 FUZZ", ["http://localhost:9000/2"], "Non existent FUZZ payload"),
+
+ # filter based on various payloads
+ ("test_fuzz_fuz2z_code", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z list,404-302-200 --prefilter FUZZ[code]=FUZ2Z FUZZ[url]/FUZ2Z", ['http://localhost:9000/1 - 404'], None),
+ ("test_fuzz_fuz2z_code2", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z list,404-302-200 --prefilter FUZZ[code]=FUZ2Z FUZZ[url]", ['http://localhost:9000/1'], None),
+ ("test_fuzz_fuz2z_code3", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z list,404-302-200 --prefilter FUZZ[code]=FUZ2Z FUZZ", ['http://localhost:9000/1'], None),
+
+ # set values various payloads
+ ("test_set_fuzz_from_fuz2z_full", "-z range,1-1 {}/FUZZ?param=1".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z list,6-3 --prefilter r.params.get.param:=FUZ2Z FUZZ", ["http://localhost:9000/1?param=6", "http://localhost:9000/1?param=3"], None),
+ ("test_set_fuzz_from_fuz2z_full2", "-z range,1-1 {}/FUZZ?param=1".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z list,6-3 --prefilter FUZZ[r.params.get.param]:=FUZ2Z FUZZ", ["http://localhost:9000/1?param=6", "http://localhost:9000/1?param=3"], None),
+ ("test_set_fuzz_from_fuz2z_full_all", "-z range,1-1 {}/FUZZ?param=1¶m2=2".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z range,6-6 --prefilter r.params.all:=FUZ2Z FUZZ", ["http://localhost:9000/1?param=6¶m2=6"], None),
+ ("test_app_fuzz_from_fuz2z_full_all", "-z range,1-1 {}/FUZZ?param=1¶m2=2".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z range,6-6 --prefilter r.params.all=+FUZ2Z FUZZ", ["http://localhost:9000/1?param=16¶m2=26"], None),
+ # fails ("test_set_fuzz_from_fuz2z_url", "-z range,1-1 {}/FUZZ?param=1".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ -z list,6-3 --prefilter r.params.get.param:=FUZ2Z FUZZ[url]", ["http://localhost:9000/1?param=6", "http://localhost:9000/1?param=3"], None),
+
+ # test different field
+ ("test_field", "-z range,1-1 {}/FUZZ".format(HTTPBIN_URL), "-z wfuzzp,$$PREVFILE$$ --field c FUZZ", [404], None),
+
+]
+
basic_tests = [
+ # different connect host ip
+ # travis has an old pycurl version ("test_static_strquery_set_ip", "http://wfuzz.org/FUZZ?var=1&var2=2", [["anything"], ['PUT', 'GET', 'DELETE']], dict(connect_to_ip={'ip': '127.0.0.1', 'port': '9000'}, method='FUZ2Z', filter="content~'url' and content~'http://wfuzz.org'"), [(200, '/anything')] * 3, None),
+
# encoding tests
("test_encode_cookie2_utf8_return", "%s/anything" % HTTPBIN_URL, [["は国"]], dict(cookie=["test=FUZZ"], filter="content~'test=\\\\u00e3\\\\u0081\\\\u00af\\\\u00e5\\\\u009b\\\\u00bd'"), [(200, '/anything')], None),
("test_encode_header_utf8_return", "%s/headers" % HTTPBIN_URL, [["は国"]], dict(headers=[("myheader", "FUZZ")], filter="content~'Myheader' and content~'\\\\u00e3\\\\u0081\\\\u00af\\\\u00e5\\\\u009b\\\\u00bd'"), [(200, '/headers')], None),
@@ -52,7 +103,7 @@
("test_encode_url_filter", "%s/FUZZ" % HTTPBIN_URL, [["は国"]], dict(filter="url~'は国'"), [(404, '/は国')], None),
# ("test_encode_var", "%s/anything?var=FUZZ" % HTTPBIN_URL, [["は国"]], dict(filter="content~'\"は国\"'"), [(200, '/anything')], None),
("test_encode_var", "%s/anything?var=FUZZ" % HTTPBIN_URL, [["は国"]], dict(filter="content~'\"\\\\u306f\\\\u56fd\"'"), [(200, '/anything')], None),
- ("test_encode_redirect", "%s/redirect-to?url=FUZZ" % HTTPBIN_URL, [["は国"]], dict(filter="headers.response.Location='%C3%A3%C2%81%C2%AF%C3%A5%C2%9B%C2%BD'"), [(302, '/redirect-to')], None),
+ ("test_encode_redirect", "%s/redirect-to?url=FUZZ" % HTTPBIN_URL, [["は国"]], dict(filter="r.headers.response.Location='%C3%A3%C2%81%C2%AF%C3%A5%C2%9B%C2%BD'"), [(302, '/redirect-to')], None),
# ("test_encode_cookie", "%s/cookies" % HTTPBIN_URL, [["は国"]], dict(cookie=["cookie1=FUZZ"], follow=True, filter="content~FUZZ"), [(200, '/cookies')], None),
("test_encode_cookie", "%s/cookies" % HTTPBIN_URL, [["は国"]], dict(cookie=["cookie1=FUZZ"], follow=True, filter="content~'\\\\u306f\\\\u56fd'"), [(200, '/cookies')], None),
@@ -72,13 +123,17 @@
("test_basic_auth", "%s/basic-auth/FUZZ/FUZZ" % HTTPBIN_URL, [["userpass"]], dict(auth=("basic", "FUZZ:FUZZ")), [(200, '/basic-auth/userpass/userpass')], None),
("test_digest_auth", "%s/digest-auth/auth/FUZZ/FUZZ" % HTTPBIN_URL, [["userpass"]], dict(auth=("digest", "FUZZ:FUZZ")), [(200, '/digest-auth/auth/userpass/userpass')], None),
("test_delayed_response", "%s/delay/FUZZ" % HTTPBIN_URL, [["2"]], dict(req_delay=1), [(200, '/delay/2')], 'Operation timed out'),
- ("test_static_strquery_set", "%s/FUZZ?var=1&var2=2" % HTTPBIN_URL, [["anything"], ['PUT', 'GET', 'POST', 'DELETE']], dict(method='FUZ2Z', filter="content~'\"args\":{\"var\":\"1\",\"var2\":\"2\"}'"), [(200, '/anything')] * 4, None),
+ ("test_static_strquery_set_multiple_method", "%s/FUZZ?var=1&var2=2" % HTTPBIN_URL, [["anything"], ['PUT', 'GET', 'POST', 'DELETE']], dict(method='FUZ2Z', filter="content~FUZ2Z and content~'\"var\": \"1\"' and content~'\"var2\": \"2\"'"), [(200, '/anything')] * 4, None),
+ ("test_static_strquery_set_multiple_method_gre", "%s/FUZZ?var=1&var2=2" % HTTPBIN_URL, [["anything"], ['PUT', 'GET', 'POST', 'DELETE']], dict(method='FUZ2Z', filter="content|gre('\"method\": \"(.*)?\",')=FUZ2Z and content~'\"var\": \"1\"' and content~'\"var2\": \"2\"'"), [(200, '/anything')] * 4, None),
# set static HTTP values
- ("test_static_strquery_set", "%s:8000/FUZZ?var=1&var=2" % LOCAL_DOMAIN, [["echo"]], dict(filter="content~'query=var=1&var=2'"), [(200, '/echo')], None),
- ("test_static_postdata_set", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(postdata="a=2", filter="content~'POST_DATA=a=2'"), [(200, '/echo')], None),
- ("test_static_postdata2_set", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(postdata="2", filter="content~'POST_DATA=2'"), [(200, '/echo')], None),
- ("test_empty_postdata", "%s/FUZZ" % HTTPBIN_URL, [["anything"]], dict(postdata='', filter="content~'POST' and method='POST'"), [(200, '/anything')], None),
+ ("test_static_strquery_set", "%s:8000/FUZZ?var=1&var=2" % LOCAL_DOMAIN, [["echo"]], dict(filter="content=~'query=var=1&var=2$'"), [(200, '/echo')], None),
+ ("test_static_postdata_set", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(postdata="a=2", filter="content=~'POST_DATA=a=2$'"), [(200, '/echo')], None),
+ ("test_static_postdata2_set", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(postdata="2", filter="content=~'POST_DATA=2$'"), [(200, '/echo')], None),
+ ("test_empty_postdata", "%s/FUZZ" % HTTPBIN_URL, [["anything"]], dict(postdata='', filter="content~'POST' and content~'\"form\": {},' and r.method='POST'"), [(200, '/anything')], None),
+ ("test_static_postdata3_set", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(headers=[("Content-Type", "application/json")], postdata="2", filter="content=~'POST_DATA=2$' and content=~'command=POST$' and content~'Content-Type: application/json'"), [(200, '/echo')], None),
+ ("test_static_postdata3_set2", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(headers=[("Content-Type", "aaaa")], postdata="a=2&b=3", filter="(content=~'POST_DATA=a=2&b=3$' or content=~'POST_DATA=b=3&a=2$') and content=~'command=POST$' and content~'Content-Type: aaaa'"), [(200, '/echo')], None),
+ ("test_static_postdata3_set3", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(headers=[("Content-Type", "application/json")], postdata="{\"a\": \"2\"}", filter="content=~'POST_DATA={\"a\": \"2\"}$' and content=~'command=POST$' and content~'Content-Type: application/json'"), [(200, '/echo')], None),
("test_static_method_set", "%s/FUZZ" % URL_LOCAL, [["dir"]], dict(method="OPTIONS", filter="content~'Message: Unsupported method (\\\'OPTIONS\\\')'"), [(501, '/dir/dir')], None),
("test_static_header_set", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(headers=[("myheader", "isset")], filter="content~'Myheader: isset'"), [(200, '/echo')], None),
("test_static_cookie_set", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["echo"]], dict(cookie=["cookie1=value1", ], filter="content~'Cookie: cookie1=value1'"), [(200, '/echo')], None),
@@ -106,7 +161,7 @@
("test_url_hostname2_fuzz", "http://FUZZ/dir/a", [["localhost:8000"]], dict(), [(200, '/dir/a')], None),
("test_url_schema_fuzz", "FUZZ://localhost:8000/dir/a", [["http"]], dict(), [(200, '/dir/a')], None),
("test_url_all_url_fuzz", "FUZZ", [["http://localhost:8000/dir/a"]], dict(), [(200, '/dir/a')], None),
- ("test_url_all_url_fuzz2", "FUZZ", [["http://webscantest.com/datastore/search_get_by_name.php?name=Rake"]], dict(), [(200, '/datastore/search_get_by_name.php')], None),
+ ("test_url_all_url_fuzz2", "FUZZ", [["%s/anything/datastore/search_get_by_name.php?name=Rake" % HTTPBIN_URL]], dict(), [(200, '/anything/datastore/search_get_by_name.php')], None),
# edge cases
("test_vhost_fuzz", "%s" % ECHO_URL, [["onevalue", "twovalue"]], dict(headers=[("Host", "FUZZ")], filter="content~'Host:' and content~FUZZ"), [(200, '/echo'), (200, '/echo')], None),
@@ -119,13 +174,14 @@
# prefilter, slice
("test_prefilter", "%s/FUZZ" % URL_LOCAL, [["a", "a", "a", "a", "a", "a"]], dict(prefilter="FUZZ|u()", ss="one"), [(200, '/dir/a')], None),
("test_slice", "%s/FUZZ" % URL_LOCAL, None, dict(payloads=[("list", dict(default="a-a-a-a-a"), "FUZZ|u()")], ss="one"), [(200, '/dir/a')], None),
+ ("test_slice2", "%s/FUZZ" % URL_LOCAL, None, dict(payloads=[("range", dict(default="1-10"), "FUZZ='1'")]), [(404, '/dir/1')], None),
# follow
("test_follow", "%s:8000/FUZZ" % LOCAL_DOMAIN, [["redirect"]], dict(follow=True, filter="content~'path=/echo'"), [(200, '/echo')], None),
# all params
("test_all_params_get", "%s:8000/echo?var=1&var2=2" % LOCAL_DOMAIN, [["avalue"]], dict(allvars="allvars", filter="content~'query=var=avalue&var2=2' or content~'var=1&var2=avalue'"), [(200, '/echo'), (200, '/echo')], None),
- ("test_all_params_post", "%s" % ECHO_URL, [["onevalue"]], dict(allvars="allpost", postdata="a=1&b=2", filter="content~'POST_DATA=a=onevalue&b=2' or content~'POST_DATA=a=1&b=onevalue'"), [(200, '/echo'), (200, '/echo')], None),
+ ("test_all_params_post", "%s" % ECHO_URL, [["onevalue"]], dict(allvars="allpost", postdata="a=1&b=2", filter="content~'command=POST' and (content~'a=onevalue' and content~'b=2') or (content~'a=1' and content~'b=onevalue')"), [(200, '/echo'), (200, '/echo')], None),
# simple filter
("test_codes_HC", "%s/FUZZ" % URL_LOCAL, [["a", "b", "c"]], dict(hc=[404]), [(200, '/dir/a'), (200, '/dir/b'), (200, '/dir/c')], None),
@@ -152,6 +208,7 @@
("test_filter_hw", "%s/FUZZ" % URL_LOCAL, [["a", "b", "c"]], dict(filter="h=28 or w=6"), [(200, '/dir/a')], None),
("test_filter_intext", "%s/FUZZ" % URL_LOCAL, [["a", "b", "c"]], dict(filter="content~'one'"), [(200, '/dir/a'), (200, '/dir/b')], None),
("test_filter_intext2", "%s/FUZZ" % URL_LOCAL, [["a", "b", "c"]], dict(filter="content!~'one'"), [(200, '/dir/c')], None),
+ ("test_dict_filter_strquery_fuzz", "%s:8000/echo?var=FUZZ" % LOCAL_DOMAIN, [["value1"]], dict(filter="r.params.get~'value1'"), [(200, '/echo')], None),
# baseline
("test_baseline", "%s/FUZZ{notthere}" % URL_LOCAL, [["a", "b", "c"]], dict(), [(200, '/dir/a'), (200, '/dir/b'), (200, '/dir/c'), (404, "/dir/notthere")], None),
@@ -172,6 +229,7 @@
# plugins
("test_robots", "%s:8000/plugins/FUZZ" % LOCAL_DOMAIN, [["robots.txt"]], dict(script="robots"), [(404, '/cal_endar/'), (404, '/crawlsnags/'), (404, '/osrun/'), (200, '/plugins/robots.txt'), (200, '/static/')], None),
("test_robots_hc", "%s:8000/plugins/FUZZ" % LOCAL_DOMAIN, [["robots.txt"]], dict(hc=[404], script="robots"), [(200, '/plugins/robots.txt'), (200, '/static/')], None),
+ ("test_plugins_filter", "%s/FUZZ" % HTTPBIN_URL, [["anything"]], dict(script='headers', filter="plugins~'unicorn'"), [(200, '/anything')], None),
]
scanmode_tests = [
@@ -188,7 +246,7 @@
("test_all_params_no_var", "%s:8000/echo" % LOCAL_DOMAIN, [["avalue"]], dict(allvars="allvars", filter="content~'query=var=avalue&var2=2' or content~'var=1&var2=avalue'"), [(200, '/echo'), (200, '/echo')], "No variables on specified variable set"),
("test_bad_port", "%s:6666/FUZZ" % LOCAL_DOMAIN, [list(range(1))], dict(), [], 'Failed to connect to localhost port 6666'),
("test_bad_num_payloads", "%s:8000/FUZZ" % LOCAL_DOMAIN, [list(range(1)), list(range(1))], dict(), [], 'FUZZ words and number of payloads do not match'),
- ("test_bad_proxy", "%s:8000/FUZZ" % LOCAL_DOMAIN, [list(range(1))], dict(proxies=[("localhost", 888, "HTML")]), [], 'Failed to connect to localhost port 888'),
+ ("test_bad_proxy", "%s:8000/FUZZ" % LOCAL_DOMAIN, [list(range(1))], dict(proxies=[("localhost", 888, "HTTP")]), [], 'Failed to connect to localhost port 888'),
("test_bad_num_dic", "%s:8000/iterators/FUZZ" % LOCAL_DOMAIN, [list(range(1))], dict(iterator="zip"), [], 'Several dictionaries must be used when specifying an iterator'),
]
@@ -222,6 +280,10 @@ def test(self):
if proxied_payloads:
proxied_payloads = [[payload.replace(original_host, proxied_host) for payload in payloads_list] for payloads_list in proxied_payloads]
+ if 'connect_to_ip' in extra_params and extra_params['connect_to_ip']:
+ extra_params['connect_to_ip']['ip'] = 'httpbin'
+ extra_params['connect_to_ip']['port'] = '80'
+
with wfuzz.FuzzSession(url=proxied_url) as s:
same_list = [(x.code, x.history.urlparse.path) for x in s.get_payloads(proxied_payloads).fuzz(**extra_params)]
@@ -293,7 +355,7 @@ def test(self):
ret_list = [(x.code, x.history.urlparse.path) for x in fuzzed]
# repeat test with recipe as only parameter
- with wfuzz.FuzzSession(recipe=filename) as s:
+ with wfuzz.FuzzSession(recipe=[filename]) as s:
if payloads is None:
same_list = [(x.code, x.history.urlparse.path) for x in s.fuzz()]
else:
@@ -304,6 +366,26 @@ def test(self):
return test
+def wfuzz_me_test_generator_previous_session(prev_session_cli, next_session_cli, expected_list):
+ def test(self):
+ temp_name = next(tempfile._get_candidate_names())
+ defult_tmp_dir = tempfile._get_default_tempdir()
+
+ filename = os.path.join(defult_tmp_dir, temp_name)
+
+ # first session
+ with wfuzz.get_session(prev_session_cli) as s:
+ ret_list = [x.eval(x._description) if x._description else x.description for x in s.fuzz(save=filename)]
+
+ # second session wfuzzp as payload
+ with wfuzz.get_session(next_session_cli.replace("$$PREVFILE$$", filename)) as s:
+ ret_list = [x.eval(x._description) if x._description else x.description for x in s.fuzz()]
+
+ self.assertEqual(sorted(ret_list), sorted(expected_list))
+
+ return test
+
+
def create_test(test_name, url, payloads, params, expected_res, extra_params, exception_str):
test_fn = wfuzz_me_test_generator(url, payloads, params, expected_res, extra_params)
if exception_str:
@@ -332,12 +414,13 @@ def duplicate_tests_diff_params(test_list, group, next_extra_params, previous_ex
if group == "_proxy_" and "encode" in test_name:
continue
- next_extra = dict(list(params.items()) + list(next_extra_params.items()))
+ next_extra = copy.deepcopy(params)
+ next_extra.update(next_extra_params)
new_test = "%s_%s" % (test_name, group)
- prev_extra = params
+ prev_extra = copy.deepcopy(params)
if previous_extra_params:
- prev_extra = dict(list(params.items()) + list(previous_extra_params.items()))
+ prev_extra.update(previous_extra_params)
create_test(new_test, url, payloads, prev_extra, None, next_extra, exception_str)
@@ -358,16 +441,34 @@ def duplicate_tests(test_list, group, test_gen_fun):
setattr(DynamicTests, new_test, test_fn)
+def create_savedsession_tests(test_list, test_gen_fun):
+ """
+ generates wfuzz tests that run 2 times with recipe input, expecting same results.
+
+ """
+ for test_name, prev_cli, next_cli, expected_res, exception_str in test_list:
+ test_fn = test_gen_fun(prev_cli, next_cli, expected_res)
+ if exception_str:
+ test_fn_exc = wfuzz_me_test_generator_exception(test_fn, exception_str)
+ setattr(DynamicTests, test_name, test_fn_exc)
+ else:
+ setattr(DynamicTests, test_name, test_fn)
+
+
def create_tests():
"""
Creates all dynamic tests
"""
+ if testing_savedsession_tests:
+ create_savedsession_tests(testing_savedsession_tests, wfuzz_me_test_generator_previous_session)
+ return
+
if testing_tests:
create_tests_from_list(testing_tests)
duplicate_tests(testing_tests, "recipe", wfuzz_me_test_generator_recipe)
duplicate_tests(testing_tests, "saveres", wfuzz_me_test_generator_saveres)
- duplicate_tests_diff_params(testing_tests, "_proxy_", dict(proxies=[("localhost", 8080, "HTML")]), None)
+ duplicate_tests_diff_params(testing_tests, "_proxy_", dict(proxies=[("localhost", 8080, "HTTP")]), None)
else:
# this are the basics
basic_functioning_tests = [error_tests, scanmode_tests, basic_tests]
@@ -375,6 +476,9 @@ def create_tests():
for t in basic_functioning_tests:
create_tests_from_list(t)
+ # description tests
+ create_savedsession_tests(savedsession_tests, wfuzz_me_test_generator_previous_session)
+
# duplicate tests with recipe
duplicate_tests(basic_tests, "recipe", wfuzz_me_test_generator_recipe)
@@ -382,7 +486,7 @@ def create_tests():
duplicate_tests(basic_tests, "saveres", wfuzz_me_test_generator_saveres)
# duplicate tests with proxy
- duplicate_tests_diff_params(basic_tests, "_proxy_", dict(proxies=[("localhost", 8080, "HTML")]), None)
+ duplicate_tests_diff_params(basic_tests, "_proxy_", dict(proxies=[("localhost", 8080, "HTTP")]), None)
create_tests()
diff --git a/tests/test_api.py b/tests/test_api.py
index 04a184d1..5b953230 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -1,7 +1,13 @@
import unittest
import sys
+from io import BytesIO
+import gzip
+import pickle as pickle
import wfuzz
+from wfuzz.facade import Facade
+from wfuzz.fuzzobjects import FuzzRequest
+from wfuzz.fuzzobjects import FuzzResult
try:
# Python >= 3.3
@@ -64,6 +70,62 @@ def test_get_session(self):
self.assertEqual(data.get('url'), 'http://127.0.0.1/FUZZ')
self.assertEqual(data.get('payloads'), [('range', {'default': '0-4', 'encoder': None}, None)])
+ def test_payload_description(self):
+ class mock_saved_session(object):
+ def __init__(self, description, show_field):
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/path?param=1¶m2=2"
+ fuzz_res = FuzzResult(history=fr)
+ fuzz_res._description = description
+ fuzz_res._show_field = show_field
+
+ self.outfile = BytesIO()
+
+ with gzip.GzipFile(fileobj=self.outfile, mode="wb") as f:
+ pickle.dump(fuzz_res, f)
+
+ self.outfile.seek(0)
+ self.outfile.name = "mockfile"
+
+ def close(self):
+ pass
+
+ def read(self, *args, **kwargs):
+ return self.outfile.read(*args, **kwargs)
+
+ def seek(self, *args, **kwargs):
+ return self.outfile.seek(*args, **kwargs)
+
+ def tell(self):
+ return self.outfile.tell()
+
+ # load plugins before mocking file object
+ Facade().payloads
+
+ m = mock.MagicMock(name='open', spec=open)
+ m.return_value = mock_saved_session("r.params.all", True)
+
+ mocked_fun = "builtins.open" if sys.version_info >= (3, 0) else "__builtin__.open"
+ with mock.patch(mocked_fun, m):
+ payload_list = list(wfuzz.payload(**{'show_field': True, 'description': 'r', 'payloads': [('wfuzzp', {'default': 'mockedfile', 'encoder': None}, None)]}))
+ self.assertEqual([res[0].description for res in payload_list], [{'param': '1', 'param2': '2'}])
+
+ m = mock.MagicMock(name='open', spec=open)
+ m.return_value = mock_saved_session("url", None)
+
+ mocked_fun = "builtins.open" if sys.version_info >= (3, 0) else "__builtin__.open"
+ with mock.patch(mocked_fun, m):
+ payload_list = list(wfuzz.payload(**{'show_field': True, 'description': 'r', 'payloads': [('wfuzzp', {'default': 'mockedfile', 'encoder': None}, None)]}))
+ self.assertEqual([res[0].description for res in payload_list], ['http://www.wfuzz.org/path?param=1¶m2=2'])
+
+ m = mock.MagicMock(name='open', spec=open)
+ m.return_value = mock_saved_session("r.scheme", False)
+
+ mocked_fun = "builtins.open" if sys.version_info >= (3, 0) else "__builtin__.open"
+ with mock.patch(mocked_fun, m):
+ payload_list = list(wfuzz.payload(**{'show_field': True, 'description': 'r', 'payloads': [('wfuzzp', {'default': 'mockedfile', 'encoder': None}, None)]}))
+ self.assertEqual([res[0].description for res in payload_list], ['http://www.wfuzz.org/path?param=1¶m2=2 | http'])
+
def test_payload(self):
payload_list = list(wfuzz.payload(**{'payloads': [('range', {'default': '0-4', 'encoder': None}, None)]}))
self.assertEqual(payload_list, [('0',), ('1',), ('2',), ('3',), ('4',)])
@@ -79,10 +141,28 @@ def test_payload(self):
payload_list = list(wfuzz.payload(**{'payloads': [('dirwalk', {'default': 'foo', 'encoder': None}, None)]}))
self.assertEqual(payload_list, [('baz',), ('bar/spam',), ('bar/eggs',)])
+ class mock_file(object):
+ def __init__(self):
+ self.my_iter = iter([b"one", b"two"])
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ return next(self.my_iter)
+
+ def seek(self, pos):
+ self.my_iter = iter([b"one", b"two"])
+
+ next = __next__ # for Python 2
+
+ m = mock.MagicMock(name='open', spec=open)
+ m.return_value = mock_file()
+
mocked_fun = "builtins.open" if sys.version_info >= (3, 0) else "__builtin__.open"
- with mock.patch(mocked_fun, mock.mock_open(read_data="one\ntwo\n")):
+ with mock.patch(mocked_fun, m):
payload_list = list(wfuzz.payload(**{'payloads': [('file', {'default': 'mockedfile', 'encoder': None}, None)]}))
- self.assertEqual(payload_list, [('one',), ('two',)])
+ self.assertEqual(sorted(payload_list), sorted([('one',), ('two',)]))
payload_list = list(wfuzz.payload(**{'payloads': [('hexrange', {'default': '09-10', 'encoder': None}, None)]}))
self.assertEqual(payload_list, [('09',), ('0a',), ('0b',), ('0c',), ('0d',), ('0e',), ('0f',), ('10',)])
@@ -114,7 +194,3 @@ def test_iterator(self):
payload_list = list(wfuzz.payload(**{'iterator': 'product', 'payloads': [('range', {'default': '0-2', 'encoder': None}, None), ('range', {'default': '0-2', 'encoder': None}, None)]}))
self.assertEqual(sorted(payload_list), sorted([('0', '0'), ('0', '1'), ('0', '2'), ('1', '0'), ('1', '1'), ('1', '2'), ('2', '0'), ('2', '1'), ('2', '2')]))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test_clparser.py b/tests/test_clparser.py
index 81c8c3fa..a4180a2a 100644
--- a/tests/test_clparser.py
+++ b/tests/test_clparser.py
@@ -10,6 +10,42 @@ def test_listplugins(self):
self.assertEqual(cm.exception.code, 0)
+ def test_ip_option(self):
+ options = CLParser(['wfuzz', '--ip', '127.0.0.1']).parse_cl()
-if __name__ == '__main__':
- unittest.main()
+ self.assertEqual(options.data['connect_to_ip']['ip'], '127.0.0.1')
+ self.assertEqual(options.data['connect_to_ip']['port'], '80')
+
+ options = CLParser(['wfuzz', '--ip', '127.0.0.1:22']).parse_cl()
+
+ self.assertEqual(options.data['connect_to_ip']['ip'], '127.0.0.1')
+ self.assertEqual(options.data['connect_to_ip']['port'], '22')
+
+ options = CLParser(['wfuzz', '--ip', '127.0.0.1:']).parse_cl()
+
+ self.assertEqual(options.data['connect_to_ip']['ip'], '127.0.0.1')
+ self.assertEqual(options.data['connect_to_ip']['port'], '80')
+
+ with self.assertRaises(Exception) as cm:
+ options = CLParser(['wfuzz', '--ip', ':80']).parse_cl()
+ self.assertTrue("An IP must be specified" in str(cm.exception))
+
+ def test_ze_zd_option(self):
+ with self.assertRaises(Exception) as cm:
+ options = CLParser(['wfuzz', '-z', 'range,0-10', '--zD', '0-10', 'url']).parse_cl()
+ self.assertTrue("exclusive" in str(cm.exception))
+
+ options = CLParser(['wfuzz', '-z', 'range', '--zD', '0-1', '--zE', 'md5', 'url']).parse_cl()
+ self.assertEqual(options.data['payloads'], [('range', {'default': '0-1', 'encoder': ['md5']}, None)])
+
+ options = CLParser(['wfuzz', '-z', 'range,0-1', '--zE', 'md5', 'url']).parse_cl()
+ self.assertEqual(options.data['payloads'], [('range', {'default': '0-1', 'encoder': ['md5']}, None)])
+
+ options = CLParser(['wfuzz', '-z', 'range', '--zD', '0-1', '--zE', 'md5', 'url']).parse_cl()
+ self.assertEqual(options.data['payloads'], [('range', {'default': '0-1', 'encoder': ['md5']}, None)])
+
+ options = CLParser(['wfuzz', '-z', 'range', '--zD', '0-1']).parse_cl()
+ self.assertEqual(options.data['payloads'], [('range', {'default': '0-1', 'encoder': None}, None)])
+
+ options = CLParser(['wfuzz', '-z', 'range,0-1']).parse_cl()
+ self.assertEqual(options.data['payloads'], [('range', {'default': '0-1', 'encoder': None}, None)])
diff --git a/tests/test_dotdict.py b/tests/test_dotdict.py
new file mode 100644
index 00000000..e752f61c
--- /dev/null
+++ b/tests/test_dotdict.py
@@ -0,0 +1,17 @@
+import unittest
+
+from wfuzz.utils import DotDict
+
+
+class FilterDotDict(unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ super(FilterDotDict, self).__init__(*args, **kwargs)
+ self.maxDiff = 1000
+
+ def test_code_set(self):
+ dd = DotDict({'a': '1'})
+ dd2 = DotDict({'a': '2'})
+
+ self.assertEqual(dd + "test", {'a': "1test"})
+ self.assertEqual("test" + dd, {'a': "test1"})
+ self.assertEqual(dd + dd2, {'a': "2"})
diff --git a/tests/test_filterintro.py b/tests/test_filterintro.py
new file mode 100644
index 00000000..37b9e5c9
--- /dev/null
+++ b/tests/test_filterintro.py
@@ -0,0 +1,194 @@
+import unittest
+
+# Python 2 and 3: urlib.parse
+
+from wfuzz.fuzzobjects import FuzzRequest
+from wfuzz.fuzzobjects import FuzzResult
+from wfuzz.filter import FuzzResFilter
+
+
+raw_req = """GET / HTTP/1.1
+Host: www.wfuzz.org
+User-Agent: curl/7.58.0
+Accept: */*
+"""
+
+raw_resp = b"""HTTP/1.1 302 Found
+Content-Type: text/html; charset=utf-8
+Content-Language: en
+Location: https://wfuzz.readthedocs.io/en/latest/
+Vary: Accept-Language, Cookie
+Server: nginx/1.14.0 (Ubuntu)
+X-Fallback: True
+X-Served: Django
+X-Deity: web01
+Date: Wed, 23 Jan 2019 21:43:59 GMT
+Content-Length: 0
+"""
+
+
+class FilterTest(unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ super(FilterTest, self).__init__(*args, **kwargs)
+ self.maxDiff = 1000
+
+ def get_filtered_fuzzrequest(self, filter_str):
+ fr = FuzzRequest()
+ fr.update_from_raw_http(raw_req, "http", raw_resp, b"")
+
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string=filter_str)
+ ffilter.is_visible(fuzz_res)
+
+ return fuzz_res
+
+ def test_code_set(self):
+ self.assertEqual(self.get_filtered_fuzzrequest("r.code:=429").code, 429)
+ self.assertEqual(self.get_filtered_fuzzrequest("r.c:=404").code, 404)
+ self.assertEqual(self.get_filtered_fuzzrequest("r.c=+404").code, 706)
+ self.assertEqual(self.get_filtered_fuzzrequest("r.c=-404").code, 706)
+
+ def test_url_set(self):
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/path?param=1¶m2=2"
+
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string="r.url=+'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.url, "http://www.wfuzz.org/path?param=1¶m2=2test")
+
+ ffilter = FuzzResFilter(filter_string="r.url:='test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.url, "http://test/")
+
+ ffilter = FuzzResFilter(filter_string="r.url=-'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.url, "testhttp://test/")
+
+ def test_nonexisting(self):
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/path?param=1¶m2=2"
+
+ fuzz_res = FuzzResult(history=fr)
+
+ with self.assertRaises(Exception) as context:
+ ffilter = FuzzResFilter(filter_string="url=-'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertTrue("rsetattr: Can't set" in str(context.exception))
+
+ with self.assertRaises(Exception) as context:
+ ffilter = FuzzResFilter(filter_string="notthere=-'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertTrue("rgetattr: Can't get" in str(context.exception))
+
+ with self.assertRaises(Exception) as context:
+ ffilter = FuzzResFilter(filter_string="r.params.get.notthere=-'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertTrue("DotDict: Non-existing field" in str(context.exception))
+
+ def test_params_set_no_value(self):
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/path?param"
+
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string="r.params.all=+'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.params.get, {'param': None})
+
+ def test_params_set(self):
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/path?param=1¶m2=2"
+
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string="r.params.get.param=+'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.params.get.param, "1test")
+ self.assertEqual(fuzz_res.history.params.get, {'param': "1test", 'param2': "2"})
+
+ ffilter = FuzzResFilter(filter_string="r.params.get.param=-'test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.params.get.param, "test1test")
+ self.assertEqual(fuzz_res.history.params.get, {'param': "test1test", 'param2': "2"})
+
+ ffilter = FuzzResFilter(filter_string="r.params.get.param:='test'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.params.get.param, "test")
+ self.assertEqual(fuzz_res.history.params.get, {'param': "test", 'param2': "2"})
+
+ ffilter = FuzzResFilter(filter_string="r.params.get.param2='2'")
+ self.assertEqual(ffilter.is_visible(fuzz_res), True)
+
+ fr.url = "http://www.wfuzz.org/path?param=1¶m2=2"
+ ffilter = FuzzResFilter(filter_string="r.params.all=+'2'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.params.all, {'param': "12", 'param2': "22"})
+
+ fr.url = "http://www.wfuzz.org/path?param=1¶m2=2"
+ ffilter = FuzzResFilter(filter_string="r.params.all:='2'")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(fuzz_res.history.params.all, {'param': "2", 'param2': "2"})
+
+ def test_urlp(self):
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/path/test.php?param=1¶m2=2"
+
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string="r.urlp.scheme='http'")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="r.urlp.netloc='www.wfuzz.org'")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="r.urlp.path='/path/test.php'")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="r.urlp.ffname='test.php'")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="r.urlp.fext='.php'")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="r.urlp.fname='test'")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="r.urlp.hasquery")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="not r.urlp.isbllist")
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ def test_ispath(self):
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/path?param=1¶m2=2"
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string="r.is_path")
+ self.assertEqual(False, ffilter.is_visible(fuzz_res))
+
+ ffilter = FuzzResFilter(filter_string="r.pstrip")
+ self.assertEqual(ffilter.is_visible(fuzz_res), "http://www.wfuzz.org/path-gparam-gparam2")
+
+ def test_lwh(self):
+ fr = FuzzRequest()
+ fr.update_from_raw_http(raw_req, "http", raw_resp, b"Some line\n and words\nasdsdas")
+
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string="h=28 or w=6 or l=2")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual(True, ffilter.is_visible(fuzz_res))
+
+ def test_location(self):
+ fr = FuzzRequest()
+ fr.update_from_raw_http(raw_req, "http", raw_resp, b"Some line\n and words\nasdsdas")
+
+ fuzz_res = FuzzResult(history=fr)
+
+ ffilter = FuzzResFilter(filter_string="r.headers.response.Location")
+ ffilter.is_visible(fuzz_res)
+ self.assertEqual('https://wfuzz.readthedocs.io/en/latest/', ffilter.is_visible(fuzz_res))
diff --git a/tests/test_moduleman.py b/tests/test_moduleman.py
index c5014f55..dddee523 100644
--- a/tests/test_moduleman.py
+++ b/tests/test_moduleman.py
@@ -110,22 +110,22 @@ def test_load_file(self):
self.assertTrue("Multiple plugins found" in str(context.exception))
def test_simple_filter(self):
- with mock.patch('imp.find_module') as mocked_find_module:
- with mock.patch('imp.load_module') as mocked_load_module:
- mocked_find_module.return_value = (None, '/any/project.py', ('.py', 'U', 1))
- mocked_load_module.return_value = sys.modules[__name__]
-
- br = BRegistrant(FileLoader(**{"filename": 'project1.py', "base_path": 'any'}))
+ with mock.patch('imp.find_module') as mocked_find_module:
+ with mock.patch('imp.load_module') as mocked_load_module:
+ mocked_find_module.return_value = (None, '/any/project.py', ('.py', 'U', 1))
+ mocked_load_module.return_value = sys.modules[__name__]
- with self.assertRaises(Exception) as context:
- modulefilter.PYPARSING = False
- br.get_plugins_names('not aggressive')
- self.assertTrue("Pyparsing missing, complex filters not allowed." in str(context.exception))
+ br = BRegistrant(FileLoader(**{"filename": 'project1.py', "base_path": 'any'}))
+ with self.assertRaises(Exception) as context:
modulefilter.PYPARSING = False
- self.assertEqual(sorted(br.get_plugins_names("test*")), sorted(['test_plugin1', 'test_plugin2', 'test_plugin3']))
- self.assertEqual(sorted(br.get_plugins_names("test_plugin1,test_plugin2")), sorted(['test_plugin1', 'test_plugin2']))
- self.assertEqual(sorted(br.get_plugins_names("test_plugin5")), sorted([]))
+ br.get_plugins_names('not aggressive')
+ self.assertTrue("Pyparsing missing, complex filters not allowed." in str(context.exception))
+
+ modulefilter.PYPARSING = False
+ self.assertEqual(sorted(br.get_plugins_names("test*")), sorted(['test_plugin1', 'test_plugin2', 'test_plugin3']))
+ self.assertEqual(sorted(br.get_plugins_names("test_plugin1,test_plugin2")), sorted(['test_plugin1', 'test_plugin2']))
+ self.assertEqual(sorted(br.get_plugins_names("test_plugin5")), sorted([]))
def test_plugin_decorator(self):
with self.assertRaises(Exception) as context:
@@ -135,7 +135,3 @@ class test_plugin4:
test_plugin4()
self.assertTrue("Required method method4 not implemented" in str(context.exception))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test_reqresp.py b/tests/test_reqresp.py
index 4bd1a7c3..7797cc2c 100644
--- a/tests/test_reqresp.py
+++ b/tests/test_reqresp.py
@@ -3,6 +3,8 @@
# Python 2 and 3: urlib.parse
from wfuzz.fuzzobjects import FuzzRequest
+from wfuzz.fuzzobjects import FuzzResultFactory
+from wfuzz.ui.console.clparser import CLParser
from wfuzz import __version__ as wfuzz_version
@@ -13,6 +15,46 @@
""".format(wfuzz_version)
+raw_response_header = b"""HTTP/1.0 200 Connection established
+
+HTTP/1.1 404 Not Found
+Content-Type: text/html; charset=UTF-8
+Referrer-Policy: no-referrer
+Content-Length: 1564
+Date: Wed, 24 Apr 2019 22:03:52 GMT
+Alt-Svc: quic=":443"; ma=2592000; v="46,44,43,39"
+Connection: close
+
+"""
+
+raw_response_body = b'\n\n \n \n Error 404 (Not Found)!!1\n \n \n 404. That\xe2\x80\x99s an error.\n
The requested URL /one
was not found on this server. That\xe2\x80\x99s all we know.\n'
+
+
+class FuzzResultFactoryTest(unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ super(FuzzResultFactoryTest, self).__init__(*args, **kwargs)
+ self.maxDiff = 1000
+
+ def test_baseline(self):
+ options = CLParser(['wfuzz', '-z', 'range,1-1', 'http://localhost:9000/FUZZ{first}']).parse_cl()
+ seed = FuzzResultFactory.from_options(options)
+ baseline = FuzzResultFactory.from_baseline(seed, options)
+
+ self.assertEqual(baseline.description, 'first')
+
+ options = CLParser(['wfuzz', '-z', 'range,1-1', '-z', 'range,2-2', 'http://localhost:9000/FUZZ{first}/FUZ2Z{second}']).parse_cl()
+ seed = FuzzResultFactory.from_options(options)
+ baseline = FuzzResultFactory.from_baseline(seed, options)
+
+ self.assertEqual(baseline.description, 'first - second')
+
+ def test_from_conn(self):
+ fr = FuzzRequest()
+ fr.update_from_raw_http(raw_req, 'https', raw_response_header, raw_response_body)
+
+ self.assertEqual(fr.code, 404)
+ self.assertEqual(fr.content.count("\n"), 11)
+
class FuzzRequestTest(unittest.TestCase):
def __init__(self, *args, **kwargs):
@@ -61,6 +103,21 @@ def test_seturl(self):
self.assertEqual(fr.path, "FUZZ")
self.assertEqual(fr.follow, False)
+ fr.url = "http://www.wfuzz.org:80/a"
+ self.assertEqual(fr.host, "www.wfuzz.org:80")
+
+ fr.url = "https://www.wfuzz.org:80/a"
+ self.assertEqual(fr.host, "www.wfuzz.org:80")
+
+ fr.url = "www.wfuzz.org:80/a"
+ self.assertEqual(fr.host, "www.wfuzz.org:80")
+
+ fr.url = "www.wfuzz.org:80"
+ self.assertEqual(fr.host, "www.wfuzz.org:80")
+
+ fr.url = "www.wfuzz.org"
+ self.assertEqual(fr.host, "www.wfuzz.org")
+
def test_setpostdata(self):
fr = FuzzRequest()
fr.url = "http://www.wfuzz.org/"
@@ -98,6 +155,19 @@ def test_setpostdata(self):
self.assertEqual(fr.method, "POST")
self.assertEqual(fr.params.post, {'a': '1'})
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/"
+ fr.params.post = "{'a': '1'}"
+ self.assertEqual(fr.method, "POST")
+ self.assertEqual(fr.params.post, {"{'a': '1'}": None})
+
+ fr = FuzzRequest()
+ fr.url = "http://www.wfuzz.org/"
+ fr.params.post = '1'
+ fr.headers.request = {'Content-Type': 'application/json'}
+ self.assertEqual(fr.method, "POST")
+ self.assertEqual(fr.params.post, {'1': None})
+
def test_setgetdata(self):
fr = FuzzRequest()
diff --git a/tox.ini b/tox.ini
index 0ad95c72..4089d33d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -21,7 +21,7 @@ commands = coverage erase
deps = coverage
[testenv:end]
-commands = coverage report --skip-covered --include '*python3.5/site-packages/wfuzz*' -m
+commands = coverage report --skip-covered --include '*python3.6/site-packages/wfuzz*' -m
deps = coverage
[testenv:codecov]
diff --git a/wfuzz_bash_completion b/wfuzz_bash_completion
new file mode 100644
index 00000000..f0f9861a
--- /dev/null
+++ b/wfuzz_bash_completion
@@ -0,0 +1,66 @@
+# wfuzz bash completion file
+# by Xavier Mendez (xavi.mendez@gmail.com) aka Javi
+
+_wfuzz() {
+
+ COMPREPLY=()
+ local cur prev
+ cur=${COMP_WORDS[COMP_CWORD]}
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ WFUZZ_EX="wfuzz"
+
+ # Change to your wordlists' base directory
+ WLDIR=$($WFUZZ_EX --ee files)
+
+ common_options="-z[PAYLOAD] --zD[DEFAULT] --zE[ENCODERS] --hc[HIDE_HTTP_CODES] -d[POST_DATA] "
+
+ case "$prev" in
+ -u)
+ COMPREPLY=( $( compgen -W "http https" -- $cur ) )
+ ;;
+ -w)
+ COMPREPLY=( $(compgen -W "$(find $WLDIR -type f -iname "*.txt")" -- $cur) )
+ ;;
+ -w)
+ COMPREPLY=( $(compgen -W "$(find $WLDIR -type f -iname "*.txt")" -- $cur) )
+ ;;
+ -z)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee payloads)" -- $cur))
+ ;;
+ -e)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee registrants)" -- $cur))
+ ;;
+ -m)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee iterators)" -- $cur))
+ ;;
+ -o)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee printers)" -- $cur))
+ ;;
+ --script-help)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee scripts)" -- $cur))
+ ;;
+ --script)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee scripts)" -- $cur))
+ ;;
+ --field)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee fields)" -- $cur))
+ ;;
+ --zE)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee encoders)" -- $cur))
+ ;;
+ -V)
+ COMPREPLY=( $( compgen -W "allvars allpost allheaders" -- $cur ) )
+ ;;
+ -X)
+ COMPREPLY=( $( compgen -W "FUZZ OPTIONS PUT DELETE POST GET TRACE CONNECT HEAD" -- $cur ) )
+ ;;
+ --hc)
+ COMPREPLY=( $( compgen -W "400 401 301 302 500 404 200" -- $cur ) )
+ ;;
+ *)
+ COMPREPLY=($(compgen -W "$($WFUZZ_EX --ee options)" -- $cur))
+ ;;
+ esac
+}
+
+complete -F _wfuzz -o default wfuzz
diff --git a/wordlist/vulns/dirTraversal-nix.txt b/wordlist/vulns/dirTraversal-nix.txt
index f0a4ca47..b2a88a86 100644
--- a/wordlist/vulns/dirTraversal-nix.txt
+++ b/wordlist/vulns/dirTraversal-nix.txt
@@ -845,3 +845,27 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\/etc/passwd
.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\/etc/passwd
.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\.\\..\\/etc/passwd
+%00../etc/passwd
+%00../%00../etc/passwd
+%00../%00../%00../etc/passwd
+%00../%00../%00../%00../etc/passwd
+%00../%00../%00../%00../%00../etc/passwd
+%00../%00../%00../%00../%00../%00../etc/passwd
+%00../%00../%00../%00../%00../%00../%00../etc/passwd
+%00../%00../%00../%00../%00../%00../%00../%00../etc/passwd
+.%00./etc/passwd
+.%00./.%00./etc/passwd
+.%00./.%00./.%00./etc/passwd
+.%00./.%00./.%00./.%00./etc/passwd
+.%00./.%00./.%00./.%00./.%00./etc/passwd
+.%00./.%00./.%00./.%00./.%00./.%00./etc/passwd
+.%00./.%00./.%00./.%00./.%00./.%00./.%00./etc/passwd
+.%00./.%00./.%00./.%00./.%00./.%00./.%00./.%00./etc/passwd
+..%00/etc/passwd
+..%00/..%00/etc/passwd
+..%00/..%00/..%00/etc/passwd
+..%00/..%00/..%00/..%00/etc/passwd
+..%00/..%00/..%00/..%00/..%00/etc/passwd
+..%00/..%00/..%00/..%00/..%00/..%00/etc/passwd
+..%00/..%00/..%00/..%00/..%00/..%00/..%00/etc/passwd
+..%00/..%00/..%00/..%00/..%00/..%00/..%00/..%00/etc/passwd