> For the complete documentation index, see [llms.txt](https://g4b0.gitbook.io/g4b0-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://g4b0.gitbook.io/g4b0-docs/documentation/hacking-web/xss.md).

# XSS

### Stored XSS

El primer tipo de vulnerabilidad XSS, y el más crítico, es el XSS Almacenado (*Stored XSS*) o XSS Persistente (*Persistent XSS*). Si el *payload* XSS que inyectamos se guarda en la base de datos del servidor (*back-end*) y se carga al visitar la página, significa que nuestro ataque es persistente y puede afectar a cualquier usuario que acceda a ella.

Esto hace que este tipo de XSS sea el más grave, ya que afecta a un público mucho más amplio: cualquier persona que visite la página se convertiría en víctima del ataque. Además, el XSS almacenado no suele ser fácil de eliminar, ya que generalmente es necesario borrar el *payload* directamente de la base de datos del *back-end*."

```html
<script>alert(window.origin)</script>
```

Como podemos ver, efectivamente apareció la alerta, lo que significa que la página es vulnerable a XSS, ya que nuestro *payload* se ejecutó con éxito. Podemos confirmarlo aún más revisando el código fuente de la página: basta con presionar `CTRL+U` o hacer clic derecho y seleccionar *Ver código fuente de la página*, y allí deberíamos encontrar nuestro *payload*:

```html
<div></div><ul class="list-unstyled" id="todo"><ul><script>alert(window.origin)</script>
</ul></ul>
```

*Consejo: Muchas aplicaciones modernas aíslan las entradas de usuario en IFrames externos para proteger la web principal del XSS. Por ello, es recomendable usar `window.origin` en tu alerta en lugar de un valor estático; esto revelará la URL real de ejecución y te confirmará exactamente qué formulario o IFrame es el vulnerable.*

Dado que algunos navegadores modernos bloquean la función `alert()`, es útil conocer *payloads* alternativos para confirmar una vulnerabilidad XSS:

* `<plaintext>`: Detiene la ejecución del código HTML posterior y lo muestra como texto sin formato.
* `<script>print()</script>`: Abre la ventana de impresión del navegador, un método que casi nunca es bloqueado.

Para comprobar si el XSS es Almacenado o Persistente, simplemente recarga la página. Si el *payload* se vuelve a ejecutar, significa que está guardado en el servidor (*back-end*) y que afectará a cualquier usuario que visite el sitio.

### Reflected XSS

Existen dos tipos de vulnerabilidades XSS No Persistentes (o temporales), las cuales solo afectan a la víctima específica y desaparecen al recargar o cambiar de página:

* XSS Reflejado: Ocurre cuando el servidor (*back-end*) recibe nuestra entrada y nos la devuelve sin filtrar ni sanitizar (como suele pasar en mensajes de error o confirmación). Al ser mensajes temporales, el *payload* se ejecuta solo en ese momento.
* XSS Basado en DOM: A diferencia del anterior, este se procesa íntegramente en el navegador del usuario (*front-end*), sin que los datos lleguen nunca al servidor.

Podemos probar introduciendo cualquier cadena de texto de prueba para ver cómo la procesa.

<figure><img src="/files/HC0uVxHLZfHCnwdr37Rs" alt=""><figcaption></figcaption></figure>

Como podemos observar, recibimos el mensaje *Task 'test' could not be added.*, el cual incluye nuestra entrada `test` como parte del error. Si este dato introducido no se filtró ni sanitizó, la página podría ser vulnerable a XSS. Podemos intentar inyectar el mismo *payload* XSS que utilizamos en la sección anterior y hacer clic en Add:

<figure><img src="/files/4Nx6lIZRpaC5aWwbqBHw" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/7hBJ3EPQFBerigOiAiwp" alt=""><figcaption></figcaption></figure>

En este caso, vemos que el mensaje de error ahora dice *Task '' could not be added.*. Dado que nuestro *payload* está dentro de una etiqueta `<script>`, el navegador no lo renderiza como texto visible, por lo que en su lugar solo obtenemos unas comillas simples vacías `''`. Nuevamente, podemos revisar el código fuente de la página para confirmar que el mensaje de error incluye nuestro *payload* XSS

```html
<div></div><ul class="list-unstyled" id="todo"><div style="padding-left:25px">Task '<script>alert(window.origin)</script>' could not be added.</div></ul>
```

Como podemos ver, las comillas simples efectivamente contienen nuestro *payload* XSS `'<script>alert(window.origin)</script>'`.

Si volvemos a visitar la página, el mensaje de error desaparece y nuestro *payload* ya no se ejecuta, lo que confirma que esta vulnerabilidad XSS es, en efecto, No Persistente.

Pero, si la vulnerabilidad no es persistente, ¿cómo podríamos utilizarla para atacar a una víctima?

Todo depende del tipo de petición HTTP que se utilice para enviar nuestra entrada al servidor. Podemos verificar esto abriendo las Herramientas de Desarrollador (*Developer Tools*) de Firefox con `CTRL+Shift+I` y seleccionando la pestaña de Red (*Network*). A continuación, podemos volver a introducir nuestro *payload* de prueba y hacer clic en Add para enviarlo:

<figure><img src="/files/IQAj98peFLNFDVfUT6GA" alt=""><figcaption></figcaption></figure>

Como podemos observar, la primera fila indica que nuestra petición fue una solicitud `GET`. Las peticiones `GET` envían sus parámetros y datos como parte de la URL. Por lo tanto, para atacar a un usuario, simplemente podemos enviarle una URL que contenga nuestro *payload*.

Para obtenerla, podemos copiarla directamente de la barra de direcciones de Firefox tras enviar el *payload* XSS, o bien hacer clic derecho sobre la petición `GET` en la pestaña de Red (*Network*) y seleccionar Copiar > Copiar URL (*Copy > Copy URL*). Una vez que la víctima visite este enlace, el *payload* XSS se ejecutará:

<figure><img src="/files/yc1JDCpUElXGHkgbMBSs" alt=""><figcaption></figcaption></figure>

### XSS Discovery

* Los scanners de vulnerabilidades web (Nessus, Burp Pro, ZAP) detectan los tres tipos de XSS mediante dos modos:
  * **Passive Scan:** revisa el código del lado cliente buscando vulnerabilidades DOM-based
  * **Active Scan:** envía payloads e inyecta en el source para verificar si se reflejan
* Las herramientas gratuitas funcionan identificando campos de input, enviando payloads XSS y comparando el source renderizado. Sin embargo, que el payload aparezca en el source **no garantiza ejecución exitosa** — siempre verificar manualmente
* Herramientas open-source destacadas: **XSStrike**, **Brute XSS**, **XSSer**
* Para aplicaciones populares/robustas, las herramientas automatizadas suelen fallar porque los desarrolladores ya parcharon las vulnerabilidades más conocidas. En esos casos, la revisión manual de código es el método más confiable
* El XSS puede inyectarse en **cualquier input HTML**, no solo en campos de formulario — incluye headers HTTP como `Cookie` o `User-Agent` si sus valores se renderizan en la página
* Las listas de payloads públicas cubren múltiples vectores e injection points (tras comilla simple, evasión de filtros, etc.). No todos los payloads funcionan en todos los contextos:
  * [PayloadAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings)
  * [Payload-Box](https://github.com/payloadbox/xss-payload-list)
* Copiar/pegar payloads manualmente es ineficiente. Para casos avanzados conviene escribir un script Python propio que automatice el envío y la comparación del source
* La revisión de código (front-end y back-end) es el método más confiable: entender exactamente cómo el input es procesado hasta llegar al browser permite escribir un payload personalizado con alta confianza de éxito

***

#### Aclaración de Conceptos

* **Source / Sink (DOM-based XSS):** El *source* es el punto de entrada del input del usuario (ej. `location.hash`). El *sink* es donde ese input se procesa de forma insegura (ej. `innerHTML`). Si el dato fluye del source al sink sin sanitizar, hay XSS DOM-based.

***

#### Instalación — XSStrike

```bash
git clone https://github.com/s0md3v/XSStrike.git
cd XSStrike
pip install -r requirements.txt
python xsstrike.py
```

#### Uso — XSStrike

```bash
python xsstrike.py -u "http://SERVER_IP:PORT/index.php?task=test"
```

* `-u` : URL objetivo con el parámetro a testear
* Verifica estado del WAF antes de lanzar payloads
* Genera hasta **3072 payloads** automáticamente
* Analiza reflections para optimizar los payloads generados

**Siempre verificar manualmente el resultado:** un payload encontrado en el source puede no ejecutarse por contexto de inyección, filtros o sanitización parcial.

***

#### Output Esperado

```
[~] Checking for DOM vulnerabilities
[+] WAF Status: Offline
[!] Testing parameter: task
[!] Reflections found: 1
[~] Analysing reflections
[~] Generating payloads
[!] Payloads generated: 3072
[+] Payload: <HtMl%09onPoIntERENTER+=+confirm()>
[!] Efficiency: 100
[!] Confidence: 10
[?] Would you like to continue scanning? [y/N]
```

***

#### Remediación

* Escapar y sanitizar todo input del usuario antes de renderizarlo en el DOM
* Usar `textContent` en lugar de `innerHTML` donde sea posible
* Implementar una política **CSP (Content Security Policy)** estricta


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://g4b0.gitbook.io/g4b0-docs/documentation/hacking-web/xss.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
