D’après la description, nous avons à faire à un service web.
Démarrage du challenge
Commençons par lancer le challenge et rendez-vous à l’URL http://localhost:8000.
Nous ne sommes pas très avancés. Mais pas de panique, regardons le code source.
Ah ! Il se trouve qu’à la fin du code source HTML, nous avons deux URL en commentaire.
<!--
Changelog :
- Site web v0
- /api/image : CDN interne d'images
- /api/debug
TODO :
- VPN
-->
Si nous tentons d’y accèder, nous remarquons qu’à l’URL /api/image
nous demande un paramètre…
… et l’URL /api/debug
nous amène sur une page au format JSON :
{
"Flask": "['__annotations__', '__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_find_error_handler', '_get_exc_class_and_code', '_is_setup_finished', '_method_route', '_static_folder', '_static_url_path', 'add_template_filter', 'add_template_global', 'add_template_test', 'add_url_rule', 'after_request', 'app_context', 'app_ctx_globals_class', 'async_to_sync', 'auto_find_instance_path', 'before_first_request', 'before_request', 'config_class', 'context_processor', 'create_global_jinja_loader', 'create_jinja_environment', 'create_url_adapter', 'debug', 'default_config', 'delete', 'dispatch_request', 'do_teardown_appcontext', 'do_teardown_request', 'endpoint', 'ensure_sync', 'env', 'errorhandler', 'finalize_request', 'full_dispatch_request', 'get', 'get_send_file_max_age', 'got_first_request', 'handle_exception', 'handle_http_exception', 'handle_url_build_error', 'handle_user_exception', 'has_static_folder', 'inject_url_defaults', 'iter_blueprints', 'jinja_env', 'jinja_environment', 'jinja_loader', 'jinja_options', 'json_decoder', 'json_encoder', 'log_exception', 'logger', 'make_config', 'make_default_options_response', 'make_response', 'make_shell_context', 'name', 'open_instance_resource', 'open_resource', 'patch', 'permanent_session_lifetime', 'post', 'preprocess_request', 'preserve_context_on_exception', 'process_response', 'propagate_exceptions', 'put', 'raise_routing_exception', 'register_blueprint', 'register_error_handler', 'request_class', 'request_context', 'response_class', 'route', 'run', 'secret_key', 'select_jinja_autoescape', 'send_file_max_age_default', 'send_static_file', 'session_cookie_name', 'session_interface', 'shell_context_processor', 'should_ignore_error', 'static_folder', 'static_url_path', 'teardown_appcontext', 'teardown_request', 'template_filter', 'template_global', 'template_test', 'templates_auto_reload', 'test_cli_runner', 'test_cli_runner_class', 'test_client', 'test_client_class', 'test_request_context', 'testing', 'trap_http_exception', 'try_trigger_before_first_request_functions', 'update_template_context', 'url_defaults', 'url_map_class', 'url_rule_class', 'url_value_preprocessor', 'use_x_sendfile', 'wsgi_app']",
"Response": "['__annotations__', '__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_clean_status', '_ensure_sequence', '_is_range_request_processable', '_process_range_request', '_wrap_range_response', 'accept_ranges', 'access_control_allow_credentials', 'access_control_allow_headers', 'access_control_allow_methods', 'access_control_allow_origin', 'access_control_expose_headers', 'access_control_max_age', 'add_etag', 'age', 'allow', 'autocorrect_location_header', 'automatically_set_content_length', 'cache_control', 'calculate_content_length', 'call_on_close', 'charset', 'close', 'content_encoding', 'content_language', 'content_length', 'content_location', 'content_md5', 'content_range', 'content_security_policy', 'content_security_policy_report_only', 'content_type', 'cross_origin_embedder_policy', 'cross_origin_opener_policy', 'data', 'date', 'default_mimetype', 'default_status', 'delete_cookie', 'expires', 'force_type', 'freeze', 'from_app', 'get_app_iter', 'get_data', 'get_etag', 'get_json', 'get_wsgi_headers', 'get_wsgi_response', 'implicit_sequence_conversion', 'is_json', 'is_sequence', 'is_streamed', 'iter_encoded', 'json', 'json_module', 'last_modified', 'location', 'make_conditional', 'make_sequence', 'max_cookie_size', 'mimetype', 'mimetype_params', 'retry_after', 'set_cookie', 'set_data', 'set_etag', 'status', 'status_code', 'stream', 'vary', 'www_authenticate']",
"__annotations__": "['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']",
// ...
"__file__":"/app/baguettevpn_server_app_v0.py",
// ...
}
Il faut savoir que dans le framework web Flask, il nous est possible d’accèder à une zone de debug qui permet de gérer les erreurs. Cependant, ce mode de debug ne doit pas rester activé dans un environnement de production.
Si on regarde cette page attentivement, il est indiqué le nom d’un fichier Python : /app/baguettevpn_server_app_v0.py
.
Récupération du fichier Python
Maintenant que nous avons trouvé une information intéressante, il va falloir accéder au contenu de ce fichier.
/app/
correspond sûrement au dossier racine de l’application Flask.
Donc il nous faut juste entrer dans la barre d’adresse http://localhost:8000/baguettevpn_server_app_v0.py
. Et paf ! nous avons téléchargé le fichier Python.
Exploitation du fichier Pyhton
Ouvrez le fichier avec l’éditeur de votre choix.
Ne soyez pas trop rapide et regardez bien les commentaires du haut pour accéder au premier flag :)
# Congrats! Here is the flag for Baguette VPN 1/2
# FCSC{e5e3234f8dae908461c6ee777ee329a2c5ab3b1a8b277ff2ae288743bbc6d880}