[Seccon Beginners CTF 2024] Escritura web

No fue un muy buen resultado, pero participé en el Seccon Beginners CTF 2024, así que dejaré un resumen como memo.

Tabla de contenido

ssrforfi

Verificación de la fuente

La estructura de la carpeta después de desabrochar tar.gz es la siguiente:

$ Find ./ ./ ./docker-compose.yml ./.env ./app ./app/app.py ./app/requirements.txt ./app/dockerfile ./app/uwsgi.ini ./nginx ./nginx/dockerfile ./nginx/nginx.conf

El contenido de cada archivo es el siguiente:

Servicios: UWSGI: Build: ./App Env_File: - .env Expose: - "7777" Reiniciar: Siempre Nginx: Build: ./nginx Enlaces: - UWSGI Puertos: - "4989: 80" Ambiente: TZ: "Asia/Tokio" Reinicio: siempre siempre
Copiar nginx.conf /etc/nginx/nginx.conf cmd ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]] 
usuario nginx; trabajador_procesos 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; eventos {trabajador_connections 1024; } http {include /etc/nginx/mime.types; APLICACIÓN DE LA APLICACIÓN/OCTETA DEFORT_TYPE; log_format Main '$ Remote_addr - $ remoto_user [$ Time_local] "$ request"' '$ status $ body_bytes_sent "$ http_referer"' "$ http_user_agent" "$ http_x_forwarded_for" '; access_log /var/log/nginx/access.log main; SendFile On; KeepAlive_TimeOut 65; Upstream UWSGI {Server Uwsgi: 7777; } servidor {escuchar 80; fusion_slashes apagado; ubicación / {incluir UWSGI_PARAMS; uwsgi_pass uwsgi; }}}
Desde Ubuntu: 22.04 Env Debian_Frontend No Interactive Run APT-GET -Y Update--FIX-MISSING && APT-GET -Y UPICADA Ejecutar apt-get -y install python3 python3-pip curl run mkdir/var/www workdir/var/var/wwwww ./ -R/var/www run adduser -u 1000 ssrforlfi usuario ssrforlfi cmd ["uwsgi", "--ini", "/var/www/uwsgi.ini"]]  
Flask == 3.0.0 Uwsgi == 2.0.23
[UWSGI] wsgi-file = app.py calable = app master = verdadero procesos = 4 hilos = 4 socket =: 7777 chmod-socket = 666 vacuum = true die-on-término = true py-autoreload = 1 
importar importación de subprocesos de importación de frascas de importación frasco, solicitud app = frask (__ name__) @app.route ("/") def ssrforlfi (): url = request.args.get ("url") si no url: devolver "bienvenido al espectador del sitio web.<br> <code>?url=http://example.com/</code> " # Permitir solo AZ,", (,),.,/,:,;, <,>, @, | si no re.match ('^[AZ "() ./ :; <>@|]*$', url): devuelve" url inválido; (" # ssrf & lfi protección if url.startswith (" http: // ") o url.startswith (" https: // "): si" localhost "en url: regreso" detectado url.startswith("file://"): path = url[7:] if os.path.exists(path) or ".." in path: return "Detected LFI ;(" else: # Block other schemes return "Invalid Scheme ;(" try: # RCE ? proc = subprocess.run( f"curl '{url}'", capture_output=True, shell=True, text=True, Tiempo de espera = 1,) excepto subprocesos. TIMEOTEXPIRED: return "timeout; (" if proc.returncode! = 0: return "Error; (" return Proc.stdout if __name__ == "__main__": app.run (debug = true, host = "0.0.0.0", port = 4989)

respuesta

Lo que está haciendo la aplicación es una aplicación que hace una solicitud a la URL especificada por el parámetro URL "? URL = xxx" y devuelve el contenido como respuesta.

El contenido es muy simple, pero tuve que romper las protecciones de SSRF y LFI y obtener la bandera.

Lo primero que debe tener en cuenta es el siguiente código.
HTTP y HTTPS están validando localhost. Sin embargo, el archivo no valida localhost.

# Ssrf & lfi Protection if url.startswith ("http: //") o url.startswith ("https: //"): si "localhost" en url: ull: return "detectado ssrf; (" Elif url.startswith ("archivo: //"): ruta = URL [7:] if Os.path.exists (oxists (oxists (oxists (sendero ". Lfi; ("else: # bloquea otros esquemas return" esquema inválido; ("

El esquema del archivo: // puede acceder a archivos locales, por lo que es posible leer las variables de entorno, etc.
En otras palabras, parece que puede obtener la bandera si es posible ? Url = archivo: // localhost/[archivo donde puede verificar las variables de entorno]

Esto significa que
las variables de entorno para el proceso actual /proc/self/ambiente Finalmente, lo intentaré con ? Url = archivo: // localhost/proc/self/ambiente

Ahora obtienes la bandera.

Pensé que era algo para hacer una inyección de comando, pero no pude resolver el problema dentro del límite de tiempo.

Wooorker

Requestbin

¡Comparte si quieres!

Quien escribió este artículo

Este es un blog que comencé a estudiar la seguridad de la información. Como nuevo empleado, sería feliz si pudieras mirar con un corazón amplio.
También está Teech Lab, que es una oportunidad para estudiar diversión de programación, por lo que si está interesado en el desarrollo de software, ¡asegúrese de echar un vistazo!

Tabla de contenido