Los fuzzers son herramientas bien conocidas por los pentesters, estos nos permiten inyectar entradas inesperadas a una aplicación para ver como responde, en este caso vamos a utilizar FFuF un fuzzer web que además de poder ver la manera en la que responde la aplicación también nos servirá para descubrir paths y API endpoints.
Instalamos el fuzzer en cuestión:
Cuando fuzeemos haremos sustituciones de partes de las peticiones por otras que nosotros elijamos, una buena lista de palabras a comprobar puede ser la siguiente:
FFuF puede ser vinculado a un proxy que tengamos en marcha, de este modo solo las peticiones que han retornado un código HTTP permitido, por defecto: 200,204,301,302,307,401,403,405,500, serán enviadas a este proxy:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
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 ::
Podemos ver como a Burp solo le ha llegado la petición que ha retornado un 302, no las 222:
Si la aplicación requiere el uso de cookies, podemos forjarlas del siguiente modo:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
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 ::
Podemos ver como la petición lleva la cookie indicada:
Mediante FFuF también podemos fuzzear cabeceras HTTP:
Podemos ver como las peticiones llevan el user-agent fuzzeado:
Si tenemos algún tipo de restricción de tráfico por parte del servidor web, balanceador de tráfico, WAF o algún otro mecanismo, podemos limitar las peticiones por segundo mediante el parámetro -r:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
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 ::
También es posible fuzzear dos parámetros de forma simultánea:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
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 ::
Los resultados devueltos por FFuF pueden ser filtrados de dos modos distintos.
Matchers: Muestra peticiones/respuestas cuyo patrón machee.
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: Elimina peticiones/respuestas cuyo patrón machee.
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
En este ejemplo solo vamos a machear respuestas 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 ::
A veces la página responde con un 200 pero un mensaje de error como podrÃa ser:
{ 'not found': true }
En tal caso podemos desechar estas respuestas con el siguiente filtro:
Por supuestos FFuF también nos permite enviar peticiones POST, si interceptamos un login podemos ver los siguientes campos posteados:
Nos disponemos a fuzzear el campo validar:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
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 ::
En Burp podemos ver las peticiones enviadas:
Un aspecto muy interesante de FFuF es que no nos limita a fuzzear los valores de los parámetros existentes si no que podemos fuzzear los propios parámetros:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
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 ::
En Burp podemos ver las peticiones enviadas:
También podemos postear parámetros Json:
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
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 ::
En Burp podemos ver las peticiones enviadas: