Entrada

JWT Lab 5

JWT Lab 5

Skills

  • JWT authentication bypass via jku header injection

Certificaciones

  • eWPT
  • eWPTXv2
  • OSWE
  • BSCP

Descripción

Este laboratorio utiliza un mecanismo basado en JWT para manejar las sesiones. El servidor admite el parámetro jku en el encabezado del JWT. Sin embargo, no verifica si la URL proporcionada pertenece a un dominio de confianza antes de obtener la clave. Para resolver el laboratorio, debemos forjar un JWT utilizando una URL maliciosa en el parámetro jku. Esta URL debe apuntar a un servidor bajo nuestro control, donde alojaremos una clave pública diseñada para verificar nuestro JWT modificado. Una vez que el servidor acepte nuestro JWT, obtendremos acceso al panel de administración en /admin y eliminaremos al usuario carlos. Podemos iniciar sesión en nuestra propia cuenta utilizando las credenciales wiener:peter


Resolución

Al acceder a la web nos sale esto

Pulsamos en My account y nos logueamos con las credenciales wiener:peter

Recargamos con F5 y capturamos la petición con Burpsuite

Este es el JWT, lo vemos así gracias a la extensión JWT Editor

Vemos que el algoritmo usado en un RS256, nos dirigimos a la ventana JWT Editor y nos creamos una clave privada RSA pulsando en New RSA Key

Nos dirigimos al Exploit server y pegamos este JSON, que es la clave privada en el body

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    "keys": [
    
        {
            "p": "5uY4PlzLzwgO4g3LtAxzC5SUOtBaq4HhxeW5YPNKDBL34NxUufvOjHeUz16LQBFGWlBgobX-yYGDw4nj_MDD5Qv1XxjLEQ19nrAfTaFfsysK48JP1d-6h6abYsBm_fESj54HumkncvkUIx85OoCXz0jj679t_MbutKUGdocxvx8",
            "kty": "RSA",
            "q": "v44iZ9OE1u1bR8AOiXdDIRcAksofJgsWDRkPemEukn_krCitsXpyvUPksCOLY1BrlLUdtL1ODRoPW72sWBWsJ4fecb3oHmPt2qpgX0KWdg0Sx7tXrRPd49mUrX6TLFl_0zvvaFW_kR_xIOJZbgbFIGe0ngUmy-ofzUTdmSV3C1M",
            "d": "EwlX1HlcaUIzcWZIpcM5XwfLilRURz2Kc2ATTDuKGx0xjz9PwwbVV0LkMnZCxWmDX0ZEHTccxPsrM9BoC7bjx7rPhqE16bhc_pGOH_ty_Uqq1Ezk-bwHSjimfOvFNsiv2IVUmOfW2In_o7JrfmYgn1VqJXG626EE0VMFwkFT7U4nYcXhEljiIxmeJTcdHDwocALRXgphVQtDo5NG7CdjsxtKnncv9_Ke4QmoPeeRGSe7l-pMyNsnwryr1VL72fzVfOVfkBaxsV0XKwmr3EcWL0pEYdDmjrsv7Nq9hIMbRE71OYQVa5kLuLexp3TxmhYOjXaZc9p17TE--FkbP243",
            "e": "AQAB",
            "kid": "1413e558-09db-4e90-a475-fc2b41665c6a",
            "qi": "vJqiRzmZT73cbdMjtkJdm3wxHk0qTH1-yvucm8vzR_sx1HuJdYjM52-NVuOutfFiuDQ1P--I5ZyqtyfLidTpMUZMMVVL8Sj8iNIV6XEmO07hXzRmQwaMYzkQ5a_vpE8YG-QZ2fPx9u3XX2iQ-A55WUC8ET1lVXHfWAM_bcmxzTM",
            "dp": "Cs8kOuclM1_xMmvq6Vbb2-LsvYQbeoPuCdGjSAKbqM0KhaBK5xn-pVzDvqFya2Fjpb61h1x5vP0vKew-nAp6ITLaHcWPXBEBnHgqPvwa-sw9CkSCcES0-ry18X2IVMMAV3DSc8uQaTV3190SVMbIVI_Y-6ROhdLaQeKn1syla4k",
            "dq": "a5ie4ssA9ujkOO08PSLsZg3RmKJH1MqtXDYTZ55m1otYGwvOZL5u7LjSH84XYXWuuBzzzq32xY05y0JDKEckKCA9Zo5Rb6CZ3hWNhHSWp0C4p9Anc2SRYoa46KsMaADtt-0WkPh5Xj8e5mW97fuHhqg53_jszeV4b4ibIIbW01k",
            "n": "rMX2sfK0AtkwMN0A3FH2OyKL0FclVpdf2Df95mlZ3q4PMG0vSFoluzOBHHCaUod6wxSP8OM3J34ulPzEi3zT9arkzzCQ0buTy6TL4TXMLa-YlQXnVaBsQ3k6qoOo5TUt65JSAJTxWEQD0RJuD9BIDFXkGV5YWvN241lV_cesNsXyLQyUehvPCG1mvC4Zn3HLh686A_X7JPMQI7230OkNnyOD99mdGUFYhRHcSFI8Gvz3WQKWQyzYgXN9mCnEweNS4VLqxHaQr6c-8DLz90w_ZN4bb9dl-EKZv_sGPZGP56v7eWvJLDdKsFnwLVBnRtyDQnP_BIzT_V0hYDWDSsBMDQ"
        }
    ]
}

Debido a que estamos tramitando un JSON, debemos cambiar el Content-Type en el Head a application/json

1
Content-Type: application/json

Cambiamos el nombre de usuario a administrator

Actualizamos el kid, el cual debe ser el mismo que el de la clave privada que hemos generado y añadimos el parámetro jku que apunta al servidor desde donde cargaremos la clave RSA

Firmamos el JSON con la clave privada

Hacemos una petición a /admin para comprobar que nos hemos convertido en administrador

En el navegador pulsamos Ctrl + Shift+ i y pegamos la cookie

Refrescamos la web con F5 y ya podemos eliminar al usuario carlos

Hemos podido vulnerar este laboratorio debido a que, en lugar de incorporar claves públicas directamente mediante el parámetro de encabezado jwk, algunos servidores permiten utilizar el parámetro de encabezado jku (URL del conjunto JWK) para hacer referencia a un conjunto JWK que contiene la clave. Durante el proceso de verificación de la firma, el servidor obtiene la clave relevante desde esta URL. Este es un ejemplo de un conjunto de claves JWK al cual podemos acceder mediante el parámetro jku

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
    "keys": [
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
            "n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
        },
        {
            "kty": "RSA",
            "e": "AQAB",
            "kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
            "n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
        }
    ]
}

Conjuntos JWK como este a veces se exponen públicamente a través de un endpoint estándar, como /.well-known/jwks.json. Los sitios web más seguros solo obtienen claves de dominios confiables, pero a veces puedes aprovechar las discrepancias en el análisis de la URL para evitar este tipo de filtrado. En este laboratorio se está confiando en dominios externos, esto se solucionaría teniendo una whitelist de dominios confiables. Hay algunos ejemplos en este laboratorio de PortSwigger https://portswigger.net/web-security/ssrf#ssrf-with-whitelist-based-input-filters sobre SSRF

Esta entrada está licenciada bajo CC BY 4.0 por el autor.