aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2021-07-21 19:37:15 +0200
committerLouis Burda <quent.burda@gmail.com>2021-07-21 19:37:15 +0200
commit6a321759f6f75e7e14a29fde7cd0fa359d14215e (patch)
treed3d4e8d1a8a93892ff8dcb9b83d1b0faedfa9bdf
parent6a5e16ed307a1159d836aa2085f92ecb7532b0a4 (diff)
downloadenowars5-service-stldoctor-6a321759f6f75e7e14a29fde7cd0fa359d14215e.tar.gz
enowars5-service-stldoctor-6a321759f6f75e7e14a29fde7cd0fa359d14215e.zip
final tweaks to documentations, added intro and final presentation slidesHEADmaster
-rw-r--r--documentation/README.md44
-rw-r--r--documentation/slides-final/.gitignore (renamed from documentation/slides/.gitignore)0
-rw-r--r--documentation/slides-final/index.html768
-rw-r--r--documentation/slides-final/media/dirlist.pngbin0 -> 2322 bytes
-rw-r--r--documentation/slides-final/media/enowars5-timeout.pngbin0 -> 202709 bytes
-rw-r--r--documentation/slides-final/media/enowars5.pngbin0 -> 22214 bytes
-rw-r--r--documentation/slides-final/media/exploit-1-1.png (renamed from documentation/slides/media/exploit-1-1.png)bin16715 -> 16715 bytes
-rw-r--r--documentation/slides-final/media/exploit-1-2.png (renamed from documentation/slides/media/exploit-1-2.png)bin26940 -> 26940 bytes
-rw-r--r--documentation/slides-final/media/exploit-1-3.png (renamed from documentation/slides/media/exploit-1-3.png)bin52090 -> 52090 bytes
-rw-r--r--documentation/slides-final/media/exploit-1-4.png (renamed from documentation/slides/media/exploit-1-4.png)bin70074 -> 70074 bytes
-rw-r--r--documentation/slides-final/media/exploit-1-5.png (renamed from documentation/slides/media/exploit-1-5.png)bin71647 -> 71647 bytes
-rw-r--r--documentation/slides-final/media/exploit-2-1.png (renamed from documentation/slides/media/exploit-2-1.png)bin46589 -> 46589 bytes
-rw-r--r--documentation/slides-final/media/getdirentries.pngbin0 -> 135007 bytes
-rw-r--r--documentation/slides-final/media/player-meme-hashfunc.pngbin0 -> 221940 bytes
-rw-r--r--documentation/slides-final/media/player-meme-struggling.pngbin0 -> 99623 bytes
-rw-r--r--documentation/slides-final/media/readdir.pngbin0 -> 119892 bytes
-rw-r--r--documentation/slides-final/media/readdir_more.pngbin0 -> 124526 bytes
-rw-r--r--documentation/slides-final/media/search.gif (renamed from documentation/slides/media/search.gif)bin60562 -> 60562 bytes
-rw-r--r--documentation/slides-final/media/socat.gif (renamed from documentation/slides/media/socat.gif)bin19413 -> 19413 bytes
-rw-r--r--documentation/slides-final/media/stl1.pngbin0 -> 17519 bytes
-rw-r--r--documentation/slides-final/media/stl2.pngbin0 -> 19783 bytes
-rw-r--r--documentation/slides-final/media/stl3.pngbin0 -> 16751 bytes
-rw-r--r--documentation/slides-final/media/stldoc.pngbin0 -> 114257 bytes
-rw-r--r--documentation/slides-final/media/stldoc_dead.pngbin0 -> 686794 bytes
-rw-r--r--documentation/slides-final/media/stldoc_dead_offline.pngbin0 -> 142293 bytes
-rw-r--r--documentation/slides-final/media/stldoc_dead_r17.pngbin0 -> 148922 bytes
-rw-r--r--documentation/slides-final/media/stldoc_dead_r432.pngbin0 -> 267521 bytes
-rw-r--r--documentation/slides-final/media/stldoc_dead_r469.pngbin0 -> 250294 bytes
-rw-r--r--documentation/slides-final/slides.md253
-rw-r--r--documentation/slides-final/stldoctor.pdfbin0 -> 2073788 bytes
-rw-r--r--documentation/slides-intro/.gitignore1
-rw-r--r--documentation/slides-intro/index.html (renamed from documentation/slides/index.html)0
-rw-r--r--documentation/slides-intro/media/exploit-1-1.pngbin0 -> 16715 bytes
-rw-r--r--documentation/slides-intro/media/exploit-1-2.pngbin0 -> 26940 bytes
-rw-r--r--documentation/slides-intro/media/exploit-1-3.pngbin0 -> 52090 bytes
-rw-r--r--documentation/slides-intro/media/exploit-1-4.pngbin0 -> 70074 bytes
-rw-r--r--documentation/slides-intro/media/exploit-1-5.pngbin0 -> 71647 bytes
-rw-r--r--documentation/slides-intro/media/exploit-2-1.pngbin0 -> 46589 bytes
-rw-r--r--documentation/slides-intro/media/search.gifbin0 -> 60562 bytes
-rw-r--r--documentation/slides-intro/media/socat.gifbin0 -> 19413 bytes
-rw-r--r--documentation/slides-intro/slides.md (renamed from documentation/slides/slides.md)0
-rw-r--r--documentation/slides-intro/stldoctor.pdf (renamed from documentation/slides/stldoctor.pdf)bin579874 -> 579874 bytes
42 files changed, 1045 insertions, 21 deletions
diff --git a/documentation/README.md b/documentation/README.md
index f507ecc..b664fc0 100644
--- a/documentation/README.md
+++ b/documentation/README.md
@@ -19,20 +19,21 @@ allows users to search for public models via model name. Registered user's
uploads are saved to a private directory. This (theoretically) prevents other
users from accessing their files.
-The service is hosted with socat, one process per client.
+The service is hosted with ncat, one process per client.
-Models are periodically cleaned up using files *last modified* date.
+Models are periodically checked for removal via their *last modified* date
+and tracked using index files.
For both flagstores the **service returns the flag in plaintext**, which is
-vulnerable to detection by network filters and can lead to easy replication
-of exploits.
+vulnerable to detection by network filters. However, multiple sessions can be
+used to somewhat obfuscate the exploit mechanism.
RCE Countermeasures
===================
It is good practice to take preventitive measures against unintentional RCE,
-which can be used to cause havoc on vulnboxes and make services go mumble.
+which can be used to wreak havoc on vulnboxes and make services go mumble.
For this reason, additional security features are enabled via compilation flags:
@@ -98,19 +99,20 @@ freadstr(FILE *f, char **dst)
To determine whether the end-of-file was reached, the return value of `int
fgetc(FILE *f)` is compared to the constant `EOF`, which has a value of `-1`.
-The problem lies in the fact, that this comparison is done following a demotion
-of the return value to `char` through the assignment and a subsequent promotion
-to `int`, which results in an arithmetic extension. As a result, reading the
-value char `0xff` would promote it to `0xffffffff` with a value of `-1`,
-preventing the function from reading the complete string.
+The problem lies in the fact that this comparison is done following a demotion
+of the return value to `char` through the assignment, and a subsequent promotion
+to `int`, which results in an arithmetic extension. As a result, a char with
+unsigned value `255` is cast to char (`0xff`) and then promoted to `-1`
+(`0xffffffff`). Since this value corresponds with `EOF`, it prevents the
+function from reading the complete string.
This allows an attacker to cleverly truncate a string before it has ended to
manipulate the content of strings which follow it. In this case, the model name
is saved before the model hash in the information file. By adding a `0xff` to
-the end of our uploaded model's name, the model hash is read as an empty string
-following a `search` of the file's contents. Since any following `search` will use
-the previously loaded models hash to find the file via prefix match, any files
-uploaded by unregistered users may be accessed by a user.
+our uploaded model's name, we can control what value is loaded from the file for
+the model's hash. Since a `search last` will use the previously loaded models hash
+to find the file via prefix match, any files uploaded by unregistered users can
+be accessed by choosing this value accordingly.
The flag is saved in the model name.
@@ -119,12 +121,12 @@ Exploiting
----------
1. Open a session
-2. Run `upload` to upload an STL file and specify a model name ending in `0xff`
+2. Run `upload` to upload an STL file and specify a model name ending in
+ `0xff<target-hash-prefix>`
3. Open a new session
-4. Run `search` with the same model name from **step 1** to load the parsed
- information from the `info` file and trigger the truncation
-5. Run `search last` to use the cached hash which should be empty,
- allowing you to accesss any files uploaded by unregistered users
+4. Run `search` with the same model name from **step 1** to load the malicious
+ model hash value
+5. Run `search last` to use the cached hash prefix to access the target file
See the `exploit` method of the checker in `checker/src/checker.py`
for an implementation in python.
@@ -208,12 +210,12 @@ previously, to log in as them and query information about their files.
To calculate the preimage we repeatedly choose a seed for srand. For
each seed, we XOR the values encoded in the hex-encoded hash with
-calls to rand(). If after generating each character the sum of the
+calls to `rand()`. If after generating each character the sum of the
generated values is less than the seed we used, restart. Otherwise,
we append some characters to make the sum of the input characters
match the seed, such that the seed for srand mhash uses matches the
one we chose. The actual value of these 'extra' chars is irrelevant,
-since mhash only processes the first 20 chars anyways.
+since mhash only processes the first 20 chars.
See `checker/src/revhash/main.c` for an example implementation in C.
diff --git a/documentation/slides/.gitignore b/documentation/slides-final/.gitignore
index e4e7469..e4e7469 100644
--- a/documentation/slides/.gitignore
+++ b/documentation/slides-final/.gitignore
diff --git a/documentation/slides-final/index.html b/documentation/slides-final/index.html
new file mode 100644
index 0000000..b7457ef
--- /dev/null
+++ b/documentation/slides-final/index.html
@@ -0,0 +1,768 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
+ <title>STLDoctor</title>
+ <style type="text/css">
+ body {
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ color: #222;
+ font-size: 100%;
+}
+
+.slide {
+ position: absolute;
+ top: 0; bottom: 0;
+ left: 0; right: 0;
+ background-color: #f7f7f7;
+}
+
+.slide-content {
+ width: 800px;
+ height: 600px;
+ overflow: hidden;
+ margin: 80px auto 0 auto;
+ padding: 30px;
+
+ font-weight: 200;
+ font-size: 200%;
+ line-height: 1.375;
+}
+
+.controls {
+ position: absolute;
+ bottom: 20px;
+ left: 20px;
+}
+
+.arrow {
+ width: 0; height: 0;
+ border: 30px solid #333;
+ float: left;
+ margin-right: 30px;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.prev {
+ border-top-color: transparent;
+ border-bottom-color: transparent;
+ border-left-color: transparent;
+
+ border-left-width: 0;
+ border-right-width: 50px;
+}
+
+.next {
+ border-top-color: transparent;
+ border-bottom-color: transparent;
+ border-right-color: transparent;
+
+ border-left-width: 50px;
+ border-right-width: 0;
+}
+
+.prev:hover {
+ border-right-color: #888;
+ cursor: pointer;
+}
+
+.next:hover {
+ border-left-color: #888;
+ cursor: pointer;
+}
+
+h1 {
+ font-size: 300%;
+ line-height: 1.2;
+ text-align: center;
+ margin: 170px 0 0;
+}
+
+h2 {
+ font-size: 100%;
+ line-height: 1.2;
+ margin: 5px 0;
+ text-align: center;
+ font-weight: 200;
+}
+
+h3 {
+ font-size: 140%;
+ line-height: 1.2;
+ border-bottom: 1px solid #aaa;
+ margin: 0;
+ padding-bottom: 15px;
+}
+
+ul {
+ padding: 20px 0 0 60px;
+ font-weight: 200;
+ line-height: 1.375;
+}
+
+.author h1 {
+ font-size: 170%;
+ font-weight: 200;
+ text-align: center;
+ margin-bottom: 30px;
+}
+
+.author h3 {
+ font-weight: 100;
+ text-align: center;
+ font-size: 95%;
+ border: none;
+}
+
+a {
+ text-decoration: none;
+ color: #44a4dd;
+}
+
+a:hover {
+ color: #66b5ff;
+}
+
+pre {
+ font-size: 60%;
+ line-height: 1.3;
+}
+
+.progress {
+ position: fixed;
+ top: 0; left: 0; right: 0;
+ height: 3px;
+ z-index: 1;
+}
+
+.progress-bar {
+ width: 0%;
+ height: 3px;
+ background-color: #b4b4b4;
+
+ -webkit-transition: width 0.05s ease-out;
+ -moz-transition: width 0.05s ease-out;
+ -o-transition: width 0.05s ease-out;
+ transition: width 0.05s ease-out;
+}
+
+.hidden {
+ display: none;
+}
+
+@media (max-width: 850px) {
+
+ body {
+ font-size: 70%;
+ }
+
+ .slide-content {
+ width: auto;
+ }
+
+ img {
+ width: 100%;
+ }
+
+ h1 {
+ margin-top: 120px;
+ }
+
+ .prev, .prev:hover {
+ border-right-color: rgba(135, 135, 135, 0.5);
+ }
+
+ .next, .next:hover {
+ border-left-color: rgba(135, 135, 135, 0.5);
+ }
+}
+
+@media (max-width: 480px) {
+ body {
+ font-size: 50%;
+ overflow: hidden;
+ }
+
+ .slide-content {
+ padding: 10px;
+ margin-top: 10px;
+ height: 340px;
+ }
+
+ h1 {
+ margin-top: 50px;
+ }
+
+ ul {
+ padding-left: 25px;
+ }
+}
+
+@media print {
+ * {
+ -webkit-print-color-adjust: exact;
+ }
+
+ @page {
+ size: letter;
+ }
+
+ .hidden {
+ display: inline;
+ }
+
+ html {
+ width: 100%;
+ height: 100%;
+ overflow: visible;
+ }
+
+ body {
+ margin: 0 auto !important;
+ border: 0;
+ padding: 0;
+ float: none !important;
+ overflow: visible;
+ background: none !important;
+ font-size: 52%;
+ }
+
+ .progress, .controls {
+ display: none;
+ }
+
+ .slide {
+ position: static;
+ }
+
+ .slide-content {
+ border: 1px solid #222;
+ margin-top: 0;
+ margin-bottom: 40px;
+ height: 3.5in;
+ overflow: visible;
+ }
+
+ .slide:nth-child(even) {
+ /* 2 slides per page */
+ page-break-before: always;
+ }
+}
+
+/*
+
+github.com style (c) Vasily Polovnyov <vast@whiteants.net>
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #333;
+ background: #f8f8f8;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #998;
+ font-style: italic;
+}
+
+.hljs-keyword,
+.hljs-selector-tag,
+.hljs-subst {
+ color: #333;
+ font-weight: bold;
+}
+
+.hljs-number,
+.hljs-literal,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-tag .hljs-attr {
+ color: #008080;
+}
+
+.hljs-string,
+.hljs-doctag {
+ color: #d14;
+}
+
+.hljs-title,
+.hljs-section,
+.hljs-selector-id {
+ color: #900;
+ font-weight: bold;
+}
+
+.hljs-subst {
+ font-weight: normal;
+}
+
+.hljs-type,
+.hljs-class .hljs-title {
+ color: #458;
+ font-weight: bold;
+}
+
+.hljs-tag,
+.hljs-name,
+.hljs-attribute {
+ color: #000080;
+ font-weight: normal;
+}
+
+.hljs-regexp,
+.hljs-link {
+ color: #009926;
+}
+
+.hljs-symbol,
+.hljs-bullet {
+ color: #990073;
+}
+
+.hljs-built_in,
+.hljs-builtin-name {
+ color: #0086b3;
+}
+
+.hljs-meta {
+ color: #999;
+ font-weight: bold;
+}
+
+.hljs-deletion {
+ background: #fdd;
+}
+
+.hljs-addition {
+ background: #dfd;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+
+ </style>
+</head>
+<body>
+ <div class="progress">
+ <div class="progress-bar"></div>
+ </div>
+
+ <div class="slide" id="slide-1">
+ <section class="slide-content"><style>
+
+.footnote {
+ font-size: 16pt;
+ position: absolute;
+ color: gray;
+ bottom: 0px;
+ right: 0px;
+}
+
+.slide-content {
+ position: relative;
+}
+
+.slide-content > ul >li {
+ padding: 7px 0px;
+}
+
+.slide-content > p > img {
+ width: 100%;
+}
+
+</style></section>
+ </div>
+ <div class="slide hidden" id="slide-2">
+ <section class="slide-content"><!-- Recap of the service and the problems I
+encountered preparing for the CTF and during the CTF -->
+<h1 id="stldoctor-">STLDoctor 💉</h1>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-3">
+ <section class="slide-content"><h3 id="index-">Index 🗄️</h3>
+<ul>
+<li>Service recap</li>
+<li>Optimization</li>
+<li>ENOWARS 5</li>
+<li>Reflection</li>
+</ul>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-4">
+ <section class="slide-content"><h3 id="refreshing-memories-">Refreshing Memories 💾</h3>
+<ul>
+<li>Plaintext service written in C</li>
+<li>Users upload STL files for parsing</li>
+<li>Private and public storage (2 flagstores)</li>
+<li><ol>
+<li>Vuln: Deserialization</li>
+</ol>
+</li>
+<li><ol start="2">
+<li>Vuln: Hash preimage</li>
+</ol>
+</li>
+</ul>
+<p><img style="width:300px !important; height:240px; position:absolute; bottom:80px; right:70px;" src="media/stldoc.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-5">
+ <section class="slide-content"><h3 id="since-last-meeting-">Since Last Meeting ⏩</h3>
+<!-- Of these three, we want to take a closer look
+at the performance improvements necessary -->
+<ul>
+<li>Performance improvements</li>
+<li>Added service fluff</li>
+</ul>
+<p><img id=img1 src="media/stl1.png">
+<img id=img2 src="media/stl2.png">
+<img id=img3 src="media/stl3.png"></p>
+<style>
+ #img1 {
+ position: absolute;
+ left: 2.5%;
+ bottom: 7%;
+ width: 30%;
+ }
+ #img2 {
+ position: absolute;
+ left: 35%;
+ bottom: 7%;
+ width: 30%;
+ }
+ #img3 {
+ position: absolute;
+ left: 67.5%;
+ bottom: 7%;
+ width: 30%;
+ }
+</style></section>
+ </div>
+ <div class="slide hidden" id="slide-6">
+ <section class="slide-content"><h3 id="issues-">Issues 😒</h3>
+<!-- since there were some slow io operations and
+either memory leak issues with pwnlib (witout patch)
+or engine request issues with the patch,
+sooo I decided to refactor to use enochecker3 for asyncio
+
+also noticed that I was checking the same thing multiple times
+in the checker, so tried to condense functionality -->
+<ul>
+<li>Slow search / list operations</li>
+<li>Enochecker memory leak without patch</li>
+<li>Engine error on worker restart with patch</li>
+<li>Logs not showing up in ELK</li>
+</ul>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-7">
+ <section class="slide-content"><h3 id="solutions-">Solutions 💡</h3>
+<ul>
+<li>Index files with locks for directory listing</li>
+<li>Refactored checker for asyncio</li>
+<li>Condensed checker functionality</li>
+<li>Increase docker-compose log size</li>
+</ul>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-8">
+ <section class="slide-content"><h1 id="enowars-5">ENOWARS 5</h1>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-9">
+ <section class="slide-content"><h3 id="oserror-">OSError 💢</h3>
+<ul>
+<li>Checker throws <code>INTERNAL_ERROR</code> on bad connection</li>
+<li>Fixed in c97789ad.. of enochecker3</li>
+</ul>
+<p><img style="" src="media/stldoc_dead_offline.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-10">
+ <section class="slide-content"><h3 id="checker-overload-">Checker Overload 💥</h3>
+<!-- all of a sudden all checker tasks are being aborted.
+Since all tasks were aborted, all workers must be affected
+and a blockage of a single worker could not have been the
+cause..
+During the ctf we found the checker at high load..
+Suspected that OFFLINE/unresponsive teams could be slowing
+down the service since then the timeouts are too large and the
+queue couldnt be emptied fast enough -->
+<ul>
+<li>Checker tasks being aborted for every team</li>
+</ul>
+<p><img style="height: 80%" src="media/stldoc_dead_r432.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-11">
+ <section class="slide-content"><h3 id="checker-overload-">Checker Overload 💥</h3>
+<!-- MEME CREDIT: Liikt -->
+<p><img style="height: 80%" src="media/stldoc_dead.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-12">
+ <section class="slide-content"><h3 id="anomaly-">Anomaly 👽</h3>
+<!-- service didnt timeout except on vulnboxes where everything
+seemed to be running weirdly, so unsure how to debug -->
+<p><img style="" src="media/enowars5-timeout.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-13">
+ <section class="slide-content"><h3 id="feedback-">Feedback 🤔</h3>
+<ul>
+<li><ol>
+<li>flagstore exploited after ~4h (R190)</li>
+</ol>
+</li>
+<li><ol start="2">
+<li>flagstore not exploited</li>
+</ol>
+</li>
+</ul>
+<!-- MEME CREDIT: [KuK] cluosh -->
+<p><img style="position:absolute; right:0px; height:300px; width:450px" src="media/player-meme-struggling.png">
+<img style="position:absolute; left:0px; height:300px; width: 400px;" src="media/player-meme-hashfunc.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-14">
+ <section class="slide-content"><h3 id="conclusion-">Conclusion 🎉</h3>
+<ul>
+<li>Relatively good uptime</li>
+<li>Not too easy / hard</li>
+<li>Users found vulns interesting</li>
+<li>No (known) unintended vuln</li>
+<li>Had a lot of fun</li>
+</ul>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-15">
+ <section class="slide-content"></section>
+ </div>
+ <div class="slide hidden" id="slide-16">
+ <section class="slide-content"><h3 id="slow-io-">Slow IO 🐌</h3>
+<!-- Noticed that running 'ls' on the service upload directory
+takes very long
+implementation in e.g. glibc actually pretty sane (see end slides)
+but bad cache performance / buffer not used / docker overlay fs -->
+<ul>
+<li>Enumerating files in a directory is expensive</li>
+<li>Index file per directory containing file names</li>
+<li>File locks to ensure exclusive writes</li>
+</ul>
+<p><img style="position:absolute; bottom: 30%; left:10%; width: 70% !important;" src="media/dirlist.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-17">
+ <section class="slide-content"><h3 id="investigating-readdir-">Investigating <code>readdir(..)</code> 🔍</h3>
+<!-- What makes readdir slow? actually looks like a sane implementation.
+We buffer an amount of entries and rebuffer when we run out.
+My guess is that we can buffer more with a regular file (also we have the choice).
+Better cache performance?
+Although the read is from one location, is probably just an abstraction
+Source: GLIBC 2.0.2-->
+<p><code>__readdir(..)</code>:</p>
+<p><img style="" src="media/readdir.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-18">
+ <section class="slide-content"><h3 id="investigating-readdir-">Investigating <code>readdir(..)</code> 🔍</h3>
+<p><code>__get_dir_entries(..)</code>:</p>
+<p><img style="" src="media/getdirentries.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-19">
+ <section class="slide-content"><h3 id="checker-overload">Checker Overload</h3>
+<p><img style="" src="media/stldoc_dead_r17.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-20">
+ <section class="slide-content"><h3 id="checker-overload">Checker Overload</h3>
+<p><img style="" src="media/stldoc_dead_r469.png"></p>
+</section>
+ </div>
+ <div class="slide hidden" id="slide-21">
+ <section class="slide-content"><script>
+ // var slide_headers = document.querySelectorAll(".slide-content > h3");
+ // for (var i = 0; i < slide_headers.length; i++) {
+ // var img = document.createElement('img')
+ // img.src = "logo.png";
+ // img.style = "height: 2.4ex; padding-right: 10px; float:right";
+ // slide_headers[i].append(img);
+ // }
+</script></section>
+ </div>
+
+
+
+ <script type="text/javascript">
+ /**
+ * Returns the current page number of the presentation.
+ */
+function currentPosition() {
+ return parseInt(document.querySelector('.slide:not(.hidden)').id.slice(6));
+}
+
+
+/**
+ * Navigates forward n pages
+ * If n is negative, we will navigate in reverse
+ */
+function navigate(n) {
+ var position = currentPosition();
+ var numSlides = document.getElementsByClassName('slide').length;
+
+ /* Positions are 1-indexed, so we need to add and subtract 1 */
+ var nextPosition = (position - 1 + n) % numSlides + 1;
+
+ /* Normalize nextPosition in-case of a negative modulo result */
+ nextPosition = (nextPosition - 1 + numSlides) % numSlides + 1;
+
+ document.getElementById('slide-' + position).classList.add('hidden');
+ document.getElementById('slide-' + nextPosition).classList.remove('hidden');
+
+ updateProgress();
+ updateURL();
+ updateTabIndex();
+}
+
+
+/**
+ * Updates the current URL to include a hashtag of the current page number.
+ */
+function updateURL() {
+ try {
+ window.history.replaceState({} , null, '#' + currentPosition());
+ } catch (e) {
+ window.location.hash = currentPosition();
+ }
+}
+
+
+/**
+ * Sets the progress indicator.
+ */
+function updateProgress() {
+ var progressBar = document.querySelector('.progress-bar');
+
+ if (progressBar !== null) {
+ var numSlides = document.getElementsByClassName('slide').length;
+ var position = currentPosition() - 1;
+ var percent = (numSlides === 1) ? 100 : 100 * position / (numSlides - 1);
+ progressBar.style.width = percent.toString() + '%';
+ }
+}
+
+
+/**
+ * Removes tabindex property from all links on the current slide, sets
+ * tabindex = -1 for all links on other slides. Prevents slides from appearing
+ * out of control.
+ */
+function updateTabIndex() {
+ var allLinks = document.querySelectorAll('.slide a');
+ var position = currentPosition();
+ var currentPageLinks = document.getElementById('slide-' + position).querySelectorAll('a');
+ var i;
+
+ for (i = 0; i < allLinks.length; i++) {
+ allLinks[i].setAttribute('tabindex', -1);
+ }
+
+ for (i = 0; i < currentPageLinks.length; i++) {
+ currentPageLinks[i].removeAttribute('tabindex');
+ }
+}
+
+/**
+ * Determines whether or not we are currently in full screen mode
+ */
+function isFullScreen() {
+ return document.fullscreenElement ||
+ document.mozFullScreenElement ||
+ document.webkitFullscreenElement ||
+ document.msFullscreenElement;
+}
+
+/**
+ * Toggle fullScreen mode on document element.
+ * Works on chrome (>= 15), firefox (>= 9), ie (>= 11), opera(>= 12.1), safari (>= 5).
+ */
+function toggleFullScreen() {
+ /* Convenient renames */
+ var docElem = document.documentElement;
+ var doc = document;
+
+ docElem.requestFullscreen =
+ docElem.requestFullscreen ||
+ docElem.msRequestFullscreen ||
+ docElem.mozRequestFullScreen ||
+ docElem.webkitRequestFullscreen.bind(docElem, Element.ALLOW_KEYBOARD_INPUT);
+
+ doc.exitFullscreen =
+ doc.exitFullscreen ||
+ doc.msExitFullscreen ||
+ doc.mozCancelFullScreen ||
+ doc.webkitExitFullscreen;
+
+ isFullScreen() ? doc.exitFullscreen() : docElem.requestFullscreen();
+}
+
+document.addEventListener('DOMContentLoaded', function () {
+ // Update the tabindex to prevent weird slide transitioning
+ updateTabIndex();
+
+ // If the location hash specifies a page number, go to it.
+ var page = window.location.hash.slice(1);
+ if (page) {
+ navigate(parseInt(page) - 1);
+ }
+
+ document.onkeydown = function (e) {
+ var kc = e.keyCode;
+
+ // left, down, H, J, backspace, PgUp - BACK
+ // up, right, K, L, space, PgDn - FORWARD
+ // enter - FULLSCREEN
+ if (kc === 37 || kc === 40 || kc === 8 || kc === 72 || kc === 74 || kc === 33) {
+ navigate(-1);
+ } else if (kc === 38 || kc === 39 || kc === 32 || kc === 75 || kc === 76 || kc === 34) {
+ navigate(1);
+ } else if (kc === 13) {
+ toggleFullScreen();
+ }
+ };
+
+ if (document.querySelector('.next') && document.querySelector('.prev')) {
+ document.querySelector('.next').onclick = function (e) {
+ e.preventDefault();
+ navigate(1);
+ };
+
+ document.querySelector('.prev').onclick = function (e) {
+ e.preventDefault();
+ navigate(-1);
+ };
+ }
+});
+
+
+ </script>
+</body>
+</html>
diff --git a/documentation/slides-final/media/dirlist.png b/documentation/slides-final/media/dirlist.png
new file mode 100644
index 0000000..68985ad
--- /dev/null
+++ b/documentation/slides-final/media/dirlist.png
Binary files differ
diff --git a/documentation/slides-final/media/enowars5-timeout.png b/documentation/slides-final/media/enowars5-timeout.png
new file mode 100644
index 0000000..2dfecb2
--- /dev/null
+++ b/documentation/slides-final/media/enowars5-timeout.png
Binary files differ
diff --git a/documentation/slides-final/media/enowars5.png b/documentation/slides-final/media/enowars5.png
new file mode 100644
index 0000000..4dbba87
--- /dev/null
+++ b/documentation/slides-final/media/enowars5.png
Binary files differ
diff --git a/documentation/slides/media/exploit-1-1.png b/documentation/slides-final/media/exploit-1-1.png
index b251075..b251075 100644
--- a/documentation/slides/media/exploit-1-1.png
+++ b/documentation/slides-final/media/exploit-1-1.png
Binary files differ
diff --git a/documentation/slides/media/exploit-1-2.png b/documentation/slides-final/media/exploit-1-2.png
index e63f7d0..e63f7d0 100644
--- a/documentation/slides/media/exploit-1-2.png
+++ b/documentation/slides-final/media/exploit-1-2.png
Binary files differ
diff --git a/documentation/slides/media/exploit-1-3.png b/documentation/slides-final/media/exploit-1-3.png
index 4dc961d..4dc961d 100644
--- a/documentation/slides/media/exploit-1-3.png
+++ b/documentation/slides-final/media/exploit-1-3.png
Binary files differ
diff --git a/documentation/slides/media/exploit-1-4.png b/documentation/slides-final/media/exploit-1-4.png
index 2d75f2f..2d75f2f 100644
--- a/documentation/slides/media/exploit-1-4.png
+++ b/documentation/slides-final/media/exploit-1-4.png
Binary files differ
diff --git a/documentation/slides/media/exploit-1-5.png b/documentation/slides-final/media/exploit-1-5.png
index 874529b..874529b 100644
--- a/documentation/slides/media/exploit-1-5.png
+++ b/documentation/slides-final/media/exploit-1-5.png
Binary files differ
diff --git a/documentation/slides/media/exploit-2-1.png b/documentation/slides-final/media/exploit-2-1.png
index 91b0df7..91b0df7 100644
--- a/documentation/slides/media/exploit-2-1.png
+++ b/documentation/slides-final/media/exploit-2-1.png
Binary files differ
diff --git a/documentation/slides-final/media/getdirentries.png b/documentation/slides-final/media/getdirentries.png
new file mode 100644
index 0000000..e19c3e7
--- /dev/null
+++ b/documentation/slides-final/media/getdirentries.png
Binary files differ
diff --git a/documentation/slides-final/media/player-meme-hashfunc.png b/documentation/slides-final/media/player-meme-hashfunc.png
new file mode 100644
index 0000000..04077ca
--- /dev/null
+++ b/documentation/slides-final/media/player-meme-hashfunc.png
Binary files differ
diff --git a/documentation/slides-final/media/player-meme-struggling.png b/documentation/slides-final/media/player-meme-struggling.png
new file mode 100644
index 0000000..9863892
--- /dev/null
+++ b/documentation/slides-final/media/player-meme-struggling.png
Binary files differ
diff --git a/documentation/slides-final/media/readdir.png b/documentation/slides-final/media/readdir.png
new file mode 100644
index 0000000..a211c1f
--- /dev/null
+++ b/documentation/slides-final/media/readdir.png
Binary files differ
diff --git a/documentation/slides-final/media/readdir_more.png b/documentation/slides-final/media/readdir_more.png
new file mode 100644
index 0000000..c24c582
--- /dev/null
+++ b/documentation/slides-final/media/readdir_more.png
Binary files differ
diff --git a/documentation/slides/media/search.gif b/documentation/slides-final/media/search.gif
index de4ed18..de4ed18 100644
--- a/documentation/slides/media/search.gif
+++ b/documentation/slides-final/media/search.gif
Binary files differ
diff --git a/documentation/slides/media/socat.gif b/documentation/slides-final/media/socat.gif
index 38f1e93..38f1e93 100644
--- a/documentation/slides/media/socat.gif
+++ b/documentation/slides-final/media/socat.gif
Binary files differ
diff --git a/documentation/slides-final/media/stl1.png b/documentation/slides-final/media/stl1.png
new file mode 100644
index 0000000..cef284a
--- /dev/null
+++ b/documentation/slides-final/media/stl1.png
Binary files differ
diff --git a/documentation/slides-final/media/stl2.png b/documentation/slides-final/media/stl2.png
new file mode 100644
index 0000000..1201981
--- /dev/null
+++ b/documentation/slides-final/media/stl2.png
Binary files differ
diff --git a/documentation/slides-final/media/stl3.png b/documentation/slides-final/media/stl3.png
new file mode 100644
index 0000000..49045cc
--- /dev/null
+++ b/documentation/slides-final/media/stl3.png
Binary files differ
diff --git a/documentation/slides-final/media/stldoc.png b/documentation/slides-final/media/stldoc.png
new file mode 100644
index 0000000..f276ef7
--- /dev/null
+++ b/documentation/slides-final/media/stldoc.png
Binary files differ
diff --git a/documentation/slides-final/media/stldoc_dead.png b/documentation/slides-final/media/stldoc_dead.png
new file mode 100644
index 0000000..6838fbf
--- /dev/null
+++ b/documentation/slides-final/media/stldoc_dead.png
Binary files differ
diff --git a/documentation/slides-final/media/stldoc_dead_offline.png b/documentation/slides-final/media/stldoc_dead_offline.png
new file mode 100644
index 0000000..8cc3faa
--- /dev/null
+++ b/documentation/slides-final/media/stldoc_dead_offline.png
Binary files differ
diff --git a/documentation/slides-final/media/stldoc_dead_r17.png b/documentation/slides-final/media/stldoc_dead_r17.png
new file mode 100644
index 0000000..0fef751
--- /dev/null
+++ b/documentation/slides-final/media/stldoc_dead_r17.png
Binary files differ
diff --git a/documentation/slides-final/media/stldoc_dead_r432.png b/documentation/slides-final/media/stldoc_dead_r432.png
new file mode 100644
index 0000000..5985a1a
--- /dev/null
+++ b/documentation/slides-final/media/stldoc_dead_r432.png
Binary files differ
diff --git a/documentation/slides-final/media/stldoc_dead_r469.png b/documentation/slides-final/media/stldoc_dead_r469.png
new file mode 100644
index 0000000..d202b69
--- /dev/null
+++ b/documentation/slides-final/media/stldoc_dead_r469.png
Binary files differ
diff --git a/documentation/slides-final/slides.md b/documentation/slides-final/slides.md
new file mode 100644
index 0000000..54b1fa8
--- /dev/null
+++ b/documentation/slides-final/slides.md
@@ -0,0 +1,253 @@
+title: STLDoctor
+output: index.html
+controls: false
+
+--
+
+<style>
+
+.footnote {
+ font-size: 16pt;
+ position: absolute;
+ color: gray;
+ bottom: 0px;
+ right: 0px;
+}
+
+.slide-content {
+ position: relative;
+}
+
+.slide-content > ul >li {
+ padding: 7px 0px;
+}
+
+.slide-content > p > img {
+ width: 100%;
+}
+
+</style>
+
+--
+
+<!-- Recap of the service and the problems I
+encountered preparing for the CTF and during the CTF -->
+
+# STLDoctor 💉
+
+--
+
+### Index 🗄️
+
+- Service recap
+- Optimization
+- ENOWARS 5
+- Reflection
+
+--
+
+### Refreshing Memories 💾
+
+- Plaintext service written in C
+- Users upload STL files for parsing
+- Private and public storage (2 flagstores)
+- 1. Vuln: Deserialization
+- 2. Vuln: Hash preimage
+
+<img style="width:300px !important; height:240px; position:absolute; bottom:80px; right:70px;" src="media/stldoc.png">
+
+--
+
+### Since Last Meeting ⏩
+
+<!-- Of these three, we want to take a closer look
+at the performance improvements necessary -->
+
+- Performance improvements
+- Added service fluff
+
+<img id=img1 src="media/stl1.png">
+<img id=img2 src="media/stl2.png">
+<img id=img3 src="media/stl3.png">
+
+<style>
+ #img1 {
+ position: absolute;
+ left: 2.5%;
+ bottom: 7%;
+ width: 30%;
+ }
+ #img2 {
+ position: absolute;
+ left: 35%;
+ bottom: 7%;
+ width: 30%;
+ }
+ #img3 {
+ position: absolute;
+ left: 67.5%;
+ bottom: 7%;
+ width: 30%;
+ }
+</style>
+
+--
+
+### Issues 😒
+
+<!-- since there were some slow io operations and
+either memory leak issues with pwnlib (witout patch)
+or engine request issues with the patch,
+sooo I decided to refactor to use enochecker3 for asyncio
+
+also noticed that I was checking the same thing multiple times
+in the checker, so tried to condense functionality -->
+
+- Slow search / list operations
+- Enochecker memory leak without patch
+- Engine error on worker restart with patch
+- Logs not showing up in ELK
+
+--
+
+### Solutions 💡
+
+- Index files with locks for directory listing
+- Refactored checker for asyncio
+- Condensed checker functionality
+- Increase docker-compose log size
+
+--
+
+# ENOWARS 5
+
+--
+
+### OSError 💢
+
+- Checker throws `INTERNAL_ERROR` on bad connection
+- Fixed in c97789ad.. of enochecker3
+
+<img style="" src="media/stldoc_dead_offline.png">
+
+--
+
+### Checker Overload 💥
+
+<!-- all of a sudden all checker tasks are being aborted.
+Since all tasks were aborted, all workers must be affected
+and a blockage of a single worker could not have been the
+cause..
+During the ctf we found the checker at high load..
+Suspected that OFFLINE/unresponsive teams could be slowing
+down the service since then the timeouts are too large and the
+queue couldnt be emptied fast enough -->
+
+- Checker tasks being aborted for every team
+
+<img style="height: 80%" src="media/stldoc_dead_r432.png">
+
+--
+
+### Checker Overload 💥
+
+<!-- MEME CREDIT: Liikt -->
+<img style="height: 80%" src="media/stldoc_dead.png">
+
+--
+
+### Anomaly 👽
+
+<!-- service didnt timeout except on vulnboxes where everything
+seemed to be running weirdly, so unsure how to debug -->
+
+<img style="" src="media/enowars5-timeout.png">
+
+--
+
+### Feedback 🤔
+
+- 1. flagstore exploited after ~4h (R190)
+- 2. flagstore not exploited
+
+<!-- MEME CREDIT: [KuK] cluosh -->
+<img style="position:absolute; right:0px; height:300px; width:450px" src="media/player-meme-struggling.png">
+<img style="position:absolute; left:0px; height:300px; width: 400px;" src="media/player-meme-hashfunc.png">
+
+--
+
+### Conclusion 🎉
+
+- Relatively good uptime
+- Not too easy / hard
+- Users found vulns interesting
+- No (known) unintended vuln
+- Had a lot of fun
+
+--
+
+--
+
+### Slow IO 🐌
+
+<!-- Noticed that running 'ls' on the service upload directory
+takes very long
+implementation in e.g. glibc actually pretty sane (see end slides)
+but bad cache performance / buffer not used / docker overlay fs -->
+
+- Enumerating files in a directory is expensive
+- Index file per directory containing file names
+- File locks to ensure exclusive writes
+
+<img style="position:absolute; bottom: 30%; left:10%; width: 70% !important;" src="media/dirlist.png">
+
+--
+
+### Investigating `readdir(..)` 🔍
+
+<!-- What makes readdir slow? actually looks like a sane implementation.
+We buffer an amount of entries and rebuffer when we run out.
+My guess is that we can buffer more with a regular file (also we have the choice).
+Better cache performance?
+Although the read is from one location, is probably just an abstraction
+Source: GLIBC 2.0.2-->
+
+`__readdir(..)`:
+
+<img style="" src="media/readdir.png">
+
+--
+
+### Investigating `readdir(..)` 🔍
+
+`__get_dir_entries(..)`:
+
+<img style="" src="media/getdirentries.png">
+
+--
+
+### Checker Overload
+
+<img style="" src="media/stldoc_dead_r17.png">
+
+--
+
+### Checker Overload
+
+<img style="" src="media/stldoc_dead_r469.png">
+
+--
+
+
+
+
+
+<script>
+ // var slide_headers = document.querySelectorAll(".slide-content > h3");
+ // for (var i = 0; i < slide_headers.length; i++) {
+ // var img = document.createElement('img')
+ // img.src = "logo.png";
+ // img.style = "height: 2.4ex; padding-right: 10px; float:right";
+ // slide_headers[i].append(img);
+ // }
+</script>
diff --git a/documentation/slides-final/stldoctor.pdf b/documentation/slides-final/stldoctor.pdf
new file mode 100644
index 0000000..6667621
--- /dev/null
+++ b/documentation/slides-final/stldoctor.pdf
Binary files differ
diff --git a/documentation/slides-intro/.gitignore b/documentation/slides-intro/.gitignore
new file mode 100644
index 0000000..e4e7469
--- /dev/null
+++ b/documentation/slides-intro/.gitignore
@@ -0,0 +1 @@
+slides
diff --git a/documentation/slides/index.html b/documentation/slides-intro/index.html
index cc0aa6a..cc0aa6a 100644
--- a/documentation/slides/index.html
+++ b/documentation/slides-intro/index.html
diff --git a/documentation/slides-intro/media/exploit-1-1.png b/documentation/slides-intro/media/exploit-1-1.png
new file mode 100644
index 0000000..b251075
--- /dev/null
+++ b/documentation/slides-intro/media/exploit-1-1.png
Binary files differ
diff --git a/documentation/slides-intro/media/exploit-1-2.png b/documentation/slides-intro/media/exploit-1-2.png
new file mode 100644
index 0000000..e63f7d0
--- /dev/null
+++ b/documentation/slides-intro/media/exploit-1-2.png
Binary files differ
diff --git a/documentation/slides-intro/media/exploit-1-3.png b/documentation/slides-intro/media/exploit-1-3.png
new file mode 100644
index 0000000..4dc961d
--- /dev/null
+++ b/documentation/slides-intro/media/exploit-1-3.png
Binary files differ
diff --git a/documentation/slides-intro/media/exploit-1-4.png b/documentation/slides-intro/media/exploit-1-4.png
new file mode 100644
index 0000000..2d75f2f
--- /dev/null
+++ b/documentation/slides-intro/media/exploit-1-4.png
Binary files differ
diff --git a/documentation/slides-intro/media/exploit-1-5.png b/documentation/slides-intro/media/exploit-1-5.png
new file mode 100644
index 0000000..874529b
--- /dev/null
+++ b/documentation/slides-intro/media/exploit-1-5.png
Binary files differ
diff --git a/documentation/slides-intro/media/exploit-2-1.png b/documentation/slides-intro/media/exploit-2-1.png
new file mode 100644
index 0000000..91b0df7
--- /dev/null
+++ b/documentation/slides-intro/media/exploit-2-1.png
Binary files differ
diff --git a/documentation/slides-intro/media/search.gif b/documentation/slides-intro/media/search.gif
new file mode 100644
index 0000000..de4ed18
--- /dev/null
+++ b/documentation/slides-intro/media/search.gif
Binary files differ
diff --git a/documentation/slides-intro/media/socat.gif b/documentation/slides-intro/media/socat.gif
new file mode 100644
index 0000000..38f1e93
--- /dev/null
+++ b/documentation/slides-intro/media/socat.gif
Binary files differ
diff --git a/documentation/slides/slides.md b/documentation/slides-intro/slides.md
index 48e3447..48e3447 100644
--- a/documentation/slides/slides.md
+++ b/documentation/slides-intro/slides.md
diff --git a/documentation/slides/stldoctor.pdf b/documentation/slides-intro/stldoctor.pdf
index ddfe89b..ddfe89b 100644
--- a/documentation/slides/stldoctor.pdf
+++ b/documentation/slides-intro/stldoctor.pdf
Binary files differ