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>