Ce n'était pas un très bon résultat, mais j'ai participé au CTF 2024 des débutants de Seccon, donc je vais laisser un rédaction en tant que mémo.
ssrforfi
Vérifier la source
La structure du dossier après dézipper Tar.gz est la suivante:
$ trouver ./ ./ ./docker-compose.yml ./.env ./app ./app/app.py ./app/requiments.txt ./app/dockerfile ./app/uwsgi.ini ./nginx ./nginx/dockerfile ./nginx/nginx.conf.
Le contenu de chaque fichier est le suivant:
Services: uwsgi: build: ./app Env_file: - .env exposer: - "7777" Redémarrer: toujours nginx: build: ./nginx liens: - UWSGI PORTS: - "4989: 80" Environnement: TZ: "Asia / Tokyo" Restart: toujours
Copy nginx.conf /etc/nginx/nginx.conf cmd ["nginx", "-g", "daemon off;", "-c", "/etc/nginx/nginx.conf"]
utilisateur nginx; Worker_Processes 1; error_log /var/log/nginx/error.log Warn; pid /var/run/nginx.pid; Événements {Worker_Connections 1024; } http {include /etc/nginx/mime.types; Default_type Application / Octet-Stream; LOG_FORMAT MAIN '$ Remote_addr - $ Remote_User [$ time_local] "$ request"' '$ status $ body_bytes_sent "$ http_referrer"' "$ http_user_agent" "$ http_x_forwarded_for" '; Access_log /var/log/nginx/access.log main; SendFile sur; keepalive_timeout 65; uwsgi en amont {serveur uwsgi: 7777; } Server {écouter 80; Merge_slashes off; Emplacement / {inclue uwsgi_params; uwsgi_pass uwsgi; }}}
Depuis Ubuntu: 22.04 env depian_fronttend non interactif run apt-get -y mise à jour - fixe-missing && apt-get -y mise à niveau run apt-get -y install python3 python3-pip curl run mkdir / var / www workdir / var / www copy ./. / var / www run addUser -U 1000 ssrforlfi utilisateur ssrforlfi cmd ["uwsgi", "- in", "/var/www/uwsgi.ini"]
FLASK == 3.0.0 UWSGI == 2.0.23
[uwsgi] wsgi-file = app.py callable = app maître = true processes = 4 threads = 4 socket =: 7777 chmod-socket = 666 vide = true die-onter = true py-utoreload = 1
Importer OS Import re Importer le sous-processus depuis FLASK Importer Flask, request app = flask (__ name__) @ app.Route ("/") def ssrforlfi (): url = request.args.get ("url") sinon URL: renvoyez "bienvenue à la vue de site Web.<br> <code>?url=http://example.com/</code> "# autoriser uniquement az,", (,),., / ,:,;, <,>, @, | Si pas re.match ('^ [az "() ./:; <> @ |] * $', url): renvoie" URL non valide; ("# ssrf & lfi Protection if url.startswith (" http: // ") ou url.startswith (" https: // "): if" localhost "dans url: return" ssrf; ("eflif url.startswith ("fichier: //"): path = url [7:] if os.path.exists (path) ou ".." dans le chemin: return "détecté lfi; (" else: # bloquer les autres schémas return "invalide scheme; (" try: # rce? proc = subprocess.run (f "curl '{url}" ",", capture_output = true = true = tex timeout = 1,) sauf sub-process.TimeoutExpired: 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)
répondre
Que fait l'application est une application qui fait une demande à l'URL spécifiée par le paramètre URL "? Url = xxx" et renvoie le contenu en réponse.
Le contenu est très simple, mais j'ai dû percer les protections de SSRF et LFI et d'obtenir le drapeau.
La première chose à noter est le code ci-dessous.
HTTP et HTTPS valident localhost. Cependant, le fichier ne valide pas LocalHost.
# Ssrf & lfi protection if url.startswith ("http: //") ou url.startswith ("https: //"): if "localhost" dans url: return "détecté ssrf; (" elif url.startswith ("fichier: //"): path = url [7:] if Os.path.exists (path) ou "dans" dans le chemin: discours:] if os.path.exists (chemin) ou "dans" dans le chemin: Deth:] If Os.path.Exists (Path) ou "dans" dans le chemin: Dethe Lfi; ("Else: # Bloc d'autres schémas renvoient" Schéma non valide; ("
Le schéma de fichier: //
peut accéder aux fichiers locaux, il peut donc être possible de lire les variables d'environnement, etc.
En d'autres termes, il semble que vous puissiez obtenir l'indicateur si possible ? Url = fichier: // localhost / [fichier où vous pouvez vérifier les variables d'environnement]
Cela signifie que
les variables d'environnement pour le processus actuel / proc / self / Environ
Enfin, je vais l'essayer avec ? Url = file: // localhost / proc / self / environnement
Maintenant, vous obtenez le drapeau.

Je pensais que c'était quelque chose à faire de la commande d'injection, mais je n'ai pas pu résoudre le problème dans le délai.
Laveur
Requête