This page looks best with JavaScript enabled

HTTP Fuzzing with FFuF

 ·  🎃 kr0m

Fuzzers are well-known tools for pentesters. They allow us to inject unexpected inputs into an application to see how it responds. In this case, we will use FFuF , a web fuzzer that will not only allow us to see how the application responds, but also help us discover paths and API endpoints.

We install the fuzzer:

pkg install ffuf

When we fuzz, we will substitute parts of the requests with others that we choose. A good list of words to check can be found here:

FFuF can be linked to a proxy that we have running, so that only requests that have returned an allowed HTTP code, by default: 200,204,301,302,307,401,403,405,500, will be sent to this proxy:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/FUZZ -o output.txt -replay-proxy http://192.168.69.204:8081


        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : https://XXXXXXXXXX.com/FUZZ
 :: Wordlist         : FUZZ: actions.txt
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

admin                   [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 190ms]
:: Progress: [222/222] :: Job [1/1] :: 120 req/sec :: Duration: [0:00:02] :: Errors: 0 ::

We can see how Burp has only received the request that returned a 302, not the 222:

If the application requires the use of cookies, we can forge them as follows:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/FUZZ -o output.txt -replay-proxy http://192.168.69.204:8081 -b "Cookie: _ga=GA1.2.135180862.1669714648; _gid=GA1.2.334284534.1669893254; PHPSESSID=cmh79qfsgolamu70lhcvkb4dmi; acceptCookie=1; _gat_gtag_UA_11506612_2=1"

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : https://XXXXXXXXXX.com/FUZZ
 :: Wordlist         : FUZZ: actions.txt
 :: Header           : Cookie: Cookie: _ga=GA1.2.135180862.1669714648; _gid=GA1.2.334284534.1669893254; PHPSESSID=cmh79qfsgolamu70lhcvkb4dmi; acceptCookie=1; _gat_gtag_UA_11506612_2=1
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

admin                   [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 921ms]
:: Progress: [222/222] :: Job [1/1] :: 31 req/sec :: Duration: [0:00:07] :: Errors: 0 ::

We can see how the request carries the indicated cookie:

Through FFuF, we can also fuzz HTTP headers:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/admin -o output.txt -replay-proxy http://192.168.69.204:8081 -H "user-agent:FUZZ"

We can see how the requests carry the fuzzed user-agent:

If we have any kind of traffic restriction by the web server, traffic balancer, WAF, or any other mechanism, we can limit the requests per second using the -r parameter:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/FUZZ -o output.txt -replay-proxy http://192.168.69.204:8081 -rate 2

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : https://XXXXXXXXXX.com/FUZZ
 :: Wordlist         : FUZZ: actions.txt
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

admin                   [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 192ms]
:: Progress: [222/222] :: Job [1/1] :: 2 req/sec :: Duration: [0:00:52] :: Errors: 0 ::

It is also possible to fuzz two parameters simultaneously:

ffuf -w actions.txt:FUZZ -w actions.txt:SECOND -u https://XXXXXXXXXX.com/FUZZ/SECOND -o output.txt -replay-proxy http://192.168.69.204:8081

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : https://XXXXXXXXXX.com/FUZZ/SECOND
 :: Wordlist         : FUZZ: actions.txt
 :: Wordlist         : SECOND: actions.txt
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________


:: Progress: [49284/49284] :: Job [1/1] :: 119 req/sec :: Duration: [0:06:58] :: Errors: 0 ::

The results returned by FFuF can be filtered in two different ways.
Matchers: Show requests/responses whose pattern matches.

MATCHER OPTIONS:
  -mc                 Match HTTP status codes, or "all" for everything. (default: 200,204,301,302,307,401,403,405,500)
  -ml                 Match amount of lines in response
  -mmode              Matcher set operator. Either of: and, or (default: or)
  -mr                 Match regexp
  -ms                 Match HTTP response size
  -mt                 Match how many milliseconds to the first response byte, either greater or less than. EG: >100 or <100
  -mw                 Match amount of words in response

Filters: Eliminate requests/responses whose pattern matches.

FILTER OPTIONS:
  -fc                 Filter HTTP status codes from response. Comma separated list of codes and ranges
  -fl                 Filter by amount of lines in response. Comma separated list of line counts and ranges
  -fmode              Filter set operator. Either of: and, or (default: or)
  -fr                 Filter regexp
  -fs                 Filter HTTP response size. Comma separated list of sizes and ranges
  -ft                 Filter by number of milliseconds to the first response byte, either greater or less than. EG: >100 or <100
  -fw                 Filter by amount of words in response. Comma separated list of word counts and ranges

In this example, we are only going to match 302 responses:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/FUZZ -o output.txt -replay-proxy http://192.168.69.204:8081 -fc 302

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : https://XXXXXXXXXX.com/FUZZ
 :: Wordlist         : FUZZ: actions.txt
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
 :: Filter           : Response status: 302
________________________________________________

:: Progress: [222/222] :: Job [1/1] :: 119 req/sec :: Duration: [0:00:02] :: Errors: 0 ::

Sometimes the page responds with a 200 but an error message such as:

{ 'not found': true }

In such a case, we can discard these responses with the following filter:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/FUZZ -o output.txt -replay-proxy http://192.168.69.204:8081 -fr "not found"

Of course, FFuF also allows us to send POST requests. If we intercept a login, we can see the following fields posted:

We are going to fuzz the validate field:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/cliente -o output.txt -replay-proxy http://192.168.69.204:8081 -X POST -d "nick=kr0m%40alfaexploit.com&pwd=123PASSWORD123&recordarme=1&validar=FUZZ"


        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : POST
 :: URL              : https://XXXXXXXXXX.com/cliente
 :: Wordlist         : FUZZ: actions.txt
 :: Data             : nick=kr0m%40alfaexploit.com&pwd=123PASSWORD123&recordarme=1&validar=FUZZ
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

:: Progress: [222/222] :: Job [1/1] :: 8 req/sec :: Duration: [0:00:24] :: Errors: 0 ::

In Burp, we can see the sent requests:

A very interesting aspect of FFuF is that it does not limit us to fuzzing the values of existing parameters, but we can also fuzz the parameters themselves:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/cliente -o output.txt -replay-proxy http://192.168.69.204:8081 -X POST -d "nick=kr0m%40alfaexploit.com&pwd=123PASSWORD123&recordarme=1&validar=&FUZZ=valor_inventado"

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : POST
 :: URL              : https://XXXXXXXXXX.com/cliente
 :: Wordlist         : FUZZ: actions.txt
 :: Data             : nick=kr0m%40alfaexploit.com&pwd=123PASSWORD123&recordarme=1&validar=&FUZZ=valor_inventado
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

:: Progress: [222/222] :: Job [1/1] :: 5 req/sec :: Duration: [0:00:38] :: Errors: 0 ::

In Burp, we can see the sent requests:

We can also post Json parameters:

ffuf -w actions.txt -u https://XXXXXXXXXX.com/cliente -o output.txt -replay-proxy http://192.168.69.204:8081 -X POST -H "Content-Type: application/json" -d "{'FUZZ':'kr0m%40alfaexploit.com'}"

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v1.5.0-dev
________________________________________________

 :: Method           : POST
 :: URL              : https://XXXXXXXXXX.com/cliente
 :: Wordlist         : FUZZ: actions.txt
 :: Header           : Content-Type: application/json
 :: Data             : {'FUZZ':'kr0m%40alfaexploit.com'}
 :: Output file      : output.txt
 :: File format      : json
 :: Follow redirects : false
 :: Calibration      : false
 :: ReplayProxy      : http://192.168.69.204:8081
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________

:: Progress: [222/222] :: Job [1/1] :: 5 req/sec :: Duration: [0:00:37] :: Errors: 0 ::

In Burp, we can see the sent requests:

If you liked the article, you can treat me to a RedBull here