**Pardon me for my bad english**
Challenge Description:
Will you be able to find the flag in the universe/ ? I've been told that the guy who wrote this nice application called **server.py** is a huge fan of **nano** (yeah... he knows **vim** is better).
Challenge URL: [http://exploring-the-universe.ctf.insecurity-insa.fr/](http://exploring-the-universe.ctf.insecurity-insa.fr/)
Vulnerability: Path Traversal
According to the description, it seems we have to dump the source code in order to get the flag. But if we try to access **server.py** it returns 404 (Not Found) response code.
So how can we dump the source code?If we can't find the actual file, maybe we can find the *temp* file. Remember that the author of the source code used either **nano** or **vim**. The temp file format for nano is **\<filename\>.save** and the temp file for vim is **.\<filename\>.swp**. Now, we just have to dump the source code. We successfully dumped the source code by using the vim temp file.
[http://exploring-the-universe.ctf.insecurity-insa.fr/.server.py.swp](http://exploring-the-universe.ctf.insecurity-insa.fr/.server.py.swp) -> To dump the source code
After that, we look into the source code.```from pathlib import Pathfrom mimetypes import guess_typefrom aiohttp import web
ROOT = Path().resolve()print(ROOT)PUBLIC = ROOT.joinpath('public')
async def stream_file(request, filepath):    '''Streams a regular file    '''    filepath = PUBLIC.joinpath(filepath).resolve()    if filepath.is_dir():        return web.Response(headers={'DT': 'DT_DIR'})    if not filepath.is_file():        raise web.HTTPNotFound(headers={'DT': 'DT_UNKNOWN'})    try:        filepath.relative_to(ROOT)    except:        raise web.HTTPForbidden(reason="You can't go beyond the universe...")    mime, encoding = guess_type(str(filepath))    headers = {        'DT': 'DT_REG',        'Content-Type': mime or 'application/octet-stream',        'Content-Length': str(filepath.stat().st_size)    }    if encoding:        headers['Content-Encoding'] = encoding    resp = web.StreamResponse(headers=headers)                                                                                                                                                      await resp.prepare(request)                                                                                                                                                                     with filepath.open('rb') as resource:        while True:            data = resource.read(4096)            if not data: break            await resp.write(data)    return resp
async def handle_403(request):    '''Stream 403 HTML file    '''    return await stream_file(request, '403.html')
async def handle_404(request):    '''Stream 404 HTML file    '''    return await stream_file(request, '404.html')
def create_error_middleware(overrides):    '''Create an error middleware for aiohttp    '''    @web.middleware    async def error_middleware(request, handler):        '''Handles specific web exceptions based on overrides        '''        try:            response = await handler(request)            override = overrides.get(response.status)            if override:                return await override(request)            return response        except web.HTTPException as ex:            override = overrides.get(ex.status)            if override:                return await override(request)            raise    return error_middleware
def setup_error_middlewares(app):    '''Setup error middleware on given application    '''    error_middleware = create_error_middleware({        403: handle_403,        404: handle_404    })    app.middlewares.append(error_middleware)
async def root(request):    '''Web server root handler    '''    path = request.match_info['path']    if not path:        path = 'index.html'    path = Path(path)    print(f"client requested: {path}")    return await stream_file(request, path)
def app():    app = web.Application()    setup_error_middlewares(app)    app.add_routes([web.get(r'/{path:.*}', root)])    web.run_app(app)
if __name__ == '__main__':    app()```
From this source code, most of it is actually (not so) useless for us. The most important part of this source code is in the **stream_file function**.```ROOT = Path().resolve()print(ROOT)PUBLIC = ROOT.joinpath('public')
async def stream_file(request, filepath):    '''Streams a regular file    '''    filepath = PUBLIC.joinpath(filepath).resolve()    if filepath.is_dir():        return web.Response(headers={'DT': 'DT_DIR'})    if not filepath.is_file():        raise web.HTTPNotFound(headers={'DT': 'DT_UNKNOWN'})    try:        filepath.relative_to(ROOT)    except:        raise web.HTTPForbidden(reason="You can't go beyond the universe...")    mime, encoding = guess_type(str(filepath))    headers = {        'DT': 'DT_REG',        'Content-Type': mime or 'application/octet-stream',        'Content-Length': str(filepath.stat().st_size)    }    if encoding:        headers['Content-Encoding'] = encoding    resp = web.StreamResponse(headers=headers)                                                                                                                                                      await resp.prepare(request)                                                                                                                                                                     with filepath.open('rb') as resource:        while True:            data = resource.read(4096)            if not data: break            await resp.write(data)    return resp
```
And the most important part of the function is this one:```ROOT = Path().resolve()print(ROOT)PUBLIC = ROOT.joinpath('public')
filepath = PUBLIC.joinpath(filepath).resolve()```
From this piece of code, every path that we request, it will be appended with **/public/**. For example:Input: universe/flagResult: public/universe/flag
From there we can conclude that whatever the path we send to the server we will always get 404 response code (as far as the writer know).So, in order to access the flag file, we have to get back 1 directory and then access the *universe/flag*.
Final url to get the flag:
[https://exploring-the-universe.ctf.insecurity-insa.fr/..%2Funiverse/flag](https://exploring-the-universe.ctf.insecurity-insa.fr/..%2Funiverse/flag) -> To get the flag file
Flag:INSA{3e508f6e93fb2b6de561d5277f2a9b26bc79c5f349c467a91dd12769232c1a29}