commit a0bd3d833d916cadd23d17d0b3784e28c729967d
parent aeb66a7b19008fabecbca23a1e21a9d6942ec28a
Author: Louis Burda <quent.burda@gmail.com>
Date: Thu, 24 Jun 2021 02:52:21 +0200
various fixes made while stress-testing exploit
Diffstat:
10 files changed, 170 insertions(+), 117 deletions(-)
diff --git a/checker/src/checker.py b/checker/src/checker.py
@@ -8,6 +8,8 @@ logging.getLogger("faker").setLevel(logging.WARNING)
logging.getLogger("pwnlib").setLevel(logging.WARNING)
logging.getLogger("_curses").setLevel(logging.CRITICAL)
+rand = random.SystemRandom()
+
from faker import Faker
# DEBUGING MEMORY ISSUES#
@@ -63,18 +65,20 @@ class STLDoctorChecker(BaseChecker):
def closeconn(self, conn):
self.debug("Sending exit command")
conn.write("exit\n")
+ # ensure it is a clean exit
+ conn.recvuntil("bye!")
conn.close()
def fakeid(self):
fake = Faker(["en_US"])
allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz0123456789-+.!"
- 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)])
+ idstr = "".join([c for c in fake.name().replace(' ','') if c in allowed][:12]).ljust(10, '.')
+ idstr += "".join([rand.choice(allowed) for i in range(8)])
return idstr
def havocid(self):
- idlen = random.randint(10, 60)
- return "".join([chr(random.randint(32, 127)) for i in range(idlen)])
+ idlen = rand.randint(10, 40)
+ return "".join([chr(rand.randint(32, 127)) for i in range(idlen)])
def do_auth(self, conn, authstr):
authstr = ensure_bytes(authstr)
@@ -113,10 +117,10 @@ class STLDoctorChecker(BaseChecker):
content = b"solid " + solidname + b"\n"
else:
content = b"solid\n"
- facet_count = random.randint(4, 30)
+ facet_count = rand.randint(4, 30)
for fi in range(facet_count):
content += b"facet normal "
- vs = [[random.random() for i in range(3)] for k in range(3)]
+ vs = [[rand.random() for i in range(3)] for k in range(3)]
norm = np.cross(np.subtract(vs[1], vs[0]), np.subtract(vs[2],vs[0]))
norm = norm / np.linalg.norm(norm)
content += " ".join([f"{v:.2f}" for v in norm]).encode() + b"\n"
@@ -141,10 +145,10 @@ class STLDoctorChecker(BaseChecker):
content = b"#" + solidname.ljust(78, b"\x00") + b"\x00"
else:
content = b"#" + b"\x00" * 79
- facet_count = random.randint(4, 30)
+ facet_count = rand.randint(4, 30)
content += struct.pack("<I", facet_count)
for fi in range(facet_count):
- vs = [[random.random() for i in range(3)] for k in range(3)]
+ vs = [[rand.random() for i in range(3)] for k in range(3)]
norm = np.cross(np.subtract(vs[1], vs[0]), np.subtract(vs[2],vs[0]))
for i in range(3):
content += struct.pack("<f", norm[i])
@@ -184,7 +188,7 @@ class STLDoctorChecker(BaseChecker):
modelid = line.rsplit(b"!", 1)[0].split(b"with ID ", 1)[1]
if modelid == b"": raise Exception
except:
- raise BrokenServiceException(f"Invalid response during upload of {modelname}")
+ raise BrokenServiceException(f"Invalid response during upload of {modelname}:\n{line}")
# Consume rest of data in this call
conn.recvuntil(self.prompt)
@@ -202,7 +206,7 @@ class STLDoctorChecker(BaseChecker):
conn.write("y\n" if download else "\n")
# Wait for end of info box
- resp = conn.recvuntil("==================")
+ resp = conn.recvuntil("================== \n")
# Ask for download if desired
if download:
@@ -352,22 +356,36 @@ class STLDoctorChecker(BaseChecker):
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")
+ index_dict = {fl[1]: fl[0] for fl in filelist}
+ targets = [fl[1] for fl in filelist]
# 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])
- conn.write(filelist[i][0] + b"\ny\n")
+ self.debug("Targets:\n" + "\n".join([' - ' + l.decode('latin1') for l in targets]))
+ for i,fhash in enumerate(targets):
+ if index_dict[fhash] == None:
+ self.debug(b"Skipping now missing file " + fhash)
+ continue
+
+ # Retrieve current file
+ self.debug(b"Retrieving file " + fhash + b" at index " + index_dict[fhash])
+ conn.write(index_dict[fhash] + b"\ny\n")
fileinfo = conn.recvuntil(self.prompt)
- self.debug("File contents:\n" + fileinfo.decode("latin1"))
+ # self.debug("File contents:\n" + fileinfo.decode("latin1"))
found = self.search_flag_bytes(fileinfo)
- if found is not None or i == len(filelist) - 1:
+ if found is not None or i == len(targets) - 1:
break
# Parse evil file again for next iter
self.getfile(conn, name, download=False)
conn.write("search last\n")
- conn.recvuntil("?")
+
+ # Update indicies from new search
+ filelist = [l.strip().split(b" : ") for l in conn.recvuntil("?").split(b"\n") if b" : " in l]
+ index_dict = {name : None for name in targets}
+ for fl in filelist:
+ index_dict[fl[1]] = fl[0]
+
self.closeconn(conn)
if found is None:
diff --git a/checker/src/gunicorn.conf.py b/checker/src/gunicorn.conf.py
@@ -1,10 +1,8 @@
import multiprocessing
-worker_class = "gevent"
+worker_class = "eventlet"
workers = multiprocessing.cpu_count() * 2 + 1
bind = "0.0.0.0:3031"
timeout = 90
keepalive = 3600
-max_requests = 100
preload_app = True
-max_requests_jitter = 30
diff --git a/checker/src/requirements.txt b/checker/src/requirements.txt
@@ -3,14 +3,14 @@ chardet==4.0.0
click==7.1.2
dnspython==1.16.0
# enochecker==0.4.2
-# git+https://github.com/enowars/enochecker@e1ce01b510b0d9e05d292a11a24c809bca1c181b
-git+https://github.com/Sinitax/enochecker@7fbc1b9ad4eee85343dcdce7e575e95b8e3c481e
+# git+https://github.com/enowars/enochecker@37981175f3125bd552c3c351494186fe9ce35e0b
+git+https://github.com/Sinitax/enochecker@3bd2e698e9421f4a67e60a2377ac6f40e65b18a7
enochecker-cli==0.7.0
enochecker-core==0.10.0
eventlet==0.30.2
Flask==1.1.2
greenlet==1.0.0
-gunicorn[gevent]
+gunicorn==20.1.0
idna==2.10
itsdangerous==1.1.0
Jinja2==2.11.3
diff --git a/checker/test.sh b/checker/test.sh
@@ -26,14 +26,15 @@ except:
try() {
cmd="$1"
- tmpfile="/tmp/checker-log-$BASHPID"
+ pid=$BASHPID
+ tmpfile="/tmp/checker-log-$pid"
[ -e "$tmpfile" ] && rm "$tmpfile"
if [ $# -lt 2 ]; then
variant=0
else
variant=$2
fi
- taskid=$$
+ taskid=$pid
if [ ! -z "$REMOTE" ]; then
python3 enoreq.py -j True -A http://localhost:9091 -a $REMOTE \
--flag ENOTESTFLAG123= --flag_regex 'ENO.*=' -i $taskid \
@@ -46,18 +47,18 @@ try() {
res="$(cat $tmpfile | grep -a Result: | tail -n1 | grep -a -o OK)"
fi
if [ "$res" != "OK" ]; then
- newfile="fails/err-$(ls fails | wc -l)"
+ newfile="fails/err-$pid"
(
echo "METHOD $@"
+ echo "RESULT $res"
+ echo "TASK $taskid"
cat "$tmpfile"
if [ ! -z "$REMOTE" -a -e "$ENOLOGMESSAGE_PARSER" ]; then
- docker-compose logs --tail=400 | grep '"taskId": '$taskid | $ENOLOGMESSAGE_PARSER
+ docker-compose logs --tail=2000 | grep '"taskId": '$taskid | $ENOLOGMESSAGE_PARSER
fi
) > "$newfile"
- echo -ne "Executing $cmd with variant $variant.. $res ($newfile)\n"
- else
- echo -ne "Executing $cmd with variant $variant.. $res\n"
fi
+ echo -ne "Executing $cmd with variant $variant.. $res (TASK: $taskid)\n"
}
try-all() {
@@ -82,16 +83,23 @@ try-all() {
try exploit 1
}
-if [ $# -ge 2 ]; then
+one-of() {
+ for arg in ${@:2}; do
+ [ "$1" == "$arg" ] && return 0
+ done
+ return 1
+}
+
+if one-of "$1" putflag getflag putnoise getnoise havoc exploit; then
try $@
elif [ "$1" == "test-exploits" ]; then
try exploit 0
try exploit 1
elif [ "$1" == "stress-test" ]; then
mkdir -p fails
- while [ 1 ]; do
- try-all &
- sleep 2
+ count=${2:-100}
+ for i in $(seq $count); do
+ try ${3:-exploit} ${4:-0} &
done
else
try-all
diff --git a/do.sh b/do.sh
@@ -35,7 +35,7 @@ elif [ "$1" == "cleansrc" ]; then
dst="$3"
[ -e "$dst" ] && rm -rf "$dst"
mkdir -p "$dst"
- cp -r "$src"/{*.c,*.h,Makefile,msgs} "$dst"
+ cp -r "$src"/{*.c,*.h,Makefile,msgs,.gitignore} "$dst"
# strip comments
find "$dst" | while read path; do
diff --git a/service/entrypoint.sh b/service/entrypoint.sh
@@ -5,7 +5,7 @@ chown -R service:service "$RESULTDIR"
while [ 1 ]; do
/cleaner.sh
- sleep 200
+ sleep 400
done &
CMD="socat -T180 -s TCP-LISTEN:9000,nodelay,reuseaddr,fork EXEC:/service/build/stldoctor,raw,pty,echo=0,stderr"
diff --git a/service/src/.gitignore b/service/src/.gitignore
@@ -0,0 +1,2 @@
+build
+vgcore.*
diff --git a/service/src/main.c b/service/src/main.c
@@ -92,6 +92,13 @@ fail:
return FAIL;
}
+int
+access_authorized(const char *file)
+{
+ return (loggedin && file[0] == '.' && file[1] != '.')
+ || (!loggedin && file[0] != '.');
+}
+
void
cat_cmd(const char *arg)
{
@@ -106,12 +113,10 @@ help_cmd(const char *arg)
{
int i;
- if (arg) {
- for (i = 0; i < ARRSIZE(commands); i++) {
- if (!strcmp(commands[i].name, arg)) {
- printf("%s\n", commands[i].desc);
- return;
- }
+ for (i = 0; arg && i < ARRSIZE(commands); i++) {
+ if (!strcmp(commands[i].name, arg)) {
+ printf("%s\n", commands[i].desc);
+ return;
}
}
@@ -124,6 +129,7 @@ help_cmd(const char *arg)
void
exit_cmd(const char *arg)
{
+ printf("bye!\n");
exit(0);
}
@@ -170,8 +176,9 @@ cleanup:
void
search_cmd(const char *arg)
{
- char *end, *scandir = NULL, *infopath = NULL, *modelpath = NULL;
- int i, which, dirstart, ishidden;
+ char *end, *scandir = NULL, *infopath = NULL,
+ *modelpath = NULL, **paths = NULL;
+ int i, which, dirstart, ishidden, pathc, pathcap = 100;
const char *hash, *name;
struct dirent *de;
DIR *d = NULL;
@@ -188,51 +195,49 @@ search_cmd(const char *arg)
hash = mhash(arg ? arg : ask("Model name: "), -1);
}
- if (!(d = opendir(resultdir))) return;
+ if (!(d = opendir(resultdir))) {
+ printf("Unable to access upload directory!\n");
+ return;
+ }
+ paths = checkp(malloc(pathcap * sizeof(char*)));
dirstart = telldir(d);
- for (i = 0; (de = readdir(d));) {
- name = de->d_name;
- if (loggedin && *name == '.' && !strpfcmp(hash, name + 1)
- || !loggedin && *name != '.' && !strpfcmp(hash, name)) {
- printf("%i : %s\n", i, de->d_name);
- i++;
+ for (pathc = 0; (de = readdir(d));) {
+ if (access_authorized(de->d_name)
+ && !strpfcmp(hash, de->d_name + loggedin)) {
+ printf("%i : %s\n", pathc, de->d_name);
+ paths[pathc++] = checkp(strdup(de->d_name));
+ if (pathc == pathcap) {
+ pathcap *= 2;
+ paths = checkp(realloc(paths, pathcap * sizeof(char*)));
+ }
}
}
+ closedir(d);
- if (i == 0) {
+ if (pathc == 0) {
printf("Sorry, couldnt find a matching scan result!\n");
goto cleanup;
- } else {
- which = strtoul(ask("Which of these results? "), &end, 10);
- if (which >= i || which < 0 || *end) {
- printf("Invalid index!\n");
- goto cleanup;
- }
- }
-
- seekdir(d, dirstart);
- for (i = 0; (de = readdir(d));) {
- name = de->d_name;
- if (loggedin && *name == '.' && !strpfcmp(hash, name + 1)
- || !loggedin && *name != '.' && !strpfcmp(hash, name)) {
- if (i == which) {
- scandir = aprintf("%s/%s", resultdir, de->d_name);
- break;
- }
- i++;
- }
}
- if (!scandir) {
- printf("Selected result spontaneously combusted!\n");
+ which = strtoul(ask("Which of these results? "), &end, 10);
+ if (which >= pathc || which < 0 || *end) {
+ printf("Invalid index!\n");
goto cleanup;
}
+ scandir = aprintf("%s/%s", resultdir, paths[which]);
+
infopath = aprintf("%s/%s", scandir, "info");
- if (!(f = fopen(infopath, "r"))) goto cleanup;
+ if (!(f = fopen(infopath, "r"))) {
+ printf("Selected result is missing!\n");
+ goto cleanup;
+ }
free_info(&cached);
- if (load_info(&cached, f) != OK) goto cleanup;
+ if (load_info(&cached, f) != OK) {
+ printf("Failed to parse info file!\n");
+ goto cleanup;
+ }
fclose(f);
f = NULL;
@@ -240,11 +245,17 @@ search_cmd(const char *arg)
if (strchr(ask("Download the model? "), 'y')) {
modelpath = aprintf("%s/%s", scandir, "model");
- if (!(f = fopen(modelpath, "r"))) goto cleanup;
+ if (!(f = fopen(modelpath, "r"))) {
+ printf("Failed to access file!\n");
+ goto cleanup;
+ }
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
- if (size > MAXFILESIZE) goto cleanup;
+ if (size > MAXFILESIZE) {
+ printf("File is too large to send!\n");
+ goto cleanup;
+ }
printf("Here you go.. (%liB)\n", size);
while ((i = getc(f)) != EOF)
putc(i, stdout);
@@ -254,10 +265,13 @@ search_cmd(const char *arg)
cleanup:
if (f) fclose(f);
- closedir(d);
+
free(scandir);
free(infopath);
free(modelpath);
+
+ for (i = 0; i < pathc; i++) free(paths[i]);
+ free(paths);
}
void
diff --git a/src/.gitignore b/src/.gitignore
@@ -1,4 +1,2 @@
-stldoctor
-*.o
+build
vgcore.*
-safe_*
diff --git a/src/main.c b/src/main.c
@@ -92,6 +92,13 @@ fail:
return FAIL;
}
+int
+access_authorized(const char *file)
+{
+ return (loggedin && file[0] == '.' && file[1] != '.')
+ || (!loggedin && file[0] != '.');
+}
+
void
cat_cmd(const char *arg)
{
@@ -122,6 +129,7 @@ help_cmd(const char *arg)
void
exit_cmd(const char *arg)
{
+ printf("bye!\n");
exit(0);
}
@@ -168,8 +176,9 @@ cleanup:
void
search_cmd(const char *arg)
{
- char *end, *scandir = NULL, *infopath = NULL, *modelpath = NULL;
- int i, which, dirstart, ishidden;
+ char *end, *scandir = NULL, *infopath = NULL,
+ *modelpath = NULL, **paths = NULL;
+ int i, which, dirstart, ishidden, pathc, pathcap = 100;
const char *hash, *name;
struct dirent *de;
DIR *d = NULL;
@@ -186,52 +195,49 @@ search_cmd(const char *arg)
hash = mhash(arg ? arg : ask("Model name: "), -1);
}
- if (!(d = opendir(resultdir))) return;
+ if (!(d = opendir(resultdir))) {
+ fprintf(stderr, "Unable to access upload directory!\n");
+ return;
+ }
+ paths = checkp(malloc(pathcap * sizeof(char*)));
dirstart = telldir(d);
- for (i = 0; (de = readdir(d));) {
- name = de->d_name;
- if (loggedin && *name == '.' && !strpfcmp(hash, name + 1)
- || !loggedin && *name != '.' && !strpfcmp(hash, name)) {
- printf("%i : %s\n", i, de->d_name);
- i++;
+ for (pathc = 0; (de = readdir(d));) {
+ if (access_authorized(de->d_name)
+ && !strpfcmp(hash, de->d_name + loggedin)) {
+ printf("%i : %s\n", pathc, de->d_name);
+ paths[pathc++] = checkp(strdup(de->d_name));
+ if (pathc == pathcap) {
+ pathcap *= 2;
+ paths = checkp(realloc(paths, pathcap * sizeof(char*)));
+ }
}
}
+ closedir(d);
- if (i == 0) {
+ if (pathc == 0) {
fprintf(stderr, "Sorry, couldnt find a matching scan result!\n");
goto cleanup;
- } else {
- which = strtoul(ask("Which of these results? "), &end, 10);
- if (which >= i || which < 0 || *end) {
- fprintf(stderr, "Invalid index!\n");
- goto cleanup;
- }
}
- seekdir(d, dirstart);
- for (i = 0; (de = readdir(d));) {
- name = de->d_name;
- if (loggedin && *name == '.' && !strpfcmp(hash, name + 1)
- || !loggedin && *name != '.' && !strpfcmp(hash, name)) {
- if (i == which) {
- scandir = aprintf("%s/%s", resultdir, de->d_name);
- break;
- }
- i++;
- }
- }
-
- /* file got cleaned up during race condition by background task */
- if (!scandir) {
- fprintf(stderr, "Selected result spontaneously combusted!\n");
+ which = strtoul(ask("Which of these results? "), &end, 10);
+ if (which >= pathc || which < 0 || *end) {
+ fprintf(stderr, "Invalid index!\n");
goto cleanup;
}
+ scandir = aprintf("%s/%s", resultdir, paths[which]);
+
infopath = aprintf("%s/%s", scandir, "info");
- if (!(f = fopen(infopath, "r"))) goto cleanup;
+ if (!(f = fopen(infopath, "r"))) {
+ fprintf(stderr, "Selected result is missing!\n");
+ goto cleanup;
+ }
free_info(&cached);
- if (load_info(&cached, f) != OK) goto cleanup;
+ if (load_info(&cached, f) != OK) {
+ fprintf(stderr, "Failed to parse info file!\n");
+ goto cleanup;
+ }
fclose(f);
f = NULL;
@@ -239,11 +245,17 @@ search_cmd(const char *arg)
if (strchr(ask("Download the model? "), 'y')) {
modelpath = aprintf("%s/%s", scandir, "model");
- if (!(f = fopen(modelpath, "r"))) goto cleanup;
+ if (!(f = fopen(modelpath, "r"))) {
+ fprintf(stderr, "Failed to access file!\n");
+ goto cleanup;
+ }
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
- if (size > MAXFILESIZE) goto cleanup;
+ if (size > MAXFILESIZE) {
+ fprintf(stderr, "File is too large to send!\n");
+ goto cleanup;
+ }
printf("Here you go.. (%liB)\n", size);
while ((i = getc(f)) != EOF)
putc(i, stdout);
@@ -253,10 +265,13 @@ search_cmd(const char *arg)
cleanup:
if (f) fclose(f);
- closedir(d);
+
free(scandir);
free(infopath);
free(modelpath);
+
+ for (i = 0; i < pathc; i++) free(paths[i]);
+ free(paths);
}
void