No fue un muy buen resultado, pero participé en el Seccon Beginners CTF 2024, así que dejaré un resumen como memo.
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