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

index.html (17324B)


      1<!doctype html>
      2<html>
      3<head>
      4  <meta charset="utf-8">
      5  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
      6  <title>STLDoctor</title>
      7  <style type="text/css">
      8    body {
      9  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
     10  color: #222;
     11  font-size: 100%;
     12}
     13
     14.slide {
     15  position: absolute;
     16  top: 0; bottom: 0;
     17  left: 0; right: 0;
     18  background-color: #f7f7f7;
     19}
     20
     21.slide-content {
     22  width: 800px;
     23  height: 600px;
     24  overflow: hidden;
     25  margin: 80px auto 0 auto;
     26  padding: 30px;
     27
     28  font-weight: 200;
     29  font-size: 200%;
     30  line-height: 1.375;
     31}
     32
     33.controls {
     34  position: absolute;
     35  bottom: 20px;
     36  left: 20px;
     37}
     38
     39.arrow {
     40  width: 0; height: 0;
     41  border: 30px solid #333;
     42  float: left;
     43  margin-right: 30px;
     44
     45  -webkit-touch-callout: none;
     46  -webkit-user-select: none;
     47  -khtml-user-select: none;
     48  -moz-user-select: none;
     49  -ms-user-select: none;
     50  user-select: none;
     51}
     52
     53.prev {
     54  border-top-color: transparent;
     55  border-bottom-color: transparent;
     56  border-left-color: transparent;
     57
     58  border-left-width: 0;
     59  border-right-width: 50px;
     60}
     61
     62.next {
     63  border-top-color: transparent;
     64  border-bottom-color: transparent;
     65  border-right-color: transparent;
     66
     67  border-left-width: 50px;
     68  border-right-width: 0;
     69}
     70
     71.prev:hover {
     72  border-right-color: #888;
     73  cursor: pointer;
     74}
     75
     76.next:hover {
     77  border-left-color: #888;
     78  cursor: pointer;
     79}
     80
     81h1 {
     82  font-size: 300%;
     83  line-height: 1.2;
     84  text-align: center;
     85  margin: 170px 0 0;
     86}
     87
     88h2 {
     89  font-size: 100%;
     90  line-height: 1.2;
     91  margin: 5px 0;
     92  text-align: center;
     93  font-weight: 200;
     94}
     95
     96h3 {
     97  font-size: 140%;
     98  line-height: 1.2;
     99  border-bottom: 1px solid #aaa;
    100  margin: 0;
    101  padding-bottom: 15px;
    102}
    103
    104ul {
    105  padding: 20px 0 0 60px;
    106  font-weight: 200;
    107  line-height: 1.375;
    108}
    109
    110.author h1 {
    111  font-size: 170%;
    112  font-weight: 200;
    113  text-align: center;
    114  margin-bottom: 30px;
    115}
    116
    117.author h3 {
    118  font-weight: 100;
    119  text-align: center;
    120  font-size: 95%;
    121  border: none;
    122}
    123
    124a {
    125  text-decoration: none;
    126  color: #44a4dd;
    127}
    128
    129a:hover {
    130  color: #66b5ff;
    131}
    132
    133pre {
    134  font-size: 60%;
    135  line-height: 1.3;
    136}
    137
    138.progress {
    139  position: fixed;
    140  top: 0; left: 0; right: 0;
    141  height: 3px;
    142  z-index: 1;
    143}
    144
    145.progress-bar {
    146  width: 0%;
    147  height: 3px;
    148  background-color: #b4b4b4;
    149
    150  -webkit-transition: width 0.05s ease-out;
    151  -moz-transition: width 0.05s ease-out;
    152  -o-transition: width 0.05s ease-out;
    153  transition: width 0.05s ease-out;
    154}
    155
    156.hidden {
    157  display: none;
    158}
    159
    160@media (max-width: 850px) {
    161
    162  body {
    163    font-size: 70%;
    164  }
    165
    166  .slide-content {
    167    width: auto;
    168  }
    169
    170  img {
    171    width: 100%;
    172  }
    173
    174  h1 {
    175    margin-top: 120px;
    176  }
    177
    178  .prev, .prev:hover {
    179    border-right-color: rgba(135, 135, 135, 0.5);
    180  }
    181
    182  .next, .next:hover {
    183    border-left-color: rgba(135, 135, 135, 0.5);
    184  }
    185}
    186
    187@media (max-width: 480px) {
    188  body {
    189    font-size: 50%;
    190    overflow: hidden;
    191  }
    192
    193  .slide-content {
    194    padding: 10px;
    195    margin-top: 10px;
    196    height: 340px;
    197  }
    198
    199  h1 {
    200    margin-top: 50px;
    201  }
    202
    203  ul {
    204    padding-left: 25px;
    205  }
    206}
    207
    208@media print {
    209  * {
    210    -webkit-print-color-adjust: exact;
    211  }
    212
    213  @page {
    214    size: letter;
    215  }
    216
    217  .hidden {
    218    display: inline;
    219  }
    220
    221  html {
    222    width: 100%;
    223    height: 100%;
    224    overflow: visible;
    225  }
    226
    227  body {
    228    margin: 0 auto !important;
    229    border: 0;
    230    padding: 0;
    231    float: none !important;
    232    overflow: visible;
    233    background: none !important;
    234    font-size: 52%;
    235  }
    236
    237  .progress, .controls {
    238    display: none;
    239  }
    240
    241  .slide {
    242    position: static;
    243  }
    244
    245  .slide-content {
    246    border: 1px solid #222;
    247    margin-top: 0;
    248    margin-bottom: 40px;
    249    height: 3.5in;
    250    overflow: visible;
    251  }
    252
    253  .slide:nth-child(even) {
    254    /* 2 slides per page */
    255    page-break-before: always;
    256  }
    257}
    258
    259/*
    260
    261github.com style (c) Vasily Polovnyov <vast@whiteants.net>
    262
    263*/
    264
    265.hljs {
    266  display: block;
    267  overflow-x: auto;
    268  padding: 0.5em;
    269  color: #333;
    270  background: #f8f8f8;
    271}
    272
    273.hljs-comment,
    274.hljs-quote {
    275  color: #998;
    276  font-style: italic;
    277}
    278
    279.hljs-keyword,
    280.hljs-selector-tag,
    281.hljs-subst {
    282  color: #333;
    283  font-weight: bold;
    284}
    285
    286.hljs-number,
    287.hljs-literal,
    288.hljs-variable,
    289.hljs-template-variable,
    290.hljs-tag .hljs-attr {
    291  color: #008080;
    292}
    293
    294.hljs-string,
    295.hljs-doctag {
    296  color: #d14;
    297}
    298
    299.hljs-title,
    300.hljs-section,
    301.hljs-selector-id {
    302  color: #900;
    303  font-weight: bold;
    304}
    305
    306.hljs-subst {
    307  font-weight: normal;
    308}
    309
    310.hljs-type,
    311.hljs-class .hljs-title {
    312  color: #458;
    313  font-weight: bold;
    314}
    315
    316.hljs-tag,
    317.hljs-name,
    318.hljs-attribute {
    319  color: #000080;
    320  font-weight: normal;
    321}
    322
    323.hljs-regexp,
    324.hljs-link {
    325  color: #009926;
    326}
    327
    328.hljs-symbol,
    329.hljs-bullet {
    330  color: #990073;
    331}
    332
    333.hljs-built_in,
    334.hljs-builtin-name {
    335  color: #0086b3;
    336}
    337
    338.hljs-meta {
    339  color: #999;
    340  font-weight: bold;
    341}
    342
    343.hljs-deletion {
    344  background: #fdd;
    345}
    346
    347.hljs-addition {
    348  background: #dfd;
    349}
    350
    351.hljs-emphasis {
    352  font-style: italic;
    353}
    354
    355.hljs-strong {
    356  font-weight: bold;
    357}
    358
    359
    360  </style>
    361</head>
    362<body>
    363    <div class="progress">
    364    <div class="progress-bar"></div>
    365  </div>
    366
    367  <div class="slide" id="slide-1">
    368    <section class="slide-content"><style>
    369
    370.footnote {
    371    font-size: 16pt;
    372    position: absolute;
    373    color: gray;
    374    bottom: 0px;
    375    right: 0px;
    376}
    377
    378.slide-content {
    379    position: relative;
    380}
    381
    382.slide-content > ul >li {
    383    padding: 7px 0px;
    384}
    385
    386.slide-content > p > img {
    387    width: 100%;
    388}
    389
    390</style></section>
    391  </div>
    392  <div class="slide hidden" id="slide-2">
    393    <section class="slide-content"><!-- Recap of the service and the problems I
    394encountered preparing for the CTF and during the CTF -->
    395<h1 id="stldoctor-">STLDoctor 💉</h1>
    396</section>
    397  </div>
    398  <div class="slide hidden" id="slide-3">
    399    <section class="slide-content"><h3 id="index-">Index 🗄️</h3>
    400<ul>
    401<li>Service recap</li>
    402<li>Optimization</li>
    403<li>ENOWARS 5</li>
    404<li>Reflection</li>
    405</ul>
    406</section>
    407  </div>
    408  <div class="slide hidden" id="slide-4">
    409    <section class="slide-content"><h3 id="refreshing-memories-">Refreshing Memories 💾</h3>
    410<ul>
    411<li>Plaintext service written in C</li>
    412<li>Users upload STL files for parsing</li>
    413<li>Private and public storage (2 flagstores)</li>
    414<li><ol>
    415<li>Vuln: Deserialization</li>
    416</ol>
    417</li>
    418<li><ol start="2">
    419<li>Vuln: Hash preimage</li>
    420</ol>
    421</li>
    422</ul>
    423<p><img style="width:300px !important; height:240px; position:absolute; bottom:80px; right:70px;" src="media/stldoc.png"></p>
    424</section>
    425  </div>
    426  <div class="slide hidden" id="slide-5">
    427    <section class="slide-content"><h3 id="since-last-meeting-">Since Last Meeting ⏩</h3>
    428<!-- Of these three, we want to take a closer look
    429at the performance improvements necessary -->
    430<ul>
    431<li>Performance improvements</li>
    432<li>Added service fluff</li>
    433</ul>
    434<p><img id=img1 src="media/stl1.png">
    435<img id=img2 src="media/stl2.png">
    436<img id=img3 src="media/stl3.png"></p>
    437<style>
    438    #img1 {
    439        position: absolute;
    440        left: 2.5%;
    441        bottom: 7%;
    442        width: 30%;
    443    }
    444    #img2 {
    445        position: absolute;
    446        left: 35%;
    447        bottom: 7%;
    448        width: 30%;
    449    }
    450    #img3 {
    451        position: absolute;
    452        left: 67.5%;
    453        bottom: 7%;
    454        width: 30%;
    455    }
    456</style></section>
    457  </div>
    458  <div class="slide hidden" id="slide-6">
    459    <section class="slide-content"><h3 id="issues-">Issues 😒</h3>
    460<!-- since there were some slow io operations and
    461either memory leak issues with pwnlib (witout patch)
    462or engine request issues with the patch,
    463sooo I decided to refactor to use enochecker3 for asyncio
    464
    465also noticed that I was checking the same thing multiple times
    466in the checker, so tried to condense functionality -->
    467<ul>
    468<li>Slow search / list operations</li>
    469<li>Enochecker memory leak without patch</li>
    470<li>Engine error on worker restart with patch</li>
    471<li>Logs not showing up in ELK</li>
    472</ul>
    473</section>
    474  </div>
    475  <div class="slide hidden" id="slide-7">
    476    <section class="slide-content"><h3 id="solutions-">Solutions 💡</h3>
    477<ul>
    478<li>Index files with locks for directory listing</li>
    479<li>Refactored checker for asyncio</li>
    480<li>Condensed checker functionality</li>
    481<li>Increase docker-compose log size</li>
    482</ul>
    483</section>
    484  </div>
    485  <div class="slide hidden" id="slide-8">
    486    <section class="slide-content"><h1 id="enowars-5">ENOWARS 5</h1>
    487</section>
    488  </div>
    489  <div class="slide hidden" id="slide-9">
    490    <section class="slide-content"><h3 id="oserror-">OSError 💢</h3>
    491<ul>
    492<li>Checker throws <code>INTERNAL_ERROR</code> on bad connection</li>
    493<li>Fixed in c97789ad.. of enochecker3</li>
    494</ul>
    495<p><img style="" src="media/stldoc_dead_offline.png"></p>
    496</section>
    497  </div>
    498  <div class="slide hidden" id="slide-10">
    499    <section class="slide-content"><h3 id="checker-overload-">Checker Overload 💥</h3>
    500<!-- all of a sudden all checker tasks are being aborted.
    501Since all tasks were aborted, all workers must be affected
    502and a blockage of a single worker could not have been the
    503cause.. 
    504During the ctf we found the checker at high load..
    505Suspected that OFFLINE/unresponsive teams could be slowing
    506down the service since then the timeouts are too large and the
    507queue couldnt be emptied fast enough -->
    508<ul>
    509<li>Checker tasks being aborted for every team</li>
    510</ul>
    511<p><img style="height: 80%" src="media/stldoc_dead_r432.png"></p>
    512</section>
    513  </div>
    514  <div class="slide hidden" id="slide-11">
    515    <section class="slide-content"><h3 id="checker-overload-">Checker Overload 💥</h3>
    516<!-- MEME CREDIT: Liikt -->
    517<p><img style="height: 80%" src="media/stldoc_dead.png"></p>
    518</section>
    519  </div>
    520  <div class="slide hidden" id="slide-12">
    521    <section class="slide-content"><h3 id="anomaly-">Anomaly 👽</h3>
    522<!-- service didnt timeout except on vulnboxes where everything
    523seemed to be running weirdly, so unsure how to debug -->
    524<p><img style="" src="media/enowars5-timeout.png"></p>
    525</section>
    526  </div>
    527  <div class="slide hidden" id="slide-13">
    528    <section class="slide-content"><h3 id="feedback-">Feedback 🤔</h3>
    529<ul>
    530<li><ol>
    531<li>flagstore exploited after ~4h (R190)</li>
    532</ol>
    533</li>
    534<li><ol start="2">
    535<li>flagstore not exploited</li>
    536</ol>
    537</li>
    538</ul>
    539<!-- MEME CREDIT: [KuK] cluosh -->
    540<p><img style="position:absolute; right:0px; height:300px; width:450px" src="media/player-meme-struggling.png">
    541<img style="position:absolute; left:0px; height:300px; width: 400px;" src="media/player-meme-hashfunc.png"></p>
    542</section>
    543  </div>
    544  <div class="slide hidden" id="slide-14">
    545    <section class="slide-content"><h3 id="conclusion-">Conclusion 🎉</h3>
    546<ul>
    547<li>Relatively good uptime</li>
    548<li>Not too easy / hard</li>
    549<li>Users found vulns interesting</li>
    550<li>No (known) unintended vuln</li>
    551<li>Had a lot of fun</li>
    552</ul>
    553</section>
    554  </div>
    555  <div class="slide hidden" id="slide-15">
    556    <section class="slide-content"></section>
    557  </div>
    558  <div class="slide hidden" id="slide-16">
    559    <section class="slide-content"><h3 id="slow-io-">Slow IO 🐌</h3>
    560<!-- Noticed that running 'ls' on the service upload directory
    561takes very long
    562implementation in e.g. glibc actually pretty sane (see end slides)
    563but bad cache performance / buffer not used / docker overlay fs -->
    564<ul>
    565<li>Enumerating files in a directory is expensive</li>
    566<li>Index file per directory containing file names</li>
    567<li>File locks to ensure exclusive writes</li>
    568</ul>
    569<p><img style="position:absolute; bottom: 30%; left:10%; width: 70% !important;" src="media/dirlist.png"></p>
    570</section>
    571  </div>
    572  <div class="slide hidden" id="slide-17">
    573    <section class="slide-content"><h3 id="investigating-readdir-">Investigating <code>readdir(..)</code> 🔍</h3>
    574<!-- What makes readdir slow? actually looks like a sane implementation.
    575We buffer an amount of entries and rebuffer when we run out.
    576My guess is that we can buffer more with a regular file (also we have the choice).
    577Better cache performance?
    578Although the read is from one location, is probably just an abstraction
    579Source: GLIBC 2.0.2-->
    580<p><code>__readdir(..)</code>:</p>
    581<p><img style="" src="media/readdir.png"></p>
    582</section>
    583  </div>
    584  <div class="slide hidden" id="slide-18">
    585    <section class="slide-content"><h3 id="investigating-readdir-">Investigating <code>readdir(..)</code> 🔍</h3>
    586<p><code>__get_dir_entries(..)</code>:</p>
    587<p><img style="" src="media/getdirentries.png"></p>
    588</section>
    589  </div>
    590  <div class="slide hidden" id="slide-19">
    591    <section class="slide-content"><h3 id="checker-overload">Checker Overload</h3>
    592<p><img style="" src="media/stldoc_dead_r17.png"></p>
    593</section>
    594  </div>
    595  <div class="slide hidden" id="slide-20">
    596    <section class="slide-content"><h3 id="checker-overload">Checker Overload</h3>
    597<p><img style="" src="media/stldoc_dead_r469.png"></p>
    598</section>
    599  </div>
    600  <div class="slide hidden" id="slide-21">
    601    <section class="slide-content"><script>
    602    // var slide_headers = document.querySelectorAll(".slide-content > h3");
    603    // for (var i = 0; i < slide_headers.length; i++) {
    604    //     var img = document.createElement('img')
    605    //     img.src = "logo.png";
    606    //     img.style = "height: 2.4ex; padding-right: 10px; float:right";
    607    //     slide_headers[i].append(img);
    608    // }
    609</script></section>
    610  </div>
    611
    612
    613
    614  <script type="text/javascript">
    615    /**
    616 * Returns the current page number of the presentation.
    617 */
    618function currentPosition() {
    619  return parseInt(document.querySelector('.slide:not(.hidden)').id.slice(6));
    620}
    621
    622
    623/**
    624 * Navigates forward n pages
    625 * If n is negative, we will navigate in reverse
    626 */
    627function navigate(n) {
    628  var position = currentPosition();
    629  var numSlides = document.getElementsByClassName('slide').length;
    630
    631  /* Positions are 1-indexed, so we need to add and subtract 1 */
    632  var nextPosition = (position - 1 + n) % numSlides + 1;
    633
    634  /* Normalize nextPosition in-case of a negative modulo result */
    635  nextPosition = (nextPosition - 1 + numSlides) % numSlides + 1;
    636
    637  document.getElementById('slide-' + position).classList.add('hidden');
    638  document.getElementById('slide-' + nextPosition).classList.remove('hidden');
    639
    640  updateProgress();
    641  updateURL();
    642  updateTabIndex();
    643}
    644
    645
    646/**
    647 * Updates the current URL to include a hashtag of the current page number.
    648 */
    649function updateURL() {
    650  try {
    651    window.history.replaceState({} , null, '#' + currentPosition());
    652  } catch (e) {
    653    window.location.hash = currentPosition();
    654  }
    655}
    656
    657
    658/**
    659 * Sets the progress indicator.
    660 */
    661function updateProgress() {
    662  var progressBar = document.querySelector('.progress-bar');
    663
    664  if (progressBar !== null) {
    665    var numSlides = document.getElementsByClassName('slide').length;
    666    var position = currentPosition() - 1;
    667    var percent = (numSlides === 1) ? 100 : 100 * position / (numSlides - 1);
    668    progressBar.style.width = percent.toString() + '%';
    669  }
    670}
    671
    672
    673/**
    674 * Removes tabindex property from all links on the current slide, sets
    675 * tabindex = -1 for all links on other slides. Prevents slides from appearing
    676 * out of control.
    677 */
    678function updateTabIndex() {
    679  var allLinks = document.querySelectorAll('.slide a');
    680  var position = currentPosition();
    681  var currentPageLinks = document.getElementById('slide-' + position).querySelectorAll('a');
    682  var i;
    683
    684  for (i = 0; i < allLinks.length; i++) {
    685    allLinks[i].setAttribute('tabindex', -1);
    686  }
    687
    688  for (i = 0; i < currentPageLinks.length; i++) {
    689    currentPageLinks[i].removeAttribute('tabindex');
    690  }
    691}
    692
    693/**
    694 * Determines whether or not we are currently in full screen mode
    695 */
    696function isFullScreen() {
    697  return document.fullscreenElement ||
    698         document.mozFullScreenElement ||
    699         document.webkitFullscreenElement ||
    700         document.msFullscreenElement;
    701}
    702
    703/**
    704 * Toggle fullScreen mode on document element.
    705 * Works on chrome (>= 15), firefox (>= 9), ie (>= 11), opera(>= 12.1), safari (>= 5).
    706 */
    707function toggleFullScreen() {
    708  /* Convenient renames */
    709  var docElem = document.documentElement;
    710  var doc = document;
    711
    712  docElem.requestFullscreen =
    713      docElem.requestFullscreen ||
    714      docElem.msRequestFullscreen ||
    715      docElem.mozRequestFullScreen ||
    716      docElem.webkitRequestFullscreen.bind(docElem, Element.ALLOW_KEYBOARD_INPUT);
    717
    718  doc.exitFullscreen =
    719      doc.exitFullscreen ||
    720      doc.msExitFullscreen ||
    721      doc.mozCancelFullScreen ||
    722      doc.webkitExitFullscreen;
    723
    724  isFullScreen() ? doc.exitFullscreen() : docElem.requestFullscreen();
    725}
    726
    727document.addEventListener('DOMContentLoaded', function () {
    728  // Update the tabindex to prevent weird slide transitioning
    729  updateTabIndex();
    730
    731  // If the location hash specifies a page number, go to it.
    732  var page = window.location.hash.slice(1);
    733  if (page) {
    734    navigate(parseInt(page) - 1);
    735  }
    736
    737  document.onkeydown = function (e) {
    738    var kc = e.keyCode;
    739
    740    // left, down, H, J, backspace, PgUp - BACK
    741    // up, right, K, L, space, PgDn - FORWARD
    742    // enter - FULLSCREEN
    743    if (kc === 37 || kc === 40 || kc === 8 || kc === 72 || kc === 74 || kc === 33) {
    744      navigate(-1);
    745    } else if (kc === 38 || kc === 39 || kc === 32 || kc === 75 || kc === 76 || kc === 34) {
    746      navigate(1);
    747    } else if (kc === 13) {
    748      toggleFullScreen();
    749    }
    750  };
    751
    752  if (document.querySelector('.next') && document.querySelector('.prev')) {
    753    document.querySelector('.next').onclick = function (e) {
    754      e.preventDefault();
    755      navigate(1);
    756    };
    757
    758    document.querySelector('.prev').onclick = function (e) {
    759      e.preventDefault();
    760      navigate(-1);
    761    };
    762  }
    763});
    764
    765
    766  </script>
    767</body>
    768</html>