Solution de tacorabane pour Baguette VPN 1/2

web python

9 décembre 2023

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.

web_page

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…

api_image

… 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}